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.

347 lines
9.0 KiB

  1. #if NET20
  2. using System;
  3. using System.Security;
  4. using System.Security.Cryptography;
  5. namespace Apewer.Internals
  6. {
  7. internal class SHA512CryptoServiceProvider : HashAlgorithm
  8. {
  9. private byte[] _buffer;
  10. private ulong _count;
  11. private ulong[] _stateSHA512;
  12. private ulong[] _W;
  13. private static readonly ulong[] _K = new ulong[80]
  14. {
  15. 4794697086780616226uL,
  16. 8158064640168781261uL,
  17. 13096744586834688815uL,
  18. 16840607885511220156uL,
  19. 4131703408338449720uL,
  20. 6480981068601479193uL,
  21. 10538285296894168987uL,
  22. 12329834152419229976uL,
  23. 15566598209576043074uL,
  24. 1334009975649890238uL,
  25. 2608012711638119052uL,
  26. 6128411473006802146uL,
  27. 8268148722764581231uL,
  28. 9286055187155687089uL,
  29. 11230858885718282805uL,
  30. 13951009754708518548uL,
  31. 16472876342353939154uL,
  32. 17275323862435702243uL,
  33. 1135362057144423861uL,
  34. 2597628984639134821uL,
  35. 3308224258029322869uL,
  36. 5365058923640841347uL,
  37. 6679025012923562964uL,
  38. 8573033837759648693uL,
  39. 10970295158949994411uL,
  40. 12119686244451234320uL,
  41. 12683024718118986047uL,
  42. 13788192230050041572uL,
  43. 14330467153632333762uL,
  44. 15395433587784984357uL,
  45. 489312712824947311uL,
  46. 1452737877330783856uL,
  47. 2861767655752347644uL,
  48. 3322285676063803686uL,
  49. 5560940570517711597uL,
  50. 5996557281743188959uL,
  51. 7280758554555802590uL,
  52. 8532644243296465576uL,
  53. 9350256976987008742uL,
  54. 10552545826968843579uL,
  55. 11727347734174303076uL,
  56. 12113106623233404929uL,
  57. 14000437183269869457uL,
  58. 14369950271660146224uL,
  59. 15101387698204529176uL,
  60. 15463397548674623760uL,
  61. 17586052441742319658uL,
  62. 1182934255886127544uL,
  63. 1847814050463011016uL,
  64. 2177327727835720531uL,
  65. 2830643537854262169uL,
  66. 3796741975233480872uL,
  67. 4115178125766777443uL,
  68. 5681478168544905931uL,
  69. 6601373596472566643uL,
  70. 7507060721942968483uL,
  71. 8399075790359081724uL,
  72. 8693463985226723168uL,
  73. 9568029438360202098uL,
  74. 10144078919501101548uL,
  75. 10430055236837252648uL,
  76. 11840083180663258601uL,
  77. 13761210420658862357uL,
  78. 14299343276471374635uL,
  79. 14566680578165727644uL,
  80. 15097957966210449927uL,
  81. 16922976911328602910uL,
  82. 17689382322260857208uL,
  83. 500013540394364858uL,
  84. 748580250866718886uL,
  85. 1242879168328830382uL,
  86. 1977374033974150939uL,
  87. 2944078676154940804uL,
  88. 3659926193048069267uL,
  89. 4368137639120453308uL,
  90. 4836135668995329356uL,
  91. 5532061633213252278uL,
  92. 6448918945643986474uL,
  93. 6902733635092675308uL,
  94. 7801388544844847127uL
  95. };
  96. public SHA512CryptoServiceProvider()
  97. {
  98. HashSizeValue = 512;
  99. _stateSHA512 = new ulong[8];
  100. _buffer = new byte[128];
  101. _W = new ulong[80];
  102. InitializeState();
  103. }
  104. public override void Initialize()
  105. {
  106. InitializeState();
  107. Array.Clear(_buffer, 0, _buffer.Length);
  108. Array.Clear(_W, 0, _W.Length);
  109. }
  110. [SecuritySafeCritical]
  111. protected override void HashCore(byte[] rgb, int ibStart, int cbSize)
  112. {
  113. _HashData(rgb, ibStart, cbSize);
  114. }
  115. [SecuritySafeCritical]
  116. protected override byte[] HashFinal()
  117. {
  118. return _EndHash();
  119. }
  120. private void InitializeState()
  121. {
  122. _count = 0uL;
  123. _stateSHA512[0] = 7640891576956012808uL;
  124. _stateSHA512[1] = 13503953896175478587uL;
  125. _stateSHA512[2] = 4354685564936845355uL;
  126. _stateSHA512[3] = 11912009170470909681uL;
  127. _stateSHA512[4] = 5840696475078001361uL;
  128. _stateSHA512[5] = 11170449401992604703uL;
  129. _stateSHA512[6] = 2270897969802886507uL;
  130. _stateSHA512[7] = 6620516959819538809uL;
  131. }
  132. [SecurityCritical]
  133. private unsafe void _HashData(byte[] partIn, int ibStart, int cbSize)
  134. {
  135. int num = cbSize;
  136. int num2 = ibStart;
  137. int num3 = (int)(_count & 0x7F);
  138. _count += (ulong)num;
  139. fixed (ulong* state = _stateSHA512)
  140. {
  141. fixed (byte* block = _buffer)
  142. {
  143. fixed (ulong* expandedBuffer = _W)
  144. {
  145. if (num3 > 0 && num3 + num >= 128)
  146. {
  147. Array.Copy(partIn, num2, _buffer, num3, 128 - num3);
  148. num2 += 128 - num3;
  149. num -= 128 - num3;
  150. SHATransform(expandedBuffer, state, block);
  151. num3 = 0;
  152. }
  153. while (num >= 128)
  154. {
  155. Array.Copy(partIn, num2, _buffer, 0, 128);
  156. num2 += 128;
  157. num -= 128;
  158. SHATransform(expandedBuffer, state, block);
  159. }
  160. if (num > 0)
  161. {
  162. Array.Copy(partIn, num2, _buffer, num3, num);
  163. }
  164. }
  165. }
  166. }
  167. }
  168. [SecurityCritical]
  169. private byte[] _EndHash()
  170. {
  171. byte[] array = new byte[64];
  172. int num = 128 - (int)(_count & 0x7F);
  173. if (num <= 16)
  174. {
  175. num += 128;
  176. }
  177. byte[] array2 = new byte[num];
  178. array2[0] = 128;
  179. ulong num2 = _count * 8;
  180. array2[num - 8] = (byte)((num2 >> 56) & 0xFF);
  181. array2[num - 7] = (byte)((num2 >> 48) & 0xFF);
  182. array2[num - 6] = (byte)((num2 >> 40) & 0xFF);
  183. array2[num - 5] = (byte)((num2 >> 32) & 0xFF);
  184. array2[num - 4] = (byte)((num2 >> 24) & 0xFF);
  185. array2[num - 3] = (byte)((num2 >> 16) & 0xFF);
  186. array2[num - 2] = (byte)((num2 >> 8) & 0xFF);
  187. array2[num - 1] = (byte)(num2 & 0xFF);
  188. _HashData(array2, 0, array2.Length);
  189. QuadWordToBigEndian(array, _stateSHA512, 8);
  190. HashValue = array;
  191. return array;
  192. }
  193. [SecurityCritical]
  194. private unsafe static void SHATransform(ulong* expandedBuffer, ulong* state, byte* block)
  195. {
  196. ulong num = *state;
  197. ulong num2 = state[1];
  198. ulong num3 = state[2];
  199. ulong num4 = state[3];
  200. ulong num5 = state[4];
  201. ulong num6 = state[5];
  202. ulong num7 = state[6];
  203. ulong num8 = state[7];
  204. QuadWordFromBigEndian(expandedBuffer, 16, block);
  205. SHA512Expand(expandedBuffer);
  206. int num9;
  207. for (num9 = 0; num9 < 80; num9++)
  208. {
  209. ulong num10 = num8 + Sigma_1(num5) + Ch(num5, num6, num7) + _K[num9] + expandedBuffer[num9];
  210. ulong num11 = num4 + num10;
  211. ulong num12 = num10 + Sigma_0(num) + Maj(num, num2, num3);
  212. num9++;
  213. num10 = num7 + Sigma_1(num11) + Ch(num11, num5, num6) + _K[num9] + expandedBuffer[num9];
  214. ulong num13 = num3 + num10;
  215. ulong num14 = num10 + Sigma_0(num12) + Maj(num12, num, num2);
  216. num9++;
  217. num10 = num6 + Sigma_1(num13) + Ch(num13, num11, num5) + _K[num9] + expandedBuffer[num9];
  218. ulong num15 = num2 + num10;
  219. ulong num16 = num10 + Sigma_0(num14) + Maj(num14, num12, num);
  220. num9++;
  221. num10 = num5 + Sigma_1(num15) + Ch(num15, num13, num11) + _K[num9] + expandedBuffer[num9];
  222. ulong num17 = num + num10;
  223. ulong num18 = num10 + Sigma_0(num16) + Maj(num16, num14, num12);
  224. num9++;
  225. num10 = num11 + Sigma_1(num17) + Ch(num17, num15, num13) + _K[num9] + expandedBuffer[num9];
  226. num8 = num12 + num10;
  227. num4 = num10 + Sigma_0(num18) + Maj(num18, num16, num14);
  228. num9++;
  229. num10 = num13 + Sigma_1(num8) + Ch(num8, num17, num15) + _K[num9] + expandedBuffer[num9];
  230. num7 = num14 + num10;
  231. num3 = num10 + Sigma_0(num4) + Maj(num4, num18, num16);
  232. num9++;
  233. num10 = num15 + Sigma_1(num7) + Ch(num7, num8, num17) + _K[num9] + expandedBuffer[num9];
  234. num6 = num16 + num10;
  235. num2 = num10 + Sigma_0(num3) + Maj(num3, num4, num18);
  236. num9++;
  237. num10 = num17 + Sigma_1(num6) + Ch(num6, num7, num8) + _K[num9] + expandedBuffer[num9];
  238. num5 = num18 + num10;
  239. num = num10 + Sigma_0(num2) + Maj(num2, num3, num4);
  240. }
  241. *state += num;
  242. state[1] += num2;
  243. state[2] += num3;
  244. state[3] += num4;
  245. state[4] += num5;
  246. state[5] += num6;
  247. state[6] += num7;
  248. state[7] += num8;
  249. }
  250. private static ulong RotateRight(ulong x, int n)
  251. {
  252. return (x >> n) | (x << 64 - n);
  253. }
  254. private static ulong Ch(ulong x, ulong y, ulong z)
  255. {
  256. return (x & y) ^ (ulong)(((long)x ^ -1L) & (long)z);
  257. }
  258. private static ulong Maj(ulong x, ulong y, ulong z)
  259. {
  260. return (x & y) ^ (x & z) ^ (y & z);
  261. }
  262. private static ulong Sigma_0(ulong x)
  263. {
  264. return RotateRight(x, 28) ^ RotateRight(x, 34) ^ RotateRight(x, 39);
  265. }
  266. private static ulong Sigma_1(ulong x)
  267. {
  268. return RotateRight(x, 14) ^ RotateRight(x, 18) ^ RotateRight(x, 41);
  269. }
  270. private static ulong sigma_0(ulong x)
  271. {
  272. return RotateRight(x, 1) ^ RotateRight(x, 8) ^ (x >> 7);
  273. }
  274. private static ulong sigma_1(ulong x)
  275. {
  276. return RotateRight(x, 19) ^ RotateRight(x, 61) ^ (x >> 6);
  277. }
  278. [SecurityCritical]
  279. private unsafe static void SHA512Expand(ulong* x)
  280. {
  281. for (int i = 16; i < 80; i++)
  282. {
  283. x[i] = sigma_1(x[i - 2]) + x[i - 7] + sigma_0(x[i - 15]) + x[i - 16];
  284. }
  285. }
  286. private static void QuadWordToBigEndian(byte[] block, ulong[] x, int digits)
  287. {
  288. int num = 0;
  289. int num2 = 0;
  290. while (num < digits)
  291. {
  292. block[num2] = (byte)((x[num] >> 56) & 0xFF);
  293. block[num2 + 1] = (byte)((x[num] >> 48) & 0xFF);
  294. block[num2 + 2] = (byte)((x[num] >> 40) & 0xFF);
  295. block[num2 + 3] = (byte)((x[num] >> 32) & 0xFF);
  296. block[num2 + 4] = (byte)((x[num] >> 24) & 0xFF);
  297. block[num2 + 5] = (byte)((x[num] >> 16) & 0xFF);
  298. block[num2 + 6] = (byte)((x[num] >> 8) & 0xFF);
  299. block[num2 + 7] = (byte)(x[num] & 0xFF);
  300. num++;
  301. num2 += 8;
  302. }
  303. }
  304. [SecurityCritical]
  305. private unsafe static void QuadWordFromBigEndian(ulong* x, int digits, byte* block)
  306. {
  307. int num = 0;
  308. int num2 = 0;
  309. while (num < digits)
  310. {
  311. x[num] = (((ulong)block[num2] << 56) | ((ulong)block[num2 + 1] << 48) | ((ulong)block[num2 + 2] << 40) | ((ulong)block[num2 + 3] << 32) | ((ulong)block[num2 + 4] << 24) | ((ulong)block[num2 + 5] << 16) | ((ulong)block[num2 + 6] << 8) | block[num2 + 7]);
  312. num++;
  313. num2 += 8;
  314. }
  315. }
  316. }
  317. }
  318. #endif