Crc64.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Security.Cryptography;
  4. namespace Masuit.Tools.Security
  5. {
  6. /// <summary>
  7. /// 64-bit CRC 实现
  8. /// </summary>
  9. /// <remarks>
  10. /// 支持ISO 3309标准
  11. /// </remarks>
  12. public class Crc64 : HashAlgorithm
  13. {
  14. public const ulong DefaultSeed = 0x0;
  15. private readonly ulong[] _table;
  16. private readonly ulong _seed;
  17. private ulong _hash;
  18. internal static ulong[] Table;
  19. public const ulong Iso3309Polynomial = 0xD800000000000000;
  20. public override int HashSize => 64;
  21. public Crc64() : this(Iso3309Polynomial)
  22. {
  23. }
  24. public Crc64(ulong polynomial) : this(polynomial, DefaultSeed)
  25. {
  26. }
  27. public Crc64(ulong polynomial, ulong seed)
  28. {
  29. if (!BitConverter.IsLittleEndian)
  30. {
  31. throw new PlatformNotSupportedException("Big Endian 处理程序不支持");
  32. }
  33. _table = InitializeTable(polynomial);
  34. _seed = _hash = seed;
  35. }
  36. public override void Initialize()
  37. {
  38. _hash = _seed;
  39. }
  40. protected override void HashCore(byte[] array, int ibStart, int cbSize)
  41. {
  42. _hash = CalculateHash(_hash, _table, array, ibStart, cbSize);
  43. }
  44. protected override byte[] HashFinal()
  45. {
  46. var hashBuffer = UInt64ToBigEndianBytes(_hash);
  47. HashValue = hashBuffer;
  48. return hashBuffer;
  49. }
  50. protected static ulong CalculateHash(ulong seed, ulong[] table, IList<byte> buffer, int start, int size)
  51. {
  52. var hash = seed;
  53. for (var i = start; i < start + size; i++)
  54. {
  55. unchecked
  56. {
  57. hash = (hash >> 8) ^ table[(buffer[i] ^ hash) & 0xff];
  58. }
  59. }
  60. return hash;
  61. }
  62. private static byte[] UInt64ToBigEndianBytes(ulong value)
  63. {
  64. var result = BitConverter.GetBytes(value);
  65. if (BitConverter.IsLittleEndian)
  66. {
  67. Array.Reverse(result);
  68. }
  69. return result;
  70. }
  71. private static ulong[] InitializeTable(ulong polynomial)
  72. {
  73. if (polynomial == Iso3309Polynomial && Table != null)
  74. {
  75. return Table;
  76. }
  77. var createTable = CreateTable(polynomial);
  78. if (polynomial == Iso3309Polynomial)
  79. {
  80. Table = createTable;
  81. }
  82. return createTable;
  83. }
  84. protected static ulong[] CreateTable(ulong polynomial)
  85. {
  86. var createTable = new ulong[256];
  87. for (var i = 0; i < 256; ++i)
  88. {
  89. var entry = (ulong)i;
  90. for (var j = 0; j < 8; ++j)
  91. {
  92. if ((entry & 1) == 1)
  93. {
  94. entry = (entry >> 1) ^ polynomial;
  95. }
  96. else
  97. {
  98. entry >>= 1;
  99. }
  100. }
  101. createTable[i] = entry;
  102. }
  103. return createTable;
  104. }
  105. public static ulong Compute(byte[] buffer)
  106. {
  107. return Compute(DefaultSeed, buffer);
  108. }
  109. public static ulong Compute(ulong seed, byte[] buffer)
  110. {
  111. Table ??= CreateTable(Iso3309Polynomial);
  112. return CalculateHash(seed, Table, buffer, 0, buffer.Length);
  113. }
  114. }
  115. }