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.1 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()
  43. : this(Iso3309Polynomial, DefaultSeed)
  44. {
  45. }
  46. /// <summary>Initializes a new instance of <see cref="Crc64"/></summary>
  47. /// <param name="polynomial">The polynomial.</param>
  48. /// <param name="seed">The seed.</param>
  49. private Crc64(ulong polynomial, ulong seed)
  50. {
  51. m_table = InitializeTable(polynomial);
  52. this.m_seed = m_hash = seed;
  53. }
  54. /// <summary>
  55. /// Initializes an implementation of the
  56. /// <see cref="T:System.Security.Cryptography.HashAlgorithm" /> class.
  57. /// </summary>
  58. public override void Initialize()
  59. {
  60. m_hash = m_seed;
  61. }
  62. /// <summary>When overridden in a derived class, routes data written to the object into the hash algorithm for computing the hash.</summary>
  63. /// <param name="array">The input to compute the hash code for..</param>
  64. /// <param name="ibStart">The offset into the byte array from which to begin using data.</param>
  65. /// <param name="cbSize">The number of bytes in the byte array to use as data.</param>
  66. protected override void HashCore(byte[] array, int ibStart, int cbSize)
  67. {
  68. m_hash = CalculateHash(m_hash, m_table, array, ibStart, cbSize);
  69. }
  70. /// <summary>
  71. /// Finalizes the hash computation after the last data is processed by the cryptographic stream
  72. /// object.
  73. /// </summary>
  74. /// <returns>
  75. /// This method finalizes any partial computation and returns the correct hash value for the data
  76. /// stream.
  77. /// </returns>
  78. protected override byte[] HashFinal()
  79. {
  80. var hashBuffer = UInt64ToBigEndianBytes(m_hash);
  81. HashValue = hashBuffer;
  82. return hashBuffer;
  83. }
  84. /// <summary>Gets the size, in bits, of the computed hash code.</summary>
  85. /// <value>The size, in bits, of the computed hash code.</value>
  86. public override int HashSize
  87. {
  88. get { return 64; }
  89. }
  90. /// <summary>Calculates the hash.</summary>
  91. /// <param name="seed">The seed.</param>
  92. /// <param name="table">The table.</param>
  93. /// <param name="buffer">The buffer.</param>
  94. /// <param name="start">The start.</param>
  95. /// <param name="size">The size.</param>
  96. /// <returns>The calculated hash.</returns>
  97. private static ulong CalculateHash(ulong seed, ulong[] table, IList<byte> buffer, int start, int size)
  98. {
  99. var hash = seed;
  100. for (var i = start; i < start + size; i++)
  101. unchecked
  102. {
  103. hash = (hash >> 8) ^ table[(buffer[i] ^ hash) & 0xff];
  104. }
  105. return hash;
  106. }
  107. /// <summary>Int 64 to big endian bytes.</summary>
  108. /// <param name="value">The value.</param>
  109. /// <returns>A byte[].</returns>
  110. private static byte[] UInt64ToBigEndianBytes(ulong value)
  111. {
  112. var result = BitConverter.GetBytes(value);
  113. if (BitConverter.IsLittleEndian)
  114. Array.Reverse(result);
  115. return result;
  116. }
  117. /// <summary>Initializes the table.</summary>
  118. /// <param name="polynomial">The polynomial.</param>
  119. /// <returns>An ulong[].</returns>
  120. private static ulong[] InitializeTable(ulong polynomial)
  121. {
  122. if (polynomial == Iso3309Polynomial && Table != null)
  123. return Table;
  124. var createTable = CreateTable(polynomial);
  125. if (polynomial == Iso3309Polynomial)
  126. Table = createTable;
  127. return createTable;
  128. }
  129. /// <summary>Creates a table.</summary>
  130. /// <param name="polynomial">The polynomial.</param>
  131. /// <returns>A new array of ulong.</returns>
  132. private static ulong[] CreateTable(ulong polynomial)
  133. {
  134. var createTable = new ulong[256];
  135. for (var i = 0; i < 256; ++i)
  136. {
  137. var entry = (ulong)i;
  138. for (var j = 0; j < 8; ++j)
  139. if ((entry & 1) == 1)
  140. entry = (entry >> 1) ^ polynomial;
  141. else
  142. entry = entry >> 1;
  143. createTable[i] = entry;
  144. }
  145. return createTable;
  146. }
  147. }
  148. }