Dstu7624Engine.cs 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  6. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines
  7. {
  8. /**
  9. * implementation of DSTU 7624 (Kalyna)
  10. */
  11. public class Dstu7624Engine
  12. : IBlockCipher
  13. {
  14. private ulong[] internalState;
  15. private ulong[] workingKey;
  16. private ulong[][] roundKeys;
  17. /* Number of 64-bit words in block */
  18. private int wordsInBlock;
  19. /* Number of 64-bit words in key */
  20. private int wordsInKey;
  21. /* Number of encryption rounds depending on key length */
  22. private const int ROUNDS_128 = 10;
  23. private const int ROUNDS_256 = 14;
  24. private const int ROUNDS_512 = 18;
  25. private int roundsAmount;
  26. private bool forEncryption;
  27. public Dstu7624Engine(int blockSizeBits)
  28. {
  29. /* DSTU7624 supports 128 | 256 | 512 key/block sizes */
  30. if (blockSizeBits != 128 && blockSizeBits != 256 && blockSizeBits != 512)
  31. {
  32. throw new ArgumentException("unsupported block length: only 128/256/512 are allowed");
  33. }
  34. wordsInBlock = blockSizeBits / 64;
  35. internalState = new ulong[wordsInBlock];
  36. }
  37. #region INITIALIZATION
  38. public virtual void Init(bool forEncryption, ICipherParameters parameters)
  39. {
  40. if (!(parameters is KeyParameter))
  41. throw new ArgumentException("Invalid parameter passed to Dstu7624Engine Init");
  42. this.forEncryption = forEncryption;
  43. byte[] keyBytes = ((KeyParameter)parameters).GetKey();
  44. int keyBitLength = keyBytes.Length << 3;
  45. int blockBitLength = wordsInBlock << 6;
  46. if (keyBitLength != 128 && keyBitLength != 256 && keyBitLength != 512)
  47. {
  48. throw new ArgumentException("unsupported key length: only 128/256/512 are allowed");
  49. }
  50. /* Limitations on key lengths depending on block lengths. See table 6.1 in standard */
  51. if (keyBitLength != blockBitLength && keyBitLength != (2 * blockBitLength))
  52. {
  53. throw new ArgumentException("Unsupported key length");
  54. }
  55. switch (keyBitLength)
  56. {
  57. case 128:
  58. roundsAmount = ROUNDS_128;
  59. break;
  60. case 256:
  61. roundsAmount = ROUNDS_256;
  62. break;
  63. case 512:
  64. roundsAmount = ROUNDS_512;
  65. break;
  66. }
  67. wordsInKey = keyBitLength / 64;
  68. /* +1 round key as defined in standard */
  69. roundKeys = new ulong[roundsAmount + 1][];
  70. for (int roundKeyIndex = 0; roundKeyIndex < roundKeys.Length; roundKeyIndex++)
  71. {
  72. roundKeys[roundKeyIndex] = new ulong[wordsInBlock];
  73. }
  74. workingKey = new ulong[wordsInKey];
  75. if (keyBytes.Length != wordsInKey * 8)
  76. {
  77. throw new ArgumentException("Invalid key parameter passed to Dstu7624Engine Init");
  78. }
  79. /* Unpack encryption key bytes to words */
  80. Pack.LE_To_UInt64(keyBytes, 0, workingKey);
  81. ulong[] tempKeys = new ulong[wordsInBlock];
  82. /* KSA in DSTU7624 is strengthened to mitigate known weaknesses in AES KSA (eprint.iacr.org/2012/260.pdf) */
  83. WorkingKeyExpandKT(workingKey, tempKeys);
  84. WorkingKeyExpandEven(workingKey, tempKeys);
  85. WorkingKeyExpandOdd();
  86. }
  87. private void WorkingKeyExpandKT(ulong[] workingKey, ulong[] tempKeys)
  88. {
  89. ulong[] k0 = new ulong[wordsInBlock];
  90. ulong[] k1 = new ulong[wordsInBlock];
  91. internalState = new ulong[wordsInBlock];
  92. internalState[0] += (ulong)(wordsInBlock + wordsInKey + 1);
  93. if (wordsInBlock == wordsInKey)
  94. {
  95. Array.Copy(workingKey, 0, k0, 0, k0.Length);
  96. Array.Copy(workingKey, 0, k1, 0, k1.Length);
  97. }
  98. else
  99. {
  100. Array.Copy(workingKey, 0, k0, 0, wordsInBlock);
  101. Array.Copy(workingKey, wordsInBlock, k1, 0, wordsInBlock);
  102. }
  103. for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++)
  104. {
  105. internalState[wordIndex] += k0[wordIndex];
  106. }
  107. EncryptionRound();
  108. for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++)
  109. {
  110. internalState[wordIndex] ^= k1[wordIndex];
  111. }
  112. EncryptionRound();
  113. for (int wordIndex = 0; wordIndex < internalState.Length; wordIndex++)
  114. {
  115. internalState[wordIndex] += k0[wordIndex];
  116. }
  117. EncryptionRound();
  118. Array.Copy(internalState, 0, tempKeys, 0, wordsInBlock);
  119. }
  120. private void WorkingKeyExpandEven(ulong[] workingKey, ulong[] tempKey)
  121. {
  122. ulong[] initialData = new ulong[wordsInKey];
  123. ulong[] tempRoundKey = new ulong[wordsInBlock];
  124. int round = 0;
  125. Array.Copy(workingKey, 0, initialData, 0, wordsInKey);
  126. ulong tmv = 0x0001000100010001UL;
  127. while (true)
  128. {
  129. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  130. {
  131. tempRoundKey[wordIndex] = tempKey[wordIndex] + tmv;
  132. }
  133. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  134. {
  135. internalState[wordIndex] = initialData[wordIndex] + tempRoundKey[wordIndex];
  136. }
  137. EncryptionRound();
  138. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  139. {
  140. internalState[wordIndex] ^= tempRoundKey[wordIndex];
  141. }
  142. EncryptionRound();
  143. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  144. {
  145. internalState[wordIndex] += tempRoundKey[wordIndex];
  146. }
  147. Array.Copy(internalState, 0, roundKeys[round], 0, wordsInBlock);
  148. if (roundsAmount == round)
  149. {
  150. break;
  151. }
  152. if (wordsInKey != wordsInBlock)
  153. {
  154. round += 2;
  155. tmv <<= 1;
  156. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  157. {
  158. tempRoundKey[wordIndex] = tempKey[wordIndex] + tmv;
  159. }
  160. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  161. {
  162. internalState[wordIndex] = initialData[wordsInBlock + wordIndex] + tempRoundKey[wordIndex];
  163. }
  164. EncryptionRound();
  165. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  166. {
  167. internalState[wordIndex] ^= tempRoundKey[wordIndex];
  168. }
  169. EncryptionRound();
  170. for (int wordIndex = 0; wordIndex < wordsInBlock; wordIndex++)
  171. {
  172. internalState[wordIndex] += tempRoundKey[wordIndex];
  173. }
  174. Array.Copy(internalState, 0, roundKeys[round], 0, wordsInBlock);
  175. if (roundsAmount == round)
  176. {
  177. break;
  178. }
  179. }
  180. round += 2;
  181. tmv <<= 1;
  182. ulong temp = initialData[0];
  183. for (int i = 1; i < initialData.Length; ++i)
  184. {
  185. initialData[i - 1] = initialData[i];
  186. }
  187. initialData[initialData.Length - 1] = temp;
  188. }
  189. }
  190. private void WorkingKeyExpandOdd()
  191. {
  192. for (int roundIndex = 1; roundIndex < roundsAmount; roundIndex += 2)
  193. {
  194. RotateLeft(roundKeys[roundIndex - 1], roundKeys[roundIndex]);
  195. }
  196. }
  197. #endregion
  198. public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
  199. {
  200. if (workingKey == null)
  201. throw new InvalidOperationException("Dstu7624Engine not initialised");
  202. Check.DataLength(input, inOff, GetBlockSize(), "input buffer too short");
  203. Check.OutputLength(output, outOff, GetBlockSize(), "output buffer too short");
  204. if (forEncryption)
  205. {
  206. /* Encrypt */
  207. switch (wordsInBlock)
  208. {
  209. case 2:
  210. {
  211. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  212. EncryptBlock_128(input.AsSpan(inOff), output.AsSpan(outOff));
  213. #else
  214. EncryptBlock_128(input, inOff, output, outOff);
  215. #endif
  216. break;
  217. }
  218. default:
  219. {
  220. Pack.LE_To_UInt64(input, inOff, internalState);
  221. AddRoundKey(0);
  222. for (int round = 0;;)
  223. {
  224. EncryptionRound();
  225. if (++round == roundsAmount)
  226. {
  227. break;
  228. }
  229. XorRoundKey(round);
  230. }
  231. AddRoundKey(roundsAmount);
  232. Pack.UInt64_To_LE(internalState, output, outOff);
  233. Array.Clear(internalState, 0, internalState.Length);
  234. break;
  235. }
  236. }
  237. }
  238. else
  239. {
  240. /* Decrypt */
  241. switch (wordsInBlock)
  242. {
  243. case 2:
  244. {
  245. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  246. DecryptBlock_128(input.AsSpan(inOff), output.AsSpan(outOff));
  247. #else
  248. DecryptBlock_128(input, inOff, output, outOff);
  249. #endif
  250. break;
  251. }
  252. default:
  253. {
  254. Pack.LE_To_UInt64(input, inOff, internalState);
  255. SubRoundKey(roundsAmount);
  256. for (int round = roundsAmount;;)
  257. {
  258. DecryptionRound();
  259. if (--round == 0)
  260. {
  261. break;
  262. }
  263. XorRoundKey(round);
  264. }
  265. SubRoundKey(0);
  266. Pack.UInt64_To_LE(internalState, output, outOff);
  267. Array.Clear(internalState, 0, internalState.Length);
  268. break;
  269. }
  270. }
  271. }
  272. return GetBlockSize();
  273. }
  274. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  275. public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
  276. {
  277. if (workingKey == null)
  278. throw new InvalidOperationException("Dstu7624Engine not initialised");
  279. Check.DataLength(input, GetBlockSize(), "input buffer too short");
  280. Check.OutputLength(output, GetBlockSize(), "output buffer too short");
  281. if (forEncryption)
  282. {
  283. /* Encrypt */
  284. switch (wordsInBlock)
  285. {
  286. case 2:
  287. {
  288. EncryptBlock_128(input, output);
  289. break;
  290. }
  291. default:
  292. {
  293. Pack.LE_To_UInt64(input, internalState);
  294. AddRoundKey(0);
  295. for (int round = 0;;)
  296. {
  297. EncryptionRound();
  298. if (++round == roundsAmount)
  299. {
  300. break;
  301. }
  302. XorRoundKey(round);
  303. }
  304. AddRoundKey(roundsAmount);
  305. Pack.UInt64_To_LE(internalState, output);
  306. Array.Clear(internalState, 0, internalState.Length);
  307. break;
  308. }
  309. }
  310. }
  311. else
  312. {
  313. /* Decrypt */
  314. switch (wordsInBlock)
  315. {
  316. case 2:
  317. {
  318. DecryptBlock_128(input, output);
  319. break;
  320. }
  321. default:
  322. {
  323. Pack.LE_To_UInt64(input, internalState);
  324. SubRoundKey(roundsAmount);
  325. for (int round = roundsAmount;;)
  326. {
  327. DecryptionRound();
  328. if (--round == 0)
  329. {
  330. break;
  331. }
  332. XorRoundKey(round);
  333. }
  334. SubRoundKey(0);
  335. Pack.UInt64_To_LE(internalState, output);
  336. Array.Clear(internalState, 0, internalState.Length);
  337. break;
  338. }
  339. }
  340. }
  341. return GetBlockSize();
  342. }
  343. #endif
  344. private void EncryptionRound()
  345. {
  346. SubBytes();
  347. ShiftRows();
  348. MixColumns();
  349. }
  350. private void DecryptionRound()
  351. {
  352. MixColumnsInv();
  353. InvShiftRows();
  354. InvSubBytes();
  355. }
  356. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  357. private void DecryptBlock_128(ReadOnlySpan<byte> input, Span<byte> output)
  358. {
  359. ulong c0 = Pack.LE_To_UInt64(input);
  360. ulong c1 = Pack.LE_To_UInt64(input[8..]);
  361. ulong[] roundKey = roundKeys[roundsAmount];
  362. c0 -= roundKey[0];
  363. c1 -= roundKey[1];
  364. for (int round = roundsAmount; ;)
  365. {
  366. c0 = MixColumnInv(c0);
  367. c1 = MixColumnInv(c1);
  368. uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
  369. uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
  370. {
  371. byte t0 = T0[lo0 & 0xFF];
  372. byte t1 = T1[(lo0 >> 8) & 0xFF];
  373. byte t2 = T2[(lo0 >> 16) & 0xFF];
  374. byte t3 = T3[lo0 >> 24];
  375. lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  376. byte t4 = T0[hi1 & 0xFF];
  377. byte t5 = T1[(hi1 >> 8) & 0xFF];
  378. byte t6 = T2[(hi1 >> 16) & 0xFF];
  379. byte t7 = T3[hi1 >> 24];
  380. hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  381. c0 = (ulong)lo0 | ((ulong)hi1 << 32);
  382. }
  383. {
  384. byte t0 = T0[lo1 & 0xFF];
  385. byte t1 = T1[(lo1 >> 8) & 0xFF];
  386. byte t2 = T2[(lo1 >> 16) & 0xFF];
  387. byte t3 = T3[lo1 >> 24];
  388. lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  389. byte t4 = T0[hi0 & 0xFF];
  390. byte t5 = T1[(hi0 >> 8) & 0xFF];
  391. byte t6 = T2[(hi0 >> 16) & 0xFF];
  392. byte t7 = T3[hi0 >> 24];
  393. hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  394. c1 = (ulong)lo1 | ((ulong)hi0 << 32);
  395. }
  396. if (--round == 0)
  397. {
  398. break;
  399. }
  400. roundKey = roundKeys[round];
  401. c0 ^= roundKey[0];
  402. c1 ^= roundKey[1];
  403. }
  404. roundKey = roundKeys[0];
  405. c0 -= roundKey[0];
  406. c1 -= roundKey[1];
  407. Pack.UInt64_To_LE(c0, output);
  408. Pack.UInt64_To_LE(c1, output[8..]);
  409. }
  410. private void EncryptBlock_128(ReadOnlySpan<byte> input, Span<byte> output)
  411. {
  412. ulong c0 = Pack.LE_To_UInt64(input);
  413. ulong c1 = Pack.LE_To_UInt64(input[8..]);
  414. ulong[] roundKey = roundKeys[0];
  415. c0 += roundKey[0];
  416. c1 += roundKey[1];
  417. for (int round = 0; ;)
  418. {
  419. uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
  420. uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
  421. {
  422. byte t0 = S0[lo0 & 0xFF];
  423. byte t1 = S1[(lo0 >> 8) & 0xFF];
  424. byte t2 = S2[(lo0 >> 16) & 0xFF];
  425. byte t3 = S3[lo0 >> 24];
  426. lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  427. byte t4 = S0[hi1 & 0xFF];
  428. byte t5 = S1[(hi1 >> 8) & 0xFF];
  429. byte t6 = S2[(hi1 >> 16) & 0xFF];
  430. byte t7 = S3[hi1 >> 24];
  431. hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  432. c0 = (ulong)lo0 | ((ulong)hi1 << 32);
  433. }
  434. {
  435. byte t0 = S0[lo1 & 0xFF];
  436. byte t1 = S1[(lo1 >> 8) & 0xFF];
  437. byte t2 = S2[(lo1 >> 16) & 0xFF];
  438. byte t3 = S3[lo1 >> 24];
  439. lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  440. byte t4 = S0[hi0 & 0xFF];
  441. byte t5 = S1[(hi0 >> 8) & 0xFF];
  442. byte t6 = S2[(hi0 >> 16) & 0xFF];
  443. byte t7 = S3[hi0 >> 24];
  444. hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  445. c1 = (ulong)lo1 | ((ulong)hi0 << 32);
  446. }
  447. c0 = MixColumn(c0);
  448. c1 = MixColumn(c1);
  449. if (++round == roundsAmount)
  450. {
  451. break;
  452. }
  453. roundKey = roundKeys[round];
  454. c0 ^= roundKey[0];
  455. c1 ^= roundKey[1];
  456. }
  457. roundKey = roundKeys[roundsAmount];
  458. c0 += roundKey[0];
  459. c1 += roundKey[1];
  460. Pack.UInt64_To_LE(c0, output);
  461. Pack.UInt64_To_LE(c1, output[8..]);
  462. }
  463. #else
  464. private void DecryptBlock_128(byte[] input, int inOff, byte[] output, int outOff)
  465. {
  466. ulong c0 = Pack.LE_To_UInt64(input, inOff);
  467. ulong c1 = Pack.LE_To_UInt64(input, inOff + 8);
  468. ulong[] roundKey = roundKeys[roundsAmount];
  469. c0 -= roundKey[0];
  470. c1 -= roundKey[1];
  471. for (int round = roundsAmount;;)
  472. {
  473. c0 = MixColumnInv(c0);
  474. c1 = MixColumnInv(c1);
  475. uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
  476. uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
  477. {
  478. byte t0 = T0[lo0 & 0xFF];
  479. byte t1 = T1[(lo0 >> 8) & 0xFF];
  480. byte t2 = T2[(lo0 >> 16) & 0xFF];
  481. byte t3 = T3[lo0 >> 24];
  482. lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  483. byte t4 = T0[hi1 & 0xFF];
  484. byte t5 = T1[(hi1 >> 8) & 0xFF];
  485. byte t6 = T2[(hi1 >> 16) & 0xFF];
  486. byte t7 = T3[hi1 >> 24];
  487. hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  488. c0 = (ulong)lo0 | ((ulong)hi1 << 32);
  489. }
  490. {
  491. byte t0 = T0[lo1 & 0xFF];
  492. byte t1 = T1[(lo1 >> 8) & 0xFF];
  493. byte t2 = T2[(lo1 >> 16) & 0xFF];
  494. byte t3 = T3[lo1 >> 24];
  495. lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  496. byte t4 = T0[hi0 & 0xFF];
  497. byte t5 = T1[(hi0 >> 8) & 0xFF];
  498. byte t6 = T2[(hi0 >> 16) & 0xFF];
  499. byte t7 = T3[hi0 >> 24];
  500. hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  501. c1 = (ulong)lo1 | ((ulong)hi0 << 32);
  502. }
  503. if (--round == 0)
  504. {
  505. break;
  506. }
  507. roundKey = roundKeys[round];
  508. c0 ^= roundKey[0];
  509. c1 ^= roundKey[1];
  510. }
  511. roundKey = roundKeys[0];
  512. c0 -= roundKey[0];
  513. c1 -= roundKey[1];
  514. Pack.UInt64_To_LE(c0, output, outOff);
  515. Pack.UInt64_To_LE(c1, output, outOff + 8);
  516. }
  517. private void EncryptBlock_128(byte[] input, int inOff, byte[] output, int outOff)
  518. {
  519. ulong c0 = Pack.LE_To_UInt64(input, inOff);
  520. ulong c1 = Pack.LE_To_UInt64(input, inOff + 8);
  521. ulong[] roundKey = roundKeys[0];
  522. c0 += roundKey[0];
  523. c1 += roundKey[1];
  524. for (int round = 0;;)
  525. {
  526. uint lo0 = (uint)c0, hi0 = (uint)(c0 >> 32);
  527. uint lo1 = (uint)c1, hi1 = (uint)(c1 >> 32);
  528. {
  529. byte t0 = S0[lo0 & 0xFF];
  530. byte t1 = S1[(lo0 >> 8) & 0xFF];
  531. byte t2 = S2[(lo0 >> 16) & 0xFF];
  532. byte t3 = S3[lo0 >> 24];
  533. lo0 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  534. byte t4 = S0[hi1 & 0xFF];
  535. byte t5 = S1[(hi1 >> 8) & 0xFF];
  536. byte t6 = S2[(hi1 >> 16) & 0xFF];
  537. byte t7 = S3[hi1 >> 24];
  538. hi1 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  539. c0 = (ulong)lo0 | ((ulong)hi1 << 32);
  540. }
  541. {
  542. byte t0 = S0[lo1 & 0xFF];
  543. byte t1 = S1[(lo1 >> 8) & 0xFF];
  544. byte t2 = S2[(lo1 >> 16) & 0xFF];
  545. byte t3 = S3[lo1 >> 24];
  546. lo1 = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  547. byte t4 = S0[hi0 & 0xFF];
  548. byte t5 = S1[(hi0 >> 8) & 0xFF];
  549. byte t6 = S2[(hi0 >> 16) & 0xFF];
  550. byte t7 = S3[hi0 >> 24];
  551. hi0 = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  552. c1 = (ulong)lo1 | ((ulong)hi0 << 32);
  553. }
  554. c0 = MixColumn(c0);
  555. c1 = MixColumn(c1);
  556. if (++round == roundsAmount)
  557. {
  558. break;
  559. }
  560. roundKey = roundKeys[round];
  561. c0 ^= roundKey[0];
  562. c1 ^= roundKey[1];
  563. }
  564. roundKey = roundKeys[roundsAmount];
  565. c0 += roundKey[0];
  566. c1 += roundKey[1];
  567. Pack.UInt64_To_LE(c0, output, outOff);
  568. Pack.UInt64_To_LE(c1, output, outOff + 8);
  569. }
  570. #endif
  571. private void SubBytes()
  572. {
  573. for (int i = 0; i < wordsInBlock; i++)
  574. {
  575. ulong u = internalState[i];
  576. uint lo = (uint)u, hi = (uint)(u >> 32);
  577. byte t0 = S0[lo & 0xFF];
  578. byte t1 = S1[(lo >> 8) & 0xFF];
  579. byte t2 = S2[(lo >> 16) & 0xFF];
  580. byte t3 = S3[lo >> 24];
  581. lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  582. byte t4 = S0[hi & 0xFF];
  583. byte t5 = S1[(hi >> 8) & 0xFF];
  584. byte t6 = S2[(hi >> 16) & 0xFF];
  585. byte t7 = S3[hi >> 24];
  586. hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  587. internalState[i] = (ulong)lo | ((ulong)hi << 32);
  588. }
  589. }
  590. private void InvSubBytes()
  591. {
  592. for (int i = 0; i < wordsInBlock; i++)
  593. {
  594. ulong u = internalState[i];
  595. uint lo = (uint)u, hi = (uint)(u >> 32);
  596. byte t0 = T0[lo & 0xFF];
  597. byte t1 = T1[(lo >> 8) & 0xFF];
  598. byte t2 = T2[(lo >> 16) & 0xFF];
  599. byte t3 = T3[lo >> 24];
  600. lo = (uint)t0 | ((uint)t1 << 8) | ((uint)t2 << 16) | ((uint)t3 << 24);
  601. byte t4 = T0[hi & 0xFF];
  602. byte t5 = T1[(hi >> 8) & 0xFF];
  603. byte t6 = T2[(hi >> 16) & 0xFF];
  604. byte t7 = T3[hi >> 24];
  605. hi = (uint)t4 | ((uint)t5 << 8) | ((uint)t6 << 16) | ((uint)t7 << 24);
  606. internalState[i] = (ulong)lo | ((ulong)hi << 32);
  607. }
  608. }
  609. private void ShiftRows()
  610. {
  611. switch (wordsInBlock)
  612. {
  613. case 2:
  614. {
  615. ulong c0 = internalState[0], c1 = internalState[1];
  616. ulong d;
  617. d = (c0 ^ c1) & 0xFFFFFFFF00000000UL; c0 ^= d; c1 ^= d;
  618. internalState[0] = c0;
  619. internalState[1] = c1;
  620. break;
  621. }
  622. case 4:
  623. {
  624. ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
  625. ulong d;
  626. d = (c0 ^ c2) & 0xFFFFFFFF00000000UL; c0 ^= d; c2 ^= d;
  627. d = (c1 ^ c3) & 0x0000FFFFFFFF0000UL; c1 ^= d; c3 ^= d;
  628. d = (c0 ^ c1) & 0xFFFF0000FFFF0000UL; c0 ^= d; c1 ^= d;
  629. d = (c2 ^ c3) & 0xFFFF0000FFFF0000UL; c2 ^= d; c3 ^= d;
  630. internalState[0] = c0;
  631. internalState[1] = c1;
  632. internalState[2] = c2;
  633. internalState[3] = c3;
  634. break;
  635. }
  636. case 8:
  637. {
  638. ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
  639. ulong c4 = internalState[4], c5 = internalState[5], c6 = internalState[6], c7 = internalState[7];
  640. ulong d;
  641. d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d;
  642. d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d;
  643. d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d;
  644. d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d;
  645. d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d;
  646. d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d;
  647. d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d;
  648. d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d;
  649. d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d;
  650. d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d;
  651. d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d;
  652. d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d;
  653. internalState[0] = c0;
  654. internalState[1] = c1;
  655. internalState[2] = c2;
  656. internalState[3] = c3;
  657. internalState[4] = c4;
  658. internalState[5] = c5;
  659. internalState[6] = c6;
  660. internalState[7] = c7;
  661. break;
  662. }
  663. default:
  664. {
  665. throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
  666. }
  667. }
  668. }
  669. private void InvShiftRows()
  670. {
  671. switch (wordsInBlock)
  672. {
  673. case 2:
  674. {
  675. ulong c0 = internalState[0], c1 = internalState[1];
  676. ulong d;
  677. d = (c0 ^ c1) & 0xFFFFFFFF00000000UL; c0 ^= d; c1 ^= d;
  678. internalState[0] = c0;
  679. internalState[1] = c1;
  680. break;
  681. }
  682. case 4:
  683. {
  684. ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
  685. ulong d;
  686. d = (c0 ^ c1) & 0xFFFF0000FFFF0000UL; c0 ^= d; c1 ^= d;
  687. d = (c2 ^ c3) & 0xFFFF0000FFFF0000UL; c2 ^= d; c3 ^= d;
  688. d = (c0 ^ c2) & 0xFFFFFFFF00000000UL; c0 ^= d; c2 ^= d;
  689. d = (c1 ^ c3) & 0x0000FFFFFFFF0000UL; c1 ^= d; c3 ^= d;
  690. internalState[0] = c0;
  691. internalState[1] = c1;
  692. internalState[2] = c2;
  693. internalState[3] = c3;
  694. break;
  695. }
  696. case 8:
  697. {
  698. ulong c0 = internalState[0], c1 = internalState[1], c2 = internalState[2], c3 = internalState[3];
  699. ulong c4 = internalState[4], c5 = internalState[5], c6 = internalState[6], c7 = internalState[7];
  700. ulong d;
  701. d = (c0 ^ c1) & 0xFF00FF00FF00FF00UL; c0 ^= d; c1 ^= d;
  702. d = (c2 ^ c3) & 0xFF00FF00FF00FF00UL; c2 ^= d; c3 ^= d;
  703. d = (c4 ^ c5) & 0xFF00FF00FF00FF00UL; c4 ^= d; c5 ^= d;
  704. d = (c6 ^ c7) & 0xFF00FF00FF00FF00UL; c6 ^= d; c7 ^= d;
  705. d = (c0 ^ c2) & 0xFFFF0000FFFF0000UL; c0 ^= d; c2 ^= d;
  706. d = (c1 ^ c3) & 0x00FFFF0000FFFF00UL; c1 ^= d; c3 ^= d;
  707. d = (c4 ^ c6) & 0xFFFF0000FFFF0000UL; c4 ^= d; c6 ^= d;
  708. d = (c5 ^ c7) & 0x00FFFF0000FFFF00UL; c5 ^= d; c7 ^= d;
  709. d = (c0 ^ c4) & 0xFFFFFFFF00000000UL; c0 ^= d; c4 ^= d;
  710. d = (c1 ^ c5) & 0x00FFFFFFFF000000UL; c1 ^= d; c5 ^= d;
  711. d = (c2 ^ c6) & 0x0000FFFFFFFF0000UL; c2 ^= d; c6 ^= d;
  712. d = (c3 ^ c7) & 0x000000FFFFFFFF00UL; c3 ^= d; c7 ^= d;
  713. internalState[0] = c0;
  714. internalState[1] = c1;
  715. internalState[2] = c2;
  716. internalState[3] = c3;
  717. internalState[4] = c4;
  718. internalState[5] = c5;
  719. internalState[6] = c6;
  720. internalState[7] = c7;
  721. break;
  722. }
  723. default:
  724. {
  725. throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
  726. }
  727. }
  728. }
  729. private void AddRoundKey(int round)
  730. {
  731. ulong[] roundKey = roundKeys[round];
  732. for (int i = 0; i < wordsInBlock; ++i)
  733. {
  734. internalState[i] += roundKey[i];
  735. }
  736. }
  737. private void SubRoundKey(int round)
  738. {
  739. ulong[] roundKey = roundKeys[round];
  740. for (int i = 0; i < wordsInBlock; ++i)
  741. {
  742. internalState[i] -= roundKey[i];
  743. }
  744. }
  745. private void XorRoundKey(int round)
  746. {
  747. ulong[] roundKey = roundKeys[round];
  748. for (int i = 0; i < wordsInBlock; i++)
  749. {
  750. internalState[i] ^= roundKey[i];
  751. }
  752. }
  753. private static ulong MixColumn(ulong c)
  754. {
  755. //// Calculate column multiplied by powers of 'x'
  756. //ulong x0 = c;
  757. //ulong x1 = MulX(x0);
  758. //ulong x2 = MulX(x1);
  759. //ulong x3 = MulX(x2);
  760. //// Calculate products with circulant matrix from (0x01, 0x01, 0x05, 0x01, 0x08, 0x06, 0x07, 0x04)
  761. //ulong m0 = x0;
  762. //ulong m1 = x0;
  763. //ulong m2 = x0 ^ x2;
  764. //ulong m3 = x0;
  765. //ulong m4 = x3;
  766. //ulong m5 = x1 ^ x2;
  767. //ulong m6 = x0 ^ x1 ^ x2;
  768. //ulong m7 = x2;
  769. //// Assemble the rotated products
  770. //return m0
  771. // ^ Rotate(8, m1)
  772. // ^ Rotate(16, m2)
  773. // ^ Rotate(24, m3)
  774. // ^ Rotate(32, m4)
  775. // ^ Rotate(40, m5)
  776. // ^ Rotate(48, m6)
  777. // ^ Rotate(56, m7);
  778. ulong x1 = MulX(c);
  779. ulong u, v;
  780. u = Rotate(8, c) ^ c;
  781. u ^= Rotate(16, u);
  782. u ^= Rotate(48, c);
  783. v = MulX2(u ^ c ^ x1);
  784. return u ^ Rotate(32, v) ^ Rotate(40, x1) ^ Rotate(48, x1);
  785. }
  786. private void MixColumns()
  787. {
  788. for (int col = 0; col < wordsInBlock; ++col)
  789. {
  790. internalState[col] = MixColumn(internalState[col]);
  791. }
  792. }
  793. private static ulong MixColumnInv(ulong c)
  794. {
  795. /*
  796. // Calculate column multiplied by powers of 'x'
  797. ulong x0 = c;
  798. ulong x1 = MulX(x0);
  799. ulong x2 = MulX(x1);
  800. ulong x3 = MulX(x2);
  801. ulong x4 = MulX(x3);
  802. ulong x5 = MulX(x4);
  803. ulong x6 = MulX(x5);
  804. ulong x7 = MulX(x6);
  805. // Calculate products with circulant matrix from (0xAD,0x95,0x76,0xA8,0x2F,0x49,0xD7,0xCA)
  806. //long m0 = x0 ^ x2 ^ x3 ^ x5 ^ x7;
  807. //long m1 = x0 ^ x2 ^ x4 ^ x7;
  808. //long m2 = x1 ^ x2 ^ x4 ^ x5 ^ x6;
  809. //long m3 = x3 ^ x5 ^ x7;
  810. //long m4 = x0 ^ x1 ^ x2 ^ x3 ^ x5;
  811. //long m5 = x0 ^ x3 ^ x6;
  812. //long m6 = x0 ^ x1 ^ x2 ^ x4 ^ x6 ^ x7;
  813. //long m7 = x1 ^ x3 ^ x6 ^ x7;
  814. ulong m5 = x0 ^ x3 ^ x6;
  815. x0 ^= x2;
  816. ulong m3 = x3 ^ x5 ^ x7;
  817. ulong m0 = m3 ^ x0;
  818. ulong m6 = x0 ^ x4;
  819. ulong m1 = m6 ^ x7;
  820. x5 ^= x1;
  821. x7 ^= x1 ^ x6;
  822. ulong m2 = x2 ^ x4 ^ x5 ^ x6;
  823. ulong m4 = x0 ^ x3 ^ x5;
  824. m6 ^= x7;
  825. ulong m7 = x3 ^ x7;
  826. // Assemble the rotated products
  827. return m0
  828. ^ Rotate(8, m1)
  829. ^ Rotate(16, m2)
  830. ^ Rotate(24, m3)
  831. ^ Rotate(32, m4)
  832. ^ Rotate(40, m5)
  833. ^ Rotate(48, m6)
  834. ^ Rotate(56, m7);
  835. */
  836. ulong u0 = c;
  837. u0 ^= Rotate( 8, u0);
  838. u0 ^= Rotate(32, u0);
  839. u0 ^= Rotate(48, c);
  840. ulong t = u0 ^ c;
  841. ulong c48 = Rotate(48, c);
  842. ulong c56 = Rotate(56, c);
  843. ulong u7 = t ^ c56;
  844. ulong u6 = Rotate(56, t);
  845. u6 ^= MulX(u7);
  846. ulong u5 = Rotate(16, t) ^ c;
  847. u5 ^= Rotate(40, MulX(u6) ^ c);
  848. ulong u4 = t ^ c48;
  849. u4 ^= MulX(u5);
  850. ulong u3 = Rotate(16, u0);
  851. u3 ^= MulX(u4);
  852. ulong u2 = t ^ Rotate(24, c) ^ c48 ^ c56;
  853. u2 ^= MulX(u3);
  854. ulong u1 = Rotate(32, t) ^ c ^ c56;
  855. u1 ^= MulX(u2);
  856. u0 ^= MulX(Rotate(40, u1));
  857. return u0;
  858. }
  859. private void MixColumnsInv()
  860. {
  861. for (int col = 0; col < wordsInBlock; ++col)
  862. {
  863. internalState[col] = MixColumnInv(internalState[col]);
  864. }
  865. }
  866. private static ulong MulX(ulong n)
  867. {
  868. return ((n & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((n & 0x8080808080808080UL) >> 7) * 0x1DUL);
  869. }
  870. private static ulong MulX2(ulong n)
  871. {
  872. return ((n & 0x3F3F3F3F3F3F3F3FUL) << 2) ^ (((n & 0x8080808080808080UL) >> 6) * 0x1DUL) ^ (((n & 0x4040404040404040UL) >> 6) * 0x1DUL);
  873. }
  874. //private static ulong MulX4(ulong n)
  875. //{
  876. // ulong u = n & 0xF0F0F0F0F0F0F0F0UL;
  877. // return ((n & 0x0F0F0F0F0F0F0F0FUL) << 4) ^ u ^ (u >> 1) ^ (u >> 2) ^ (u >> 4);
  878. //}
  879. /*
  880. * Pair-wise modular multiplication of 8 byte-pairs.
  881. *
  882. * REDUCTION_POLYNOMIAL is x^8 + x^4 + x^3 + x^2 + 1
  883. */
  884. //private static ulong MultiplyGFx8(ulong u, ulong v, int vMaxDegree)
  885. //{
  886. // ulong r = u & ((v & 0x0101010101010101UL) * 0xFFUL);
  887. // for (int i = 1; i <= vMaxDegree; ++i)
  888. // {
  889. // u = ((u & 0x7F7F7F7F7F7F7F7FUL) << 1) ^ (((u >> 7) & 0x0101010101010101UL) * 0x1DUL);
  890. // v >>= 1;
  891. // r ^= u & ((v & 0x0101010101010101UL) * 0xFFUL);
  892. // }
  893. // return r;
  894. //}
  895. //private static ulong MultiplyMds(ulong u)
  896. //{
  897. // ulong r = 0, s = 0, t = (u >> 8);
  898. // r ^= u & 0x0000001F00000000UL; r <<= 1;
  899. // s ^= t & 0x00000000E0000000UL; s <<= 1;
  900. // r ^= u & 0x3F3F3F00003F0000UL; r <<= 1;
  901. // s ^= t & 0x00C0C0C00000C000UL; s <<= 1;
  902. // r ^= u & 0x007F7F0000000000UL; r <<= 1;
  903. // s ^= t & 0x0000808000000000UL; s <<= 1;
  904. // r ^= u & 0x00FF0000FFFFFFFFUL;
  905. // r ^= s ^ (s << 2) ^ (s << 3) ^ (s << 4);
  906. // return r;
  907. //}
  908. private static ulong Rotate(int n, ulong x)
  909. {
  910. return (x >> n) | (x << -n);
  911. }
  912. private void RotateLeft(ulong[] x, ulong[] z)
  913. {
  914. switch (wordsInBlock)
  915. {
  916. case 2:
  917. {
  918. ulong x0 = x[0], x1 = x[1];
  919. z[0] = (x0 >> 56) | (x1 << 8);
  920. z[1] = (x1 >> 56) | (x0 << 8);
  921. break;
  922. }
  923. case 4:
  924. {
  925. ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
  926. z[0] = (x1 >> 24) | (x2 << 40);
  927. z[1] = (x2 >> 24) | (x3 << 40);
  928. z[2] = (x3 >> 24) | (x0 << 40);
  929. z[3] = (x0 >> 24) | (x1 << 40);
  930. break;
  931. }
  932. case 8:
  933. {
  934. ulong x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3];
  935. ulong x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7];
  936. z[0] = (x2 >> 24) | (x3 << 40);
  937. z[1] = (x3 >> 24) | (x4 << 40);
  938. z[2] = (x4 >> 24) | (x5 << 40);
  939. z[3] = (x5 >> 24) | (x6 << 40);
  940. z[4] = (x6 >> 24) | (x7 << 40);
  941. z[5] = (x7 >> 24) | (x0 << 40);
  942. z[6] = (x0 >> 24) | (x1 << 40);
  943. z[7] = (x1 >> 24) | (x2 << 40);
  944. break;
  945. }
  946. default:
  947. {
  948. throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
  949. }
  950. }
  951. }
  952. #region TABLES AND S-BOXES
  953. private const ulong mdsMatrix = 0x0407060801050101UL;
  954. private const ulong mdsInvMatrix = 0xCAD7492FA87695ADUL;
  955. private static readonly byte[] S0 = new byte[]{
  956. 0xa8, 0x43, 0x5f, 0x06, 0x6b, 0x75, 0x6c, 0x59, 0x71, 0xdf, 0x87, 0x95, 0x17, 0xf0, 0xd8, 0x09,
  957. 0x6d, 0xf3, 0x1d, 0xcb, 0xc9, 0x4d, 0x2c, 0xaf, 0x79, 0xe0, 0x97, 0xfd, 0x6f, 0x4b, 0x45, 0x39,
  958. 0x3e, 0xdd, 0xa3, 0x4f, 0xb4, 0xb6, 0x9a, 0x0e, 0x1f, 0xbf, 0x15, 0xe1, 0x49, 0xd2, 0x93, 0xc6,
  959. 0x92, 0x72, 0x9e, 0x61, 0xd1, 0x63, 0xfa, 0xee, 0xf4, 0x19, 0xd5, 0xad, 0x58, 0xa4, 0xbb, 0xa1,
  960. 0xdc, 0xf2, 0x83, 0x37, 0x42, 0xe4, 0x7a, 0x32, 0x9c, 0xcc, 0xab, 0x4a, 0x8f, 0x6e, 0x04, 0x27,
  961. 0x2e, 0xe7, 0xe2, 0x5a, 0x96, 0x16, 0x23, 0x2b, 0xc2, 0x65, 0x66, 0x0f, 0xbc, 0xa9, 0x47, 0x41,
  962. 0x34, 0x48, 0xfc, 0xb7, 0x6a, 0x88, 0xa5, 0x53, 0x86, 0xf9, 0x5b, 0xdb, 0x38, 0x7b, 0xc3, 0x1e,
  963. 0x22, 0x33, 0x24, 0x28, 0x36, 0xc7, 0xb2, 0x3b, 0x8e, 0x77, 0xba, 0xf5, 0x14, 0x9f, 0x08, 0x55,
  964. 0x9b, 0x4c, 0xfe, 0x60, 0x5c, 0xda, 0x18, 0x46, 0xcd, 0x7d, 0x21, 0xb0, 0x3f, 0x1b, 0x89, 0xff,
  965. 0xeb, 0x84, 0x69, 0x3a, 0x9d, 0xd7, 0xd3, 0x70, 0x67, 0x40, 0xb5, 0xde, 0x5d, 0x30, 0x91, 0xb1,
  966. 0x78, 0x11, 0x01, 0xe5, 0x00, 0x68, 0x98, 0xa0, 0xc5, 0x02, 0xa6, 0x74, 0x2d, 0x0b, 0xa2, 0x76,
  967. 0xb3, 0xbe, 0xce, 0xbd, 0xae, 0xe9, 0x8a, 0x31, 0x1c, 0xec, 0xf1, 0x99, 0x94, 0xaa, 0xf6, 0x26,
  968. 0x2f, 0xef, 0xe8, 0x8c, 0x35, 0x03, 0xd4, 0x7f, 0xfb, 0x05, 0xc1, 0x5e, 0x90, 0x20, 0x3d, 0x82,
  969. 0xf7, 0xea, 0x0a, 0x0d, 0x7e, 0xf8, 0x50, 0x1a, 0xc4, 0x07, 0x57, 0xb8, 0x3c, 0x62, 0xe3, 0xc8,
  970. 0xac, 0x52, 0x64, 0x10, 0xd0, 0xd9, 0x13, 0x0c, 0x12, 0x29, 0x51, 0xb9, 0xcf, 0xd6, 0x73, 0x8d,
  971. 0x81, 0x54, 0xc0, 0xed, 0x4e, 0x44, 0xa7, 0x2a, 0x85, 0x25, 0xe6, 0xca, 0x7c, 0x8b, 0x56, 0x80
  972. };
  973. private static readonly byte[] S1 = new byte[]{
  974. 0xce, 0xbb, 0xeb, 0x92, 0xea, 0xcb, 0x13, 0xc1, 0xe9, 0x3a, 0xd6, 0xb2, 0xd2, 0x90, 0x17, 0xf8,
  975. 0x42, 0x15, 0x56, 0xb4, 0x65, 0x1c, 0x88, 0x43, 0xc5, 0x5c, 0x36, 0xba, 0xf5, 0x57, 0x67, 0x8d,
  976. 0x31, 0xf6, 0x64, 0x58, 0x9e, 0xf4, 0x22, 0xaa, 0x75, 0x0f, 0x02, 0xb1, 0xdf, 0x6d, 0x73, 0x4d,
  977. 0x7c, 0x26, 0x2e, 0xf7, 0x08, 0x5d, 0x44, 0x3e, 0x9f, 0x14, 0xc8, 0xae, 0x54, 0x10, 0xd8, 0xbc,
  978. 0x1a, 0x6b, 0x69, 0xf3, 0xbd, 0x33, 0xab, 0xfa, 0xd1, 0x9b, 0x68, 0x4e, 0x16, 0x95, 0x91, 0xee,
  979. 0x4c, 0x63, 0x8e, 0x5b, 0xcc, 0x3c, 0x19, 0xa1, 0x81, 0x49, 0x7b, 0xd9, 0x6f, 0x37, 0x60, 0xca,
  980. 0xe7, 0x2b, 0x48, 0xfd, 0x96, 0x45, 0xfc, 0x41, 0x12, 0x0d, 0x79, 0xe5, 0x89, 0x8c, 0xe3, 0x20,
  981. 0x30, 0xdc, 0xb7, 0x6c, 0x4a, 0xb5, 0x3f, 0x97, 0xd4, 0x62, 0x2d, 0x06, 0xa4, 0xa5, 0x83, 0x5f,
  982. 0x2a, 0xda, 0xc9, 0x00, 0x7e, 0xa2, 0x55, 0xbf, 0x11, 0xd5, 0x9c, 0xcf, 0x0e, 0x0a, 0x3d, 0x51,
  983. 0x7d, 0x93, 0x1b, 0xfe, 0xc4, 0x47, 0x09, 0x86, 0x0b, 0x8f, 0x9d, 0x6a, 0x07, 0xb9, 0xb0, 0x98,
  984. 0x18, 0x32, 0x71, 0x4b, 0xef, 0x3b, 0x70, 0xa0, 0xe4, 0x40, 0xff, 0xc3, 0xa9, 0xe6, 0x78, 0xf9,
  985. 0x8b, 0x46, 0x80, 0x1e, 0x38, 0xe1, 0xb8, 0xa8, 0xe0, 0x0c, 0x23, 0x76, 0x1d, 0x25, 0x24, 0x05,
  986. 0xf1, 0x6e, 0x94, 0x28, 0x9a, 0x84, 0xe8, 0xa3, 0x4f, 0x77, 0xd3, 0x85, 0xe2, 0x52, 0xf2, 0x82,
  987. 0x50, 0x7a, 0x2f, 0x74, 0x53, 0xb3, 0x61, 0xaf, 0x39, 0x35, 0xde, 0xcd, 0x1f, 0x99, 0xac, 0xad,
  988. 0x72, 0x2c, 0xdd, 0xd0, 0x87, 0xbe, 0x5e, 0xa6, 0xec, 0x04, 0xc6, 0x03, 0x34, 0xfb, 0xdb, 0x59,
  989. 0xb6, 0xc2, 0x01, 0xf0, 0x5a, 0xed, 0xa7, 0x66, 0x21, 0x7f, 0x8a, 0x27, 0xc7, 0xc0, 0x29, 0xd7
  990. };
  991. private static readonly byte[] S2 = new byte[]{
  992. 0x93, 0xd9, 0x9a, 0xb5, 0x98, 0x22, 0x45, 0xfc, 0xba, 0x6a, 0xdf, 0x02, 0x9f, 0xdc, 0x51, 0x59,
  993. 0x4a, 0x17, 0x2b, 0xc2, 0x94, 0xf4, 0xbb, 0xa3, 0x62, 0xe4, 0x71, 0xd4, 0xcd, 0x70, 0x16, 0xe1,
  994. 0x49, 0x3c, 0xc0, 0xd8, 0x5c, 0x9b, 0xad, 0x85, 0x53, 0xa1, 0x7a, 0xc8, 0x2d, 0xe0, 0xd1, 0x72,
  995. 0xa6, 0x2c, 0xc4, 0xe3, 0x76, 0x78, 0xb7, 0xb4, 0x09, 0x3b, 0x0e, 0x41, 0x4c, 0xde, 0xb2, 0x90,
  996. 0x25, 0xa5, 0xd7, 0x03, 0x11, 0x00, 0xc3, 0x2e, 0x92, 0xef, 0x4e, 0x12, 0x9d, 0x7d, 0xcb, 0x35,
  997. 0x10, 0xd5, 0x4f, 0x9e, 0x4d, 0xa9, 0x55, 0xc6, 0xd0, 0x7b, 0x18, 0x97, 0xd3, 0x36, 0xe6, 0x48,
  998. 0x56, 0x81, 0x8f, 0x77, 0xcc, 0x9c, 0xb9, 0xe2, 0xac, 0xb8, 0x2f, 0x15, 0xa4, 0x7c, 0xda, 0x38,
  999. 0x1e, 0x0b, 0x05, 0xd6, 0x14, 0x6e, 0x6c, 0x7e, 0x66, 0xfd, 0xb1, 0xe5, 0x60, 0xaf, 0x5e, 0x33,
  1000. 0x87, 0xc9, 0xf0, 0x5d, 0x6d, 0x3f, 0x88, 0x8d, 0xc7, 0xf7, 0x1d, 0xe9, 0xec, 0xed, 0x80, 0x29,
  1001. 0x27, 0xcf, 0x99, 0xa8, 0x50, 0x0f, 0x37, 0x24, 0x28, 0x30, 0x95, 0xd2, 0x3e, 0x5b, 0x40, 0x83,
  1002. 0xb3, 0x69, 0x57, 0x1f, 0x07, 0x1c, 0x8a, 0xbc, 0x20, 0xeb, 0xce, 0x8e, 0xab, 0xee, 0x31, 0xa2,
  1003. 0x73, 0xf9, 0xca, 0x3a, 0x1a, 0xfb, 0x0d, 0xc1, 0xfe, 0xfa, 0xf2, 0x6f, 0xbd, 0x96, 0xdd, 0x43,
  1004. 0x52, 0xb6, 0x08, 0xf3, 0xae, 0xbe, 0x19, 0x89, 0x32, 0x26, 0xb0, 0xea, 0x4b, 0x64, 0x84, 0x82,
  1005. 0x6b, 0xf5, 0x79, 0xbf, 0x01, 0x5f, 0x75, 0x63, 0x1b, 0x23, 0x3d, 0x68, 0x2a, 0x65, 0xe8, 0x91,
  1006. 0xf6, 0xff, 0x13, 0x58, 0xf1, 0x47, 0x0a, 0x7f, 0xc5, 0xa7, 0xe7, 0x61, 0x5a, 0x06, 0x46, 0x44,
  1007. 0x42, 0x04, 0xa0, 0xdb, 0x39, 0x86, 0x54, 0xaa, 0x8c, 0x34, 0x21, 0x8b, 0xf8, 0x0c, 0x74, 0x67
  1008. };
  1009. private static readonly byte[] S3 = new byte[]{
  1010. 0x68, 0x8d, 0xca, 0x4d, 0x73, 0x4b, 0x4e, 0x2a, 0xd4, 0x52, 0x26, 0xb3, 0x54, 0x1e, 0x19, 0x1f,
  1011. 0x22, 0x03, 0x46, 0x3d, 0x2d, 0x4a, 0x53, 0x83, 0x13, 0x8a, 0xb7, 0xd5, 0x25, 0x79, 0xf5, 0xbd,
  1012. 0x58, 0x2f, 0x0d, 0x02, 0xed, 0x51, 0x9e, 0x11, 0xf2, 0x3e, 0x55, 0x5e, 0xd1, 0x16, 0x3c, 0x66,
  1013. 0x70, 0x5d, 0xf3, 0x45, 0x40, 0xcc, 0xe8, 0x94, 0x56, 0x08, 0xce, 0x1a, 0x3a, 0xd2, 0xe1, 0xdf,
  1014. 0xb5, 0x38, 0x6e, 0x0e, 0xe5, 0xf4, 0xf9, 0x86, 0xe9, 0x4f, 0xd6, 0x85, 0x23, 0xcf, 0x32, 0x99,
  1015. 0x31, 0x14, 0xae, 0xee, 0xc8, 0x48, 0xd3, 0x30, 0xa1, 0x92, 0x41, 0xb1, 0x18, 0xc4, 0x2c, 0x71,
  1016. 0x72, 0x44, 0x15, 0xfd, 0x37, 0xbe, 0x5f, 0xaa, 0x9b, 0x88, 0xd8, 0xab, 0x89, 0x9c, 0xfa, 0x60,
  1017. 0xea, 0xbc, 0x62, 0x0c, 0x24, 0xa6, 0xa8, 0xec, 0x67, 0x20, 0xdb, 0x7c, 0x28, 0xdd, 0xac, 0x5b,
  1018. 0x34, 0x7e, 0x10, 0xf1, 0x7b, 0x8f, 0x63, 0xa0, 0x05, 0x9a, 0x43, 0x77, 0x21, 0xbf, 0x27, 0x09,
  1019. 0xc3, 0x9f, 0xb6, 0xd7, 0x29, 0xc2, 0xeb, 0xc0, 0xa4, 0x8b, 0x8c, 0x1d, 0xfb, 0xff, 0xc1, 0xb2,
  1020. 0x97, 0x2e, 0xf8, 0x65, 0xf6, 0x75, 0x07, 0x04, 0x49, 0x33, 0xe4, 0xd9, 0xb9, 0xd0, 0x42, 0xc7,
  1021. 0x6c, 0x90, 0x00, 0x8e, 0x6f, 0x50, 0x01, 0xc5, 0xda, 0x47, 0x3f, 0xcd, 0x69, 0xa2, 0xe2, 0x7a,
  1022. 0xa7, 0xc6, 0x93, 0x0f, 0x0a, 0x06, 0xe6, 0x2b, 0x96, 0xa3, 0x1c, 0xaf, 0x6a, 0x12, 0x84, 0x39,
  1023. 0xe7, 0xb0, 0x82, 0xf7, 0xfe, 0x9d, 0x87, 0x5c, 0x81, 0x35, 0xde, 0xb4, 0xa5, 0xfc, 0x80, 0xef,
  1024. 0xcb, 0xbb, 0x6b, 0x76, 0xba, 0x5a, 0x7d, 0x78, 0x0b, 0x95, 0xe3, 0xad, 0x74, 0x98, 0x3b, 0x36,
  1025. 0x64, 0x6d, 0xdc, 0xf0, 0x59, 0xa9, 0x4c, 0x17, 0x7f, 0x91, 0xb8, 0xc9, 0x57, 0x1b, 0xe0, 0x61
  1026. };
  1027. private static readonly byte[] T0 = new byte[]{
  1028. 0xa4, 0xa2, 0xa9, 0xc5, 0x4e, 0xc9, 0x03, 0xd9, 0x7e, 0x0f, 0xd2, 0xad, 0xe7, 0xd3, 0x27, 0x5b,
  1029. 0xe3, 0xa1, 0xe8, 0xe6, 0x7c, 0x2a, 0x55, 0x0c, 0x86, 0x39, 0xd7, 0x8d, 0xb8, 0x12, 0x6f, 0x28,
  1030. 0xcd, 0x8a, 0x70, 0x56, 0x72, 0xf9, 0xbf, 0x4f, 0x73, 0xe9, 0xf7, 0x57, 0x16, 0xac, 0x50, 0xc0,
  1031. 0x9d, 0xb7, 0x47, 0x71, 0x60, 0xc4, 0x74, 0x43, 0x6c, 0x1f, 0x93, 0x77, 0xdc, 0xce, 0x20, 0x8c,
  1032. 0x99, 0x5f, 0x44, 0x01, 0xf5, 0x1e, 0x87, 0x5e, 0x61, 0x2c, 0x4b, 0x1d, 0x81, 0x15, 0xf4, 0x23,
  1033. 0xd6, 0xea, 0xe1, 0x67, 0xf1, 0x7f, 0xfe, 0xda, 0x3c, 0x07, 0x53, 0x6a, 0x84, 0x9c, 0xcb, 0x02,
  1034. 0x83, 0x33, 0xdd, 0x35, 0xe2, 0x59, 0x5a, 0x98, 0xa5, 0x92, 0x64, 0x04, 0x06, 0x10, 0x4d, 0x1c,
  1035. 0x97, 0x08, 0x31, 0xee, 0xab, 0x05, 0xaf, 0x79, 0xa0, 0x18, 0x46, 0x6d, 0xfc, 0x89, 0xd4, 0xc7,
  1036. 0xff, 0xf0, 0xcf, 0x42, 0x91, 0xf8, 0x68, 0x0a, 0x65, 0x8e, 0xb6, 0xfd, 0xc3, 0xef, 0x78, 0x4c,
  1037. 0xcc, 0x9e, 0x30, 0x2e, 0xbc, 0x0b, 0x54, 0x1a, 0xa6, 0xbb, 0x26, 0x80, 0x48, 0x94, 0x32, 0x7d,
  1038. 0xa7, 0x3f, 0xae, 0x22, 0x3d, 0x66, 0xaa, 0xf6, 0x00, 0x5d, 0xbd, 0x4a, 0xe0, 0x3b, 0xb4, 0x17,
  1039. 0x8b, 0x9f, 0x76, 0xb0, 0x24, 0x9a, 0x25, 0x63, 0xdb, 0xeb, 0x7a, 0x3e, 0x5c, 0xb3, 0xb1, 0x29,
  1040. 0xf2, 0xca, 0x58, 0x6e, 0xd8, 0xa8, 0x2f, 0x75, 0xdf, 0x14, 0xfb, 0x13, 0x49, 0x88, 0xb2, 0xec,
  1041. 0xe4, 0x34, 0x2d, 0x96, 0xc6, 0x3a, 0xed, 0x95, 0x0e, 0xe5, 0x85, 0x6b, 0x40, 0x21, 0x9b, 0x09,
  1042. 0x19, 0x2b, 0x52, 0xde, 0x45, 0xa3, 0xfa, 0x51, 0xc2, 0xb5, 0xd1, 0x90, 0xb9, 0xf3, 0x37, 0xc1,
  1043. 0x0d, 0xba, 0x41, 0x11, 0x38, 0x7b, 0xbe, 0xd0, 0xd5, 0x69, 0x36, 0xc8, 0x62, 0x1b, 0x82, 0x8f
  1044. };
  1045. private static readonly byte[] T1 = new byte[]{
  1046. 0x83, 0xf2, 0x2a, 0xeb, 0xe9, 0xbf, 0x7b, 0x9c, 0x34, 0x96, 0x8d, 0x98, 0xb9, 0x69, 0x8c, 0x29,
  1047. 0x3d, 0x88, 0x68, 0x06, 0x39, 0x11, 0x4c, 0x0e, 0xa0, 0x56, 0x40, 0x92, 0x15, 0xbc, 0xb3, 0xdc,
  1048. 0x6f, 0xf8, 0x26, 0xba, 0xbe, 0xbd, 0x31, 0xfb, 0xc3, 0xfe, 0x80, 0x61, 0xe1, 0x7a, 0x32, 0xd2,
  1049. 0x70, 0x20, 0xa1, 0x45, 0xec, 0xd9, 0x1a, 0x5d, 0xb4, 0xd8, 0x09, 0xa5, 0x55, 0x8e, 0x37, 0x76,
  1050. 0xa9, 0x67, 0x10, 0x17, 0x36, 0x65, 0xb1, 0x95, 0x62, 0x59, 0x74, 0xa3, 0x50, 0x2f, 0x4b, 0xc8,
  1051. 0xd0, 0x8f, 0xcd, 0xd4, 0x3c, 0x86, 0x12, 0x1d, 0x23, 0xef, 0xf4, 0x53, 0x19, 0x35, 0xe6, 0x7f,
  1052. 0x5e, 0xd6, 0x79, 0x51, 0x22, 0x14, 0xf7, 0x1e, 0x4a, 0x42, 0x9b, 0x41, 0x73, 0x2d, 0xc1, 0x5c,
  1053. 0xa6, 0xa2, 0xe0, 0x2e, 0xd3, 0x28, 0xbb, 0xc9, 0xae, 0x6a, 0xd1, 0x5a, 0x30, 0x90, 0x84, 0xf9,
  1054. 0xb2, 0x58, 0xcf, 0x7e, 0xc5, 0xcb, 0x97, 0xe4, 0x16, 0x6c, 0xfa, 0xb0, 0x6d, 0x1f, 0x52, 0x99,
  1055. 0x0d, 0x4e, 0x03, 0x91, 0xc2, 0x4d, 0x64, 0x77, 0x9f, 0xdd, 0xc4, 0x49, 0x8a, 0x9a, 0x24, 0x38,
  1056. 0xa7, 0x57, 0x85, 0xc7, 0x7c, 0x7d, 0xe7, 0xf6, 0xb7, 0xac, 0x27, 0x46, 0xde, 0xdf, 0x3b, 0xd7,
  1057. 0x9e, 0x2b, 0x0b, 0xd5, 0x13, 0x75, 0xf0, 0x72, 0xb6, 0x9d, 0x1b, 0x01, 0x3f, 0x44, 0xe5, 0x87,
  1058. 0xfd, 0x07, 0xf1, 0xab, 0x94, 0x18, 0xea, 0xfc, 0x3a, 0x82, 0x5f, 0x05, 0x54, 0xdb, 0x00, 0x8b,
  1059. 0xe3, 0x48, 0x0c, 0xca, 0x78, 0x89, 0x0a, 0xff, 0x3e, 0x5b, 0x81, 0xee, 0x71, 0xe2, 0xda, 0x2c,
  1060. 0xb8, 0xb5, 0xcc, 0x6e, 0xa8, 0x6b, 0xad, 0x60, 0xc6, 0x08, 0x04, 0x02, 0xe8, 0xf5, 0x4f, 0xa4,
  1061. 0xf3, 0xc0, 0xce, 0x43, 0x25, 0x1c, 0x21, 0x33, 0x0f, 0xaf, 0x47, 0xed, 0x66, 0x63, 0x93, 0xaa
  1062. };
  1063. private static readonly byte[] T2 = new byte[]{
  1064. 0x45, 0xd4, 0x0b, 0x43, 0xf1, 0x72, 0xed, 0xa4, 0xc2, 0x38, 0xe6, 0x71, 0xfd, 0xb6, 0x3a, 0x95,
  1065. 0x50, 0x44, 0x4b, 0xe2, 0x74, 0x6b, 0x1e, 0x11, 0x5a, 0xc6, 0xb4, 0xd8, 0xa5, 0x8a, 0x70, 0xa3,
  1066. 0xa8, 0xfa, 0x05, 0xd9, 0x97, 0x40, 0xc9, 0x90, 0x98, 0x8f, 0xdc, 0x12, 0x31, 0x2c, 0x47, 0x6a,
  1067. 0x99, 0xae, 0xc8, 0x7f, 0xf9, 0x4f, 0x5d, 0x96, 0x6f, 0xf4, 0xb3, 0x39, 0x21, 0xda, 0x9c, 0x85,
  1068. 0x9e, 0x3b, 0xf0, 0xbf, 0xef, 0x06, 0xee, 0xe5, 0x5f, 0x20, 0x10, 0xcc, 0x3c, 0x54, 0x4a, 0x52,
  1069. 0x94, 0x0e, 0xc0, 0x28, 0xf6, 0x56, 0x60, 0xa2, 0xe3, 0x0f, 0xec, 0x9d, 0x24, 0x83, 0x7e, 0xd5,
  1070. 0x7c, 0xeb, 0x18, 0xd7, 0xcd, 0xdd, 0x78, 0xff, 0xdb, 0xa1, 0x09, 0xd0, 0x76, 0x84, 0x75, 0xbb,
  1071. 0x1d, 0x1a, 0x2f, 0xb0, 0xfe, 0xd6, 0x34, 0x63, 0x35, 0xd2, 0x2a, 0x59, 0x6d, 0x4d, 0x77, 0xe7,
  1072. 0x8e, 0x61, 0xcf, 0x9f, 0xce, 0x27, 0xf5, 0x80, 0x86, 0xc7, 0xa6, 0xfb, 0xf8, 0x87, 0xab, 0x62,
  1073. 0x3f, 0xdf, 0x48, 0x00, 0x14, 0x9a, 0xbd, 0x5b, 0x04, 0x92, 0x02, 0x25, 0x65, 0x4c, 0x53, 0x0c,
  1074. 0xf2, 0x29, 0xaf, 0x17, 0x6c, 0x41, 0x30, 0xe9, 0x93, 0x55, 0xf7, 0xac, 0x68, 0x26, 0xc4, 0x7d,
  1075. 0xca, 0x7a, 0x3e, 0xa0, 0x37, 0x03, 0xc1, 0x36, 0x69, 0x66, 0x08, 0x16, 0xa7, 0xbc, 0xc5, 0xd3,
  1076. 0x22, 0xb7, 0x13, 0x46, 0x32, 0xe8, 0x57, 0x88, 0x2b, 0x81, 0xb2, 0x4e, 0x64, 0x1c, 0xaa, 0x91,
  1077. 0x58, 0x2e, 0x9b, 0x5c, 0x1b, 0x51, 0x73, 0x42, 0x23, 0x01, 0x6e, 0xf3, 0x0d, 0xbe, 0x3d, 0x0a,
  1078. 0x2d, 0x1f, 0x67, 0x33, 0x19, 0x7b, 0x5e, 0xea, 0xde, 0x8b, 0xcb, 0xa9, 0x8c, 0x8d, 0xad, 0x49,
  1079. 0x82, 0xe4, 0xba, 0xc3, 0x15, 0xd1, 0xe0, 0x89, 0xfc, 0xb1, 0xb9, 0xb5, 0x07, 0x79, 0xb8, 0xe1
  1080. };
  1081. private static readonly byte[] T3 = new byte[]{
  1082. 0xb2, 0xb6, 0x23, 0x11, 0xa7, 0x88, 0xc5, 0xa6, 0x39, 0x8f, 0xc4, 0xe8, 0x73, 0x22, 0x43, 0xc3,
  1083. 0x82, 0x27, 0xcd, 0x18, 0x51, 0x62, 0x2d, 0xf7, 0x5c, 0x0e, 0x3b, 0xfd, 0xca, 0x9b, 0x0d, 0x0f,
  1084. 0x79, 0x8c, 0x10, 0x4c, 0x74, 0x1c, 0x0a, 0x8e, 0x7c, 0x94, 0x07, 0xc7, 0x5e, 0x14, 0xa1, 0x21,
  1085. 0x57, 0x50, 0x4e, 0xa9, 0x80, 0xd9, 0xef, 0x64, 0x41, 0xcf, 0x3c, 0xee, 0x2e, 0x13, 0x29, 0xba,
  1086. 0x34, 0x5a, 0xae, 0x8a, 0x61, 0x33, 0x12, 0xb9, 0x55, 0xa8, 0x15, 0x05, 0xf6, 0x03, 0x06, 0x49,
  1087. 0xb5, 0x25, 0x09, 0x16, 0x0c, 0x2a, 0x38, 0xfc, 0x20, 0xf4, 0xe5, 0x7f, 0xd7, 0x31, 0x2b, 0x66,
  1088. 0x6f, 0xff, 0x72, 0x86, 0xf0, 0xa3, 0x2f, 0x78, 0x00, 0xbc, 0xcc, 0xe2, 0xb0, 0xf1, 0x42, 0xb4,
  1089. 0x30, 0x5f, 0x60, 0x04, 0xec, 0xa5, 0xe3, 0x8b, 0xe7, 0x1d, 0xbf, 0x84, 0x7b, 0xe6, 0x81, 0xf8,
  1090. 0xde, 0xd8, 0xd2, 0x17, 0xce, 0x4b, 0x47, 0xd6, 0x69, 0x6c, 0x19, 0x99, 0x9a, 0x01, 0xb3, 0x85,
  1091. 0xb1, 0xf9, 0x59, 0xc2, 0x37, 0xe9, 0xc8, 0xa0, 0xed, 0x4f, 0x89, 0x68, 0x6d, 0xd5, 0x26, 0x91,
  1092. 0x87, 0x58, 0xbd, 0xc9, 0x98, 0xdc, 0x75, 0xc0, 0x76, 0xf5, 0x67, 0x6b, 0x7e, 0xeb, 0x52, 0xcb,
  1093. 0xd1, 0x5b, 0x9f, 0x0b, 0xdb, 0x40, 0x92, 0x1a, 0xfa, 0xac, 0xe4, 0xe1, 0x71, 0x1f, 0x65, 0x8d,
  1094. 0x97, 0x9e, 0x95, 0x90, 0x5d, 0xb7, 0xc1, 0xaf, 0x54, 0xfb, 0x02, 0xe0, 0x35, 0xbb, 0x3a, 0x4d,
  1095. 0xad, 0x2c, 0x3d, 0x56, 0x08, 0x1b, 0x4a, 0x93, 0x6a, 0xab, 0xb8, 0x7a, 0xf2, 0x7d, 0xda, 0x3f,
  1096. 0xfe, 0x3e, 0xbe, 0xea, 0xaa, 0x44, 0xc6, 0xd0, 0x36, 0x48, 0x70, 0x96, 0x77, 0x24, 0x53, 0xdf,
  1097. 0xf3, 0x83, 0x28, 0x32, 0x45, 0x1e, 0xa4, 0xd3, 0xa2, 0x46, 0x6e, 0x9c, 0xdd, 0x63, 0xd4, 0x9d
  1098. };
  1099. #endregion
  1100. public virtual string AlgorithmName
  1101. {
  1102. get { return "DSTU7624"; }
  1103. }
  1104. public virtual int GetBlockSize()
  1105. {
  1106. return wordsInBlock << 3;
  1107. }
  1108. }
  1109. }
  1110. #pragma warning restore
  1111. #endif