You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

167 lines
6.0 KiB

  1. /* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. *
  21. *
  22. * Copyright (c) Damien Guard. All rights reserved.
  23. * AlphaFS has written permission from the author to include the CRC code.
  24. */
  25. using System;
  26. using System.Collections.Generic;
  27. using System.Diagnostics.CodeAnalysis;
  28. using System.Security.Cryptography;
  29. namespace Alphaleonis.Win32.Security
  30. {
  31. /// <summary>Implements an ISO-3309 compliant 64-bit CRC hash algorithm.</summary>
  32. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Crc")]
  33. internal class Crc64 : HashAlgorithm
  34. {
  35. private static ulong[] Table;
  36. private const ulong Iso3309Polynomial = 0xD800000000000000;
  37. private const ulong DefaultSeed = 0x0;
  38. private readonly ulong[] m_table;
  39. private readonly ulong m_seed;
  40. private ulong m_hash;
  41. /// <summary>Initializes a new instance of <see cref="Crc64"/> </summary>
  42. public Crc64() : this(Iso3309Polynomial, DefaultSeed)
  43. {
  44. }
  45. /// <summary>Initializes a new instance of <see cref="Crc64"/></summary>
  46. /// <param name="polynomial">The polynomial.</param>
  47. /// <param name="seed">The seed.</param>
  48. private Crc64(ulong polynomial, ulong seed)
  49. {
  50. m_table = InitializeTable(polynomial);
  51. m_seed = m_hash = seed;
  52. }
  53. /// <summary>
  54. /// Initializes an implementation of the
  55. /// <see cref="T:System.Security.Cryptography.HashAlgorithm" /> class.
  56. /// </summary>
  57. public override void Initialize()
  58. {
  59. m_hash = m_seed;
  60. }
  61. /// <summary>When overridden in a derived class, routes data written to the object into the hash algorithm for computing the hash.</summary>
  62. /// <param name="array">The input to compute the hash code for..</param>
  63. /// <param name="ibStart">The offset into the byte array from which to begin using data.</param>
  64. /// <param name="cbSize">The number of bytes in the byte array to use as data.</param>
  65. protected override void HashCore(byte[] array, int ibStart, int cbSize)
  66. {
  67. m_hash = CalculateHash(m_hash, m_table, array, ibStart, cbSize);
  68. }
  69. /// <summary>
  70. /// Finalizes the hash computation after the last data is processed by the cryptographic stream
  71. /// object.
  72. /// </summary>
  73. /// <returns>
  74. /// This method finalizes any partial computation and returns the correct hash value for the data
  75. /// stream.
  76. /// </returns>
  77. protected override byte[] HashFinal()
  78. {
  79. var hashBuffer = UInt64ToBigEndianBytes(m_hash);
  80. HashValue = hashBuffer;
  81. return hashBuffer;
  82. }
  83. /// <summary>Gets the size, in bits, of the computed hash code.</summary>
  84. /// <value>The size, in bits, of the computed hash code.</value>
  85. public override int HashSize
  86. {
  87. get { return 64; }
  88. }
  89. /// <summary>Calculates the hash.</summary>
  90. /// <param name="seed">The seed.</param>
  91. /// <param name="table">The table.</param>
  92. /// <param name="buffer">The buffer.</param>
  93. /// <param name="start">The start.</param>
  94. /// <param name="size">The size.</param>
  95. /// <returns>The calculated hash.</returns>
  96. private static ulong CalculateHash(ulong seed, ulong[] table, IList<byte> buffer, int start, int size)
  97. {
  98. var hash = seed;
  99. for (var i = start; i < start + size; i++)
  100. unchecked
  101. {
  102. hash = (hash >> 8) ^ table[(buffer[i] ^ hash) & 0xff];
  103. }
  104. return hash;
  105. }
  106. /// <summary>Int 64 to big endian bytes.</summary>
  107. /// <param name="value">The value.</param>
  108. /// <returns>A byte[].</returns>
  109. private static byte[] UInt64ToBigEndianBytes(ulong value)
  110. {
  111. var result = BitConverter.GetBytes(value);
  112. if (BitConverter.IsLittleEndian)
  113. Array.Reverse(result);
  114. return result;
  115. }
  116. /// <summary>Initializes the table.</summary>
  117. /// <param name="polynomial">The polynomial.</param>
  118. /// <returns>An ulong[].</returns>
  119. private static ulong[] InitializeTable(ulong polynomial)
  120. {
  121. if (polynomial == Iso3309Polynomial && Table != null)
  122. return Table;
  123. var createTable = CreateTable(polynomial);
  124. if (polynomial == Iso3309Polynomial)
  125. Table = createTable;
  126. return createTable;
  127. }
  128. /// <summary>Creates a table.</summary>
  129. /// <param name="polynomial">The polynomial.</param>
  130. /// <returns>A new array of ulong.</returns>
  131. private static ulong[] CreateTable(ulong polynomial)
  132. {
  133. var createTable = new ulong[256];
  134. for (var i = 0; i < 256; ++i)
  135. {
  136. var entry = (ulong) i;
  137. for (var j = 0; j < 8; ++j)
  138. entry = (entry & 1) == 1 ? (entry >> 1) ^ polynomial : entry >> 1;
  139. createTable[i] = entry;
  140. }
  141. return createTable;
  142. }
  143. }
  144. }