Crc64.cs 3.2 KB

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