DetravHMACSHA1.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace FastReport.Utils
  7. {
  8. internal class DetravHMACSHA1 : IDisposable
  9. {
  10. private readonly byte[] key;
  11. readonly SHA1Internal sha1;
  12. const int blockSize = 64;
  13. private readonly byte[] ibuffer;
  14. private readonly byte[] obuffer;
  15. public DetravHMACSHA1(byte[] key)
  16. {
  17. sha1 = new SHA1Internal();
  18. if (key.Length > blockSize)
  19. {
  20. this.key = sha1.ComputeHash(key);
  21. }
  22. else
  23. {
  24. this.key = new byte[blockSize];
  25. key.CopyTo(this.key, 0);
  26. }
  27. ibuffer = new byte[blockSize];
  28. obuffer = new byte[blockSize];
  29. for (int i = 0; i < this.key.Length; i++)
  30. {
  31. ibuffer[i] = (byte)(this.key[i] ^ 0x36);
  32. obuffer[i] = (byte)(this.key[i] ^ 0x5c);
  33. }
  34. for (int i = this.key.Length; i < blockSize; i++)
  35. {
  36. ibuffer[i] = 0x36;
  37. obuffer[i] = 0x5c;
  38. }
  39. }
  40. public byte[] ComputeHash(byte[] data)
  41. {
  42. var hash = sha1.ComputeHash(ibuffer.Concat(data).ToArray());
  43. return sha1.ComputeHash(obuffer.Concat(hash).ToArray());
  44. }
  45. public void Dispose()
  46. {
  47. }
  48. //https://github.com/mono/mono/blob/main/mcs/class/corlib/System.Security.Cryptography/SHA1CryptoServiceProvider.cs
  49. private class SHA1Internal
  50. {
  51. private const int BLOCK_SIZE_BYTES = 64;
  52. private readonly uint[] _H; // these are my chaining variables
  53. private ulong count;
  54. private readonly byte[] _ProcessingBuffer; // Used to start data when passed less than a block worth.
  55. private int _ProcessingBufferCount; // Counts how much data we have stored that still needs processed.
  56. private readonly uint[] buff;
  57. public SHA1Internal()
  58. {
  59. _H = new uint[5];
  60. _ProcessingBuffer = new byte[BLOCK_SIZE_BYTES];
  61. buff = new uint[80];
  62. Initialize();
  63. }
  64. public byte[] ComputeHash(byte[] bytes)
  65. {
  66. if (bytes == null)
  67. throw new ArgumentNullException(nameof(bytes));
  68. HashCore(bytes, 0, bytes.Length);
  69. var result = HashFinal();
  70. Initialize();
  71. return result;
  72. }
  73. public void HashCore(byte[] rgb, int ibStart, int cbSize)
  74. {
  75. int i;
  76. if (_ProcessingBufferCount != 0)
  77. {
  78. if (cbSize < (BLOCK_SIZE_BYTES - _ProcessingBufferCount))
  79. {
  80. System.Buffer.BlockCopy(rgb, ibStart, _ProcessingBuffer, _ProcessingBufferCount, cbSize);
  81. _ProcessingBufferCount += cbSize;
  82. return;
  83. }
  84. else
  85. {
  86. i = (BLOCK_SIZE_BYTES - _ProcessingBufferCount);
  87. System.Buffer.BlockCopy(rgb, ibStart, _ProcessingBuffer, _ProcessingBufferCount, i);
  88. ProcessBlock(_ProcessingBuffer, 0);
  89. _ProcessingBufferCount = 0;
  90. ibStart += i;
  91. cbSize -= i;
  92. }
  93. }
  94. for (i = 0; i < cbSize - cbSize % BLOCK_SIZE_BYTES; i += BLOCK_SIZE_BYTES)
  95. {
  96. ProcessBlock(rgb, (uint)(ibStart + i));
  97. }
  98. if (cbSize % BLOCK_SIZE_BYTES != 0)
  99. {
  100. System.Buffer.BlockCopy(rgb, cbSize - cbSize % BLOCK_SIZE_BYTES + ibStart, _ProcessingBuffer, 0, cbSize % BLOCK_SIZE_BYTES);
  101. _ProcessingBufferCount = cbSize % BLOCK_SIZE_BYTES;
  102. }
  103. }
  104. public byte[] HashFinal()
  105. {
  106. byte[] hash = new byte[20];
  107. ProcessFinalBlock(_ProcessingBuffer, 0, _ProcessingBufferCount);
  108. for (int i = 0; i < 5; i++)
  109. {
  110. for (int j = 0; j < 4; j++)
  111. {
  112. hash[i * 4 + j] = (byte)(_H[i] >> (8 * (3 - j)));
  113. }
  114. }
  115. return hash;
  116. }
  117. public void Initialize()
  118. {
  119. count = 0;
  120. _ProcessingBufferCount = 0;
  121. _H[0] = 0x67452301;
  122. _H[1] = 0xefcdab89;
  123. _H[2] = 0x98badcfe;
  124. _H[3] = 0x10325476;
  125. _H[4] = 0xC3D2E1F0;
  126. }
  127. private void ProcessBlock(byte[] inputBuffer, uint inputOffset)
  128. {
  129. uint a, b, c, d, e;
  130. count += BLOCK_SIZE_BYTES;
  131. // abc removal would not work on the fields
  132. uint[] _H = this._H;
  133. uint[] buff = this.buff;
  134. InitialiseBuff(buff, inputBuffer, inputOffset);
  135. FillBuff(buff);
  136. a = _H[0];
  137. b = _H[1];
  138. c = _H[2];
  139. d = _H[3];
  140. e = _H[4];
  141. // This function was unrolled because it seems to be doubling our performance with current compiler/VM.
  142. // Possibly roll up if this changes.
  143. // ---- Round 1 --------
  144. int i = 0;
  145. while (i < 20)
  146. {
  147. e += ((a << 5) | (a >> 27)) + (((c ^ d) & b) ^ d) + 0x5A827999 + buff[i];
  148. b = (b << 30) | (b >> 2);
  149. d += ((e << 5) | (e >> 27)) + (((b ^ c) & a) ^ c) + 0x5A827999 + buff[i + 1];
  150. a = (a << 30) | (a >> 2);
  151. c += ((d << 5) | (d >> 27)) + (((a ^ b) & e) ^ b) + 0x5A827999 + buff[i + 2];
  152. e = (e << 30) | (e >> 2);
  153. b += ((c << 5) | (c >> 27)) + (((e ^ a) & d) ^ a) + 0x5A827999 + buff[i + 3];
  154. d = (d << 30) | (d >> 2);
  155. a += ((b << 5) | (b >> 27)) + (((d ^ e) & c) ^ e) + 0x5A827999 + buff[i + 4];
  156. c = (c << 30) | (c >> 2);
  157. i += 5;
  158. }
  159. // ---- Round 2 --------
  160. while (i < 40)
  161. {
  162. e += ((a << 5) | (a >> 27)) + (b ^ c ^ d) + 0x6ED9EBA1 + buff[i];
  163. b = (b << 30) | (b >> 2);
  164. d += ((e << 5) | (e >> 27)) + (a ^ b ^ c) + 0x6ED9EBA1 + buff[i + 1];
  165. a = (a << 30) | (a >> 2);
  166. c += ((d << 5) | (d >> 27)) + (e ^ a ^ b) + 0x6ED9EBA1 + buff[i + 2];
  167. e = (e << 30) | (e >> 2);
  168. b += ((c << 5) | (c >> 27)) + (d ^ e ^ a) + 0x6ED9EBA1 + buff[i + 3];
  169. d = (d << 30) | (d >> 2);
  170. a += ((b << 5) | (b >> 27)) + (c ^ d ^ e) + 0x6ED9EBA1 + buff[i + 4];
  171. c = (c << 30) | (c >> 2);
  172. i += 5;
  173. }
  174. // ---- Round 3 --------
  175. while (i < 60)
  176. {
  177. e += ((a << 5) | (a >> 27)) + ((b & c) | (b & d) | (c & d)) + 0x8F1BBCDC + buff[i];
  178. b = (b << 30) | (b >> 2);
  179. d += ((e << 5) | (e >> 27)) + ((a & b) | (a & c) | (b & c)) + 0x8F1BBCDC + buff[i + 1];
  180. a = (a << 30) | (a >> 2);
  181. c += ((d << 5) | (d >> 27)) + ((e & a) | (e & b) | (a & b)) + 0x8F1BBCDC + buff[i + 2];
  182. e = (e << 30) | (e >> 2);
  183. b += ((c << 5) | (c >> 27)) + ((d & e) | (d & a) | (e & a)) + 0x8F1BBCDC + buff[i + 3];
  184. d = (d << 30) | (d >> 2);
  185. a += ((b << 5) | (b >> 27)) + ((c & d) | (c & e) | (d & e)) + 0x8F1BBCDC + buff[i + 4];
  186. c = (c << 30) | (c >> 2);
  187. i += 5;
  188. }
  189. // ---- Round 4 --------
  190. while (i < 80)
  191. {
  192. e += ((a << 5) | (a >> 27)) + (b ^ c ^ d) + 0xCA62C1D6 + buff[i];
  193. b = (b << 30) | (b >> 2);
  194. d += ((e << 5) | (e >> 27)) + (a ^ b ^ c) + 0xCA62C1D6 + buff[i + 1];
  195. a = (a << 30) | (a >> 2);
  196. c += ((d << 5) | (d >> 27)) + (e ^ a ^ b) + 0xCA62C1D6 + buff[i + 2];
  197. e = (e << 30) | (e >> 2);
  198. b += ((c << 5) | (c >> 27)) + (d ^ e ^ a) + 0xCA62C1D6 + buff[i + 3];
  199. d = (d << 30) | (d >> 2);
  200. a += ((b << 5) | (b >> 27)) + (c ^ d ^ e) + 0xCA62C1D6 + buff[i + 4];
  201. c = (c << 30) | (c >> 2);
  202. i += 5;
  203. }
  204. _H[0] += a;
  205. _H[1] += b;
  206. _H[2] += c;
  207. _H[3] += d;
  208. _H[4] += e;
  209. }
  210. private static void InitialiseBuff(uint[] buff, byte[] input, uint inputOffset)
  211. {
  212. buff[0] = (uint)((input[inputOffset + 0] << 24) | (input[inputOffset + 1] << 16) | (input[inputOffset + 2] << 8) | (input[inputOffset + 3]));
  213. buff[1] = (uint)((input[inputOffset + 4] << 24) | (input[inputOffset + 5] << 16) | (input[inputOffset + 6] << 8) | (input[inputOffset + 7]));
  214. buff[2] = (uint)((input[inputOffset + 8] << 24) | (input[inputOffset + 9] << 16) | (input[inputOffset + 10] << 8) | (input[inputOffset + 11]));
  215. buff[3] = (uint)((input[inputOffset + 12] << 24) | (input[inputOffset + 13] << 16) | (input[inputOffset + 14] << 8) | (input[inputOffset + 15]));
  216. buff[4] = (uint)((input[inputOffset + 16] << 24) | (input[inputOffset + 17] << 16) | (input[inputOffset + 18] << 8) | (input[inputOffset + 19]));
  217. buff[5] = (uint)((input[inputOffset + 20] << 24) | (input[inputOffset + 21] << 16) | (input[inputOffset + 22] << 8) | (input[inputOffset + 23]));
  218. buff[6] = (uint)((input[inputOffset + 24] << 24) | (input[inputOffset + 25] << 16) | (input[inputOffset + 26] << 8) | (input[inputOffset + 27]));
  219. buff[7] = (uint)((input[inputOffset + 28] << 24) | (input[inputOffset + 29] << 16) | (input[inputOffset + 30] << 8) | (input[inputOffset + 31]));
  220. buff[8] = (uint)((input[inputOffset + 32] << 24) | (input[inputOffset + 33] << 16) | (input[inputOffset + 34] << 8) | (input[inputOffset + 35]));
  221. buff[9] = (uint)((input[inputOffset + 36] << 24) | (input[inputOffset + 37] << 16) | (input[inputOffset + 38] << 8) | (input[inputOffset + 39]));
  222. buff[10] = (uint)((input[inputOffset + 40] << 24) | (input[inputOffset + 41] << 16) | (input[inputOffset + 42] << 8) | (input[inputOffset + 43]));
  223. buff[11] = (uint)((input[inputOffset + 44] << 24) | (input[inputOffset + 45] << 16) | (input[inputOffset + 46] << 8) | (input[inputOffset + 47]));
  224. buff[12] = (uint)((input[inputOffset + 48] << 24) | (input[inputOffset + 49] << 16) | (input[inputOffset + 50] << 8) | (input[inputOffset + 51]));
  225. buff[13] = (uint)((input[inputOffset + 52] << 24) | (input[inputOffset + 53] << 16) | (input[inputOffset + 54] << 8) | (input[inputOffset + 55]));
  226. buff[14] = (uint)((input[inputOffset + 56] << 24) | (input[inputOffset + 57] << 16) | (input[inputOffset + 58] << 8) | (input[inputOffset + 59]));
  227. buff[15] = (uint)((input[inputOffset + 60] << 24) | (input[inputOffset + 61] << 16) | (input[inputOffset + 62] << 8) | (input[inputOffset + 63]));
  228. }
  229. private static void FillBuff(uint[] buff)
  230. {
  231. uint val;
  232. for (int i = 16; i < 80; i += 8)
  233. {
  234. val = buff[i - 3] ^ buff[i - 8] ^ buff[i - 14] ^ buff[i - 16];
  235. buff[i] = (val << 1) | (val >> 31);
  236. val = buff[i - 2] ^ buff[i - 7] ^ buff[i - 13] ^ buff[i - 15];
  237. buff[i + 1] = (val << 1) | (val >> 31);
  238. val = buff[i - 1] ^ buff[i - 6] ^ buff[i - 12] ^ buff[i - 14];
  239. buff[i + 2] = (val << 1) | (val >> 31);
  240. val = buff[i + 0] ^ buff[i - 5] ^ buff[i - 11] ^ buff[i - 13];
  241. buff[i + 3] = (val << 1) | (val >> 31);
  242. val = buff[i + 1] ^ buff[i - 4] ^ buff[i - 10] ^ buff[i - 12];
  243. buff[i + 4] = (val << 1) | (val >> 31);
  244. val = buff[i + 2] ^ buff[i - 3] ^ buff[i - 9] ^ buff[i - 11];
  245. buff[i + 5] = (val << 1) | (val >> 31);
  246. val = buff[i + 3] ^ buff[i - 2] ^ buff[i - 8] ^ buff[i - 10];
  247. buff[i + 6] = (val << 1) | (val >> 31);
  248. val = buff[i + 4] ^ buff[i - 1] ^ buff[i - 7] ^ buff[i - 9];
  249. buff[i + 7] = (val << 1) | (val >> 31);
  250. }
  251. }
  252. private void ProcessFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
  253. {
  254. ulong total = count + (ulong)inputCount;
  255. int paddingSize = (56 - (int)(total % BLOCK_SIZE_BYTES));
  256. if (paddingSize < 1)
  257. paddingSize += BLOCK_SIZE_BYTES;
  258. int length = inputCount + paddingSize + 8;
  259. byte[] fooBuffer = (length == 64) ? _ProcessingBuffer : new byte[length];
  260. for (int i = 0; i < inputCount; i++)
  261. {
  262. fooBuffer[i] = inputBuffer[i + inputOffset];
  263. }
  264. fooBuffer[inputCount] = 0x80;
  265. for (int i = inputCount + 1; i < inputCount + paddingSize; i++)
  266. {
  267. fooBuffer[i] = 0x00;
  268. }
  269. // I deal in bytes. The algorithm deals in bits.
  270. ulong size = total << 3;
  271. AddLength(size, fooBuffer, inputCount + paddingSize);
  272. ProcessBlock(fooBuffer, 0);
  273. if (length == 128)
  274. ProcessBlock(fooBuffer, 64);
  275. }
  276. internal void AddLength(ulong length, byte[] buffer, int position)
  277. {
  278. buffer[position++] = (byte)(length >> 56);
  279. buffer[position++] = (byte)(length >> 48);
  280. buffer[position++] = (byte)(length >> 40);
  281. buffer[position++] = (byte)(length >> 32);
  282. buffer[position++] = (byte)(length >> 24);
  283. buffer[position++] = (byte)(length >> 16);
  284. buffer[position++] = (byte)(length >> 8);
  285. buffer[position] = (byte)(length);
  286. }
  287. }
  288. }
  289. }