GCMBlockCipher.cs 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.PlatformSupport.Memory;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Macs;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  10. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
  11. {
  12. /// <summary>
  13. /// Implements the Galois/Counter mode (GCM) detailed in
  14. /// NIST Special Publication 800-38D.
  15. /// </summary>
  16. [BestHTTP.PlatformSupport.IL2CPP.Il2CppSetOption(BestHTTP.PlatformSupport.IL2CPP.Option.NullChecks, false)]
  17. [BestHTTP.PlatformSupport.IL2CPP.Il2CppSetOption(BestHTTP.PlatformSupport.IL2CPP.Option.ArrayBoundsChecks, false)]
  18. [BestHTTP.PlatformSupport.IL2CPP.Il2CppSetOption(BestHTTP.PlatformSupport.IL2CPP.Option.DivideByZeroChecks, false)]
  19. [BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
  20. public sealed class GcmBlockCipher
  21. : IAeadBlockCipher
  22. {
  23. private const int BlockSize = 16;
  24. byte[] ctrBlock = new byte[BlockSize];
  25. private readonly IBlockCipher cipher;
  26. private IGcmExponentiator exp;
  27. // These fields are set by Init and not modified by processing
  28. private bool forEncryption;
  29. private bool initialised;
  30. private int macSize;
  31. private byte[] lastKey;
  32. private byte[] nonce;
  33. private byte[] initialAssociatedText;
  34. private byte[] H;
  35. private byte[] J0;
  36. // These fields are modified during processing
  37. private int bufLength;
  38. private byte[] bufBlock;
  39. private byte[] macBlock;
  40. private byte[] S, S_at, S_atPre;
  41. private byte[] counter;
  42. private uint blocksRemaining;
  43. private int bufOff;
  44. private ulong totalLength;
  45. private byte[] atBlock;
  46. private int atBlockPos;
  47. private ulong atLength;
  48. private ulong atLengthPre;
  49. public GcmBlockCipher(
  50. IBlockCipher c)
  51. : this(c, null)
  52. {
  53. }
  54. public GcmBlockCipher(
  55. IBlockCipher c,
  56. IGcmMultiplier m)
  57. {
  58. if (c.GetBlockSize() != BlockSize)
  59. throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
  60. if (m != null)
  61. throw new NotImplementedException("IGcmMultiplier");
  62. this.cipher = c;
  63. }
  64. public /*virtual*/ string AlgorithmName
  65. {
  66. get { return cipher.AlgorithmName + "/GCM"; }
  67. }
  68. public IBlockCipher GetUnderlyingCipher()
  69. {
  70. return cipher;
  71. }
  72. public /*virtual*/ int GetBlockSize()
  73. {
  74. return BlockSize;
  75. }
  76. /// <remarks>
  77. /// MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits.
  78. /// Sizes less than 96 are not recommended, but are supported for specialized applications.
  79. /// </remarks>
  80. public /*virtual*/ void Init(
  81. bool forEncryption,
  82. ICipherParameters parameters)
  83. {
  84. this.forEncryption = forEncryption;
  85. //this.macBlock = null;
  86. if (this.macBlock != null)
  87. Array.Clear(this.macBlock, 0, this.macBlock.Length);
  88. this.initialised = true;
  89. KeyParameter keyParam;
  90. byte[] newNonce = null;
  91. if (parameters is AeadParameters)
  92. {
  93. AeadParameters param = (AeadParameters)parameters;
  94. newNonce = param.GetNonce();
  95. initialAssociatedText = param.GetAssociatedText();
  96. int macSizeBits = param.MacSize;
  97. if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
  98. {
  99. throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
  100. }
  101. macSize = macSizeBits / 8;
  102. keyParam = param.Key;
  103. }
  104. else if (parameters is ParametersWithIV)
  105. {
  106. ParametersWithIV param = (ParametersWithIV)parameters;
  107. newNonce = param.GetIV();
  108. initialAssociatedText = null;
  109. macSize = 16;
  110. keyParam = (KeyParameter)param.Parameters;
  111. }
  112. else
  113. {
  114. throw new ArgumentException("invalid parameters passed to GCM");
  115. }
  116. this.bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
  117. if (this.bufBlock == null || this.bufLength < this.bufBlock.Length)
  118. BufferPool.Resize(ref this.bufBlock, this.bufLength, true, true);
  119. if (newNonce == null || newNonce.Length < 1)
  120. {
  121. throw new ArgumentException("IV must be at least 1 byte");
  122. }
  123. if (forEncryption)
  124. {
  125. if (nonce != null && Arrays.AreEqual(nonce, newNonce))
  126. {
  127. if (keyParam == null)
  128. {
  129. throw new ArgumentException("cannot reuse nonce for GCM encryption");
  130. }
  131. if (lastKey != null && Arrays.AreEqual(lastKey, keyParam.GetKey()))
  132. {
  133. throw new ArgumentException("cannot reuse nonce for GCM encryption");
  134. }
  135. }
  136. }
  137. nonce = newNonce;
  138. if (keyParam != null)
  139. {
  140. lastKey = keyParam.GetKey();
  141. }
  142. // TODO Restrict macSize to 16 if nonce length not 12?
  143. // Cipher always used in forward mode
  144. // if keyParam is null we're reusing the last key.
  145. if (keyParam != null)
  146. {
  147. cipher.Init(true, keyParam);
  148. if (this.H == null)
  149. this.H = new byte[BlockSize];
  150. else
  151. Array.Clear(this.H, 0, BlockSize);
  152. cipher.ProcessBlock(H, 0, H, 0);
  153. // if keyParam is null we're reusing the last key and the multiplier doesn't need re-init
  154. Tables8kGcmMultiplier_Init(H);
  155. exp = null;
  156. }
  157. else if (this.H == null)
  158. {
  159. throw new ArgumentException("Key must be specified in initial init");
  160. }
  161. if (this.J0 == null)
  162. this.J0 = new byte[BlockSize];
  163. else
  164. Array.Clear(this.J0, 0, BlockSize);
  165. if (nonce.Length == 12)
  166. {
  167. Array.Copy(nonce, 0, J0, 0, nonce.Length);
  168. this.J0[BlockSize - 1] = 0x01;
  169. }
  170. else
  171. {
  172. gHASH(J0, nonce, nonce.Length);
  173. byte[] X = BufferPool.Get(BlockSize, false);
  174. Pack.UInt64_To_BE((ulong)nonce.Length * 8UL, X, 8);
  175. gHASHBlock(J0, X);
  176. BufferPool.Release(X);
  177. }
  178. //BufferPool.Resize(ref this.S, BlockSize, false, true);
  179. //BufferPool.Resize(ref this.S_at, BlockSize, false, true);
  180. //BufferPool.Resize(ref this.S_atPre, BlockSize, false, true);
  181. //BufferPool.Resize(ref this.atBlock, BlockSize, false, true);
  182. if (this.S == null)
  183. this.S = new byte[BlockSize];
  184. else
  185. Array.Clear(this.S, 0, this.S.Length);
  186. if (this.S_at == null)
  187. this.S_at = new byte[BlockSize];
  188. else
  189. Array.Clear(this.S_at, 0, this.S_at.Length);
  190. if (this.S_atPre == null)
  191. this.S_atPre = new byte[BlockSize];
  192. else
  193. Array.Clear(this.S_atPre, 0, this.S_atPre.Length);
  194. if (this.atBlock == null)
  195. this.atBlock = new byte[BlockSize];
  196. else
  197. Array.Clear(this.atBlock, 0, this.atBlock.Length);
  198. this.atBlockPos = 0;
  199. this.atLength = 0;
  200. this.atLengthPre = 0;
  201. //this.counter = Arrays.Clone(J0);
  202. //BufferPool.Resize(ref this.counter, BlockSize, false, true);
  203. if (this.counter == null)
  204. this.counter = new byte[BlockSize];
  205. else
  206. Array.Clear(this.counter, 0, this.counter.Length);
  207. Array.Copy(this.J0, 0, this.counter, 0, BlockSize);
  208. this.blocksRemaining = uint.MaxValue - 1; // page 8, len(P) <= 2^39 - 256, 1 block used by tag
  209. this.bufOff = 0;
  210. this.totalLength = 0;
  211. if (initialAssociatedText != null)
  212. {
  213. ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
  214. }
  215. }
  216. public /*virtual*/ byte[] GetMac()
  217. {
  218. return macBlock == null
  219. ? new byte[macSize]
  220. : Arrays.Clone(macBlock);
  221. }
  222. public /*virtual*/ int GetOutputSize(
  223. int len)
  224. {
  225. int totalData = len + bufOff;
  226. if (forEncryption)
  227. {
  228. return totalData + macSize;
  229. }
  230. return totalData < macSize ? 0 : totalData - macSize;
  231. }
  232. public /*virtual*/ int GetUpdateOutputSize(
  233. int len)
  234. {
  235. int totalData = len + bufOff;
  236. if (!forEncryption)
  237. {
  238. if (totalData < macSize)
  239. {
  240. return 0;
  241. }
  242. totalData -= macSize;
  243. }
  244. return totalData - totalData % BlockSize;
  245. }
  246. public /*virtual*/ void ProcessAadByte(byte input)
  247. {
  248. CheckStatus();
  249. atBlock[atBlockPos] = input;
  250. if (++atBlockPos == BlockSize)
  251. {
  252. // Hash each block as it fills
  253. gHASHBlock(S_at, atBlock);
  254. atBlockPos = 0;
  255. atLength += BlockSize;
  256. }
  257. }
  258. public /*virtual*/ void ProcessAadBytes(byte[] inBytes, int inOff, int len)
  259. {
  260. CheckStatus();
  261. for (int i = 0; i < len; ++i)
  262. {
  263. atBlock[atBlockPos] = inBytes[inOff + i];
  264. if (++atBlockPos == BlockSize)
  265. {
  266. // Hash each block as it fills
  267. gHASHBlock(S_at, atBlock);
  268. atBlockPos = 0;
  269. atLength += BlockSize;
  270. }
  271. }
  272. }
  273. private void InitCipher()
  274. {
  275. if (atLength > 0)
  276. {
  277. Array.Copy(S_at, 0, S_atPre, 0, BlockSize);
  278. atLengthPre = atLength;
  279. }
  280. // Finish hash for partial AAD block
  281. if (atBlockPos > 0)
  282. {
  283. gHASHPartial(S_atPre, atBlock, 0, atBlockPos);
  284. atLengthPre += (uint)atBlockPos;
  285. }
  286. if (atLengthPre > 0)
  287. {
  288. Array.Copy(S_atPre, 0, S, 0, BlockSize);
  289. }
  290. }
  291. public /*virtual*/ int ProcessByte(
  292. byte input,
  293. byte[] output,
  294. int outOff)
  295. {
  296. CheckStatus();
  297. bufBlock[bufOff] = input;
  298. if (++bufOff == bufLength)
  299. {
  300. ProcessBlock(bufBlock, 0, output, outOff);
  301. if (forEncryption)
  302. {
  303. bufOff = 0;
  304. }
  305. else
  306. {
  307. Array.Copy(bufBlock, BlockSize, bufBlock, 0, macSize);
  308. bufOff = macSize;
  309. }
  310. return BlockSize;
  311. }
  312. return 0;
  313. }
  314. public unsafe /*virtual*/ int ProcessBytes(
  315. byte[] input,
  316. int inOff,
  317. int len,
  318. byte[] output,
  319. int outOff)
  320. {
  321. CheckStatus();
  322. Check.DataLength(input, inOff, len, "input buffer too short");
  323. int resultLen = 0;
  324. if (forEncryption)
  325. {
  326. if (bufOff != 0)
  327. {
  328. while (len > 0)
  329. {
  330. --len;
  331. bufBlock[bufOff] = input[inOff++];
  332. if (++bufOff == BlockSize)
  333. {
  334. ProcessBlock(bufBlock, 0, output, outOff);
  335. bufOff = 0;
  336. resultLen += BlockSize;
  337. break;
  338. }
  339. }
  340. }
  341. fixed (byte* pctrBlock = ctrBlock, pbuf = input, pS = S, poutput = output)
  342. {
  343. while (len >= BlockSize)
  344. {
  345. // ProcessBlock(byte[] buf, int bufOff, byte[] output, int outOff)
  346. #region ProcessBlock(buf: input, bufOff: inOff, output: output, outOff: outOff + resultLen);
  347. if (totalLength == 0)
  348. InitCipher();
  349. #region GetNextCtrBlock(ctrBlock);
  350. blocksRemaining--;
  351. uint c = 1;
  352. c += counter[15]; counter[15] = (byte)c; c >>= 8;
  353. c += counter[14]; counter[14] = (byte)c; c >>= 8;
  354. c += counter[13]; counter[13] = (byte)c; c >>= 8;
  355. c += counter[12]; counter[12] = (byte)c;
  356. cipher.ProcessBlock(counter, 0, ctrBlock, 0);
  357. #endregion
  358. ulong* pulongBuf = (ulong*)&pbuf[inOff];
  359. ulong* pulongctrBlock = (ulong*)pctrBlock;
  360. pulongctrBlock[0] ^= pulongBuf[0];
  361. pulongctrBlock[1] ^= pulongBuf[1];
  362. ulong* pulongS = (ulong*)pS;
  363. pulongS[0] ^= pulongctrBlock[0];
  364. pulongS[1] ^= pulongctrBlock[1];
  365. Tables8kGcmMultiplier_MultiplyH(S);
  366. ulong* pulongoutput = (ulong*)&poutput[outOff + resultLen];
  367. pulongoutput[0] = pulongctrBlock[0];
  368. pulongoutput[1] = pulongctrBlock[1];
  369. totalLength += BlockSize;
  370. #endregion
  371. inOff += BlockSize;
  372. len -= BlockSize;
  373. resultLen += BlockSize;
  374. }
  375. }
  376. if (len > 0)
  377. {
  378. Array.Copy(input, inOff, bufBlock, 0, len);
  379. bufOff = len;
  380. }
  381. }
  382. else
  383. {
  384. fixed (byte* pinput = input, pbufBlock = bufBlock, pctrBlock = ctrBlock, pS = S, poutput = output)
  385. {
  386. ulong* pulongbufBlock = (ulong*)pbufBlock;
  387. // adjust bufOff to be on a 8 byte boundary
  388. int adjustCount = 0;
  389. for (int i = 0; i < len && (bufOff % 8) != 0; ++i)
  390. {
  391. pbufBlock[bufOff++] = pinput[inOff++ + i];
  392. adjustCount++;
  393. if (bufOff == bufLength)
  394. {
  395. ProcessBlock(bufBlock, 0, output, outOff + resultLen);
  396. pulongbufBlock[0] = pulongbufBlock[2];
  397. pulongbufBlock[1] = pulongbufBlock[3];
  398. bufOff = macSize;
  399. resultLen += BlockSize;
  400. }
  401. }
  402. int longLen = (len - adjustCount) / 8;
  403. if (longLen > 0)
  404. {
  405. ulong* pulonginput = (ulong*)&pinput[inOff];
  406. int bufLongOff = bufOff / 8;
  407. // copy 8 bytes per cycle instead of just 1
  408. for (int i = 0; i < longLen; ++i)
  409. {
  410. pulongbufBlock[bufLongOff++] = pulonginput[i];
  411. bufOff += 8;
  412. if (bufOff == bufLength)
  413. {
  414. #region ProcessBlock(buf: bufBlock, bufOff: 0, output: output, outOff: outOff + resultLen);
  415. if (totalLength == 0)
  416. InitCipher();
  417. #region GetNextCtrBlock(ctrBlock);
  418. blocksRemaining--;
  419. uint c = 1;
  420. c += counter[15]; counter[15] = (byte)c; c >>= 8;
  421. c += counter[14]; counter[14] = (byte)c; c >>= 8;
  422. c += counter[13]; counter[13] = (byte)c; c >>= 8;
  423. c += counter[12]; counter[12] = (byte)c;
  424. cipher.ProcessBlock(counter, 0, ctrBlock, 0);
  425. #endregion
  426. ulong* pulongS = (ulong*)pS;
  427. pulongS[0] ^= pulongbufBlock[0];
  428. pulongS[1] ^= pulongbufBlock[1];
  429. Tables8kGcmMultiplier_MultiplyH(S);
  430. ulong* pulongOutput = (ulong*)&poutput[outOff + resultLen];
  431. ulong* pulongctrBlock = (ulong*)pctrBlock;
  432. pulongOutput[0] = pulongctrBlock[0] ^ pulongbufBlock[0];
  433. pulongOutput[1] = pulongctrBlock[1] ^ pulongbufBlock[1];
  434. totalLength += BlockSize;
  435. #endregion
  436. pulongbufBlock[0] = pulongbufBlock[2];
  437. pulongbufBlock[1] = pulongbufBlock[3];
  438. bufOff = macSize;
  439. resultLen += BlockSize;
  440. bufLongOff = bufOff / 8;
  441. }
  442. }
  443. }
  444. for (int i = longLen * 8; i < len; i++)
  445. {
  446. pbufBlock[bufOff++] = pinput[inOff + i];
  447. if (bufOff == bufLength)
  448. {
  449. ProcessBlock(bufBlock, 0, output, outOff + resultLen);
  450. pulongbufBlock[0] = pulongbufBlock[2];
  451. pulongbufBlock[1] = pulongbufBlock[3];
  452. bufOff = macSize;
  453. resultLen += BlockSize;
  454. }
  455. }
  456. }
  457. }
  458. return resultLen;
  459. }
  460. private unsafe void ProcessBlock(byte[] buf, int bufOff, byte[] output, int outOff)
  461. {
  462. if (totalLength == 0)
  463. InitCipher();
  464. GetNextCtrBlock(ctrBlock);
  465. if (forEncryption)
  466. {
  467. fixed (byte* pctrBlock = ctrBlock, pbuf = buf, pS = S)
  468. {
  469. ulong* pulongBuf = (ulong*)&pbuf[bufOff];
  470. ulong* pulongctrBlock = (ulong*)pctrBlock;
  471. pulongctrBlock[0] ^= pulongBuf[0];
  472. pulongctrBlock[1] ^= pulongBuf[1];
  473. ulong* pulongS = (ulong*)pS;
  474. pulongS[0] ^= pulongctrBlock[0];
  475. pulongS[1] ^= pulongctrBlock[1];
  476. Tables8kGcmMultiplier_MultiplyH(S);
  477. fixed (byte* poutput = output)
  478. {
  479. ulong* pulongoutput = (ulong*)&poutput[outOff];
  480. pulongoutput[0] = pulongctrBlock[0];
  481. pulongoutput[1] = pulongctrBlock[1];
  482. }
  483. }
  484. }
  485. else
  486. {
  487. // moved this part to ProcessBytes's main part
  488. fixed (byte* pctrBlock = ctrBlock, pbuf = buf, pS = S, poutput = output)
  489. {
  490. ulong* pulongS = (ulong*)pS;
  491. ulong* pulongBuf = (ulong*)&pbuf[bufOff];
  492. pulongS[0] ^= pulongBuf[0];
  493. pulongS[1] ^= pulongBuf[1];
  494. Tables8kGcmMultiplier_MultiplyH(S);
  495. ulong* pulongOutput = (ulong*)&poutput[outOff];
  496. ulong* pulongctrBlock = (ulong*)pctrBlock;
  497. pulongOutput[0] = pulongctrBlock[0] ^ pulongBuf[0];
  498. pulongOutput[1] = pulongctrBlock[1] ^ pulongBuf[1];
  499. }
  500. }
  501. totalLength += BlockSize;
  502. }
  503. public int DoFinal(byte[] output, int outOff)
  504. {
  505. CheckStatus();
  506. if (totalLength == 0)
  507. {
  508. InitCipher();
  509. }
  510. int extra = bufOff;
  511. if (forEncryption)
  512. {
  513. Check.OutputLength(output, outOff, extra + macSize, "Output buffer too short");
  514. }
  515. else
  516. {
  517. if (extra < macSize)
  518. throw new InvalidCipherTextException("data too short");
  519. extra -= macSize;
  520. Check.OutputLength(output, outOff, extra, "Output buffer too short");
  521. }
  522. if (extra > 0)
  523. {
  524. ProcessPartial(bufBlock, 0, extra, output, outOff);
  525. }
  526. atLength += (uint)atBlockPos;
  527. if (atLength > atLengthPre)
  528. {
  529. /*
  530. * Some AAD was sent after the cipher started. We determine the difference b/w the hash value
  531. * we actually used when the cipher started (S_atPre) and the final hash value calculated (S_at).
  532. * Then we carry this difference forward by multiplying by H^c, where c is the number of (full or
  533. * partial) cipher-text blocks produced, and adjust the current hash.
  534. */
  535. // Finish hash for partial AAD block
  536. if (atBlockPos > 0)
  537. {
  538. gHASHPartial(S_at, atBlock, 0, atBlockPos);
  539. }
  540. // Find the difference between the AAD hashes
  541. if (atLengthPre > 0)
  542. {
  543. GcmUtilities.Xor(S_at, S_atPre);
  544. }
  545. // Number of cipher-text blocks produced
  546. long c = (long)(((totalLength * 8) + 127) >> 7);
  547. // Calculate the adjustment factor
  548. byte[] H_c = BufferPool.Get(16, true);
  549. if (exp == null)
  550. {
  551. exp = new Tables1kGcmExponentiator();
  552. exp.Init(H);
  553. }
  554. exp.ExponentiateX(c, H_c);
  555. // Carry the difference forward
  556. GcmUtilities.Multiply(S_at, H_c);
  557. // Adjust the current hash
  558. GcmUtilities.Xor(S, S_at);
  559. BufferPool.Release(H_c);
  560. }
  561. // Final gHASH
  562. byte[] X = BufferPool.Get(BlockSize, false);
  563. Pack.UInt64_To_BE(atLength * 8UL, X, 0);
  564. Pack.UInt64_To_BE(totalLength * 8UL, X, 8);
  565. gHASHBlock(S, X);
  566. BufferPool.Release(X);
  567. // T = MSBt(GCTRk(J0,S))
  568. byte[] tag = BufferPool.Get(BlockSize, false);
  569. cipher.ProcessBlock(J0, 0, tag, 0);
  570. GcmUtilities.Xor(tag, S);
  571. int resultLen = extra;
  572. // We place into macBlock our calculated value for T
  573. if (this.macBlock == null || this.macBlock.Length < macSize)
  574. this.macBlock = BufferPool.Resize(ref this.macBlock, macSize, false, false);
  575. Array.Copy(tag, 0, macBlock, 0, macSize);
  576. BufferPool.Release(tag);
  577. if (forEncryption)
  578. {
  579. // Append T to the message
  580. Array.Copy(macBlock, 0, output, outOff + bufOff, macSize);
  581. resultLen += macSize;
  582. }
  583. else
  584. {
  585. // Retrieve the T value from the message and compare to calculated one
  586. byte[] msgMac = BufferPool.Get(macSize, false);
  587. Array.Copy(bufBlock, extra, msgMac, 0, macSize);
  588. if (!Arrays.ConstantTimeAreEqual(this.macBlock, msgMac))
  589. throw new InvalidCipherTextException("mac check in GCM failed");
  590. BufferPool.Release(msgMac);
  591. }
  592. Reset(false);
  593. return resultLen;
  594. }
  595. public /*virtual*/ void Reset()
  596. {
  597. Reset(true);
  598. }
  599. private unsafe void Reset(
  600. bool clearMac)
  601. {
  602. cipher.Reset();
  603. // note: we do not reset the nonce.
  604. //BufferPool.Resize(ref this.S, BlockSize, false, true);
  605. //BufferPool.Resize(ref this.S_at, BlockSize, false, true);
  606. //BufferPool.Resize(ref this.S_atPre, BlockSize, false, true);
  607. //BufferPool.Resize(ref this.atBlock, BlockSize, false, true);
  608. fixed (byte* pS = S, pS_at = S_at, pS_atPre = S_atPre, patBlock = atBlock)
  609. {
  610. for (int i = 0; i < BlockSize; ++i)
  611. {
  612. pS[i] = pS_at[i] = pS_atPre[i] = patBlock[i] = 0;
  613. }
  614. }
  615. atBlockPos = 0;
  616. atLength = 0;
  617. atLengthPre = 0;
  618. //BufferPool.Resize(ref this.counter, BlockSize, false, false);
  619. Array.Copy(this.J0, 0, this.counter, 0, BlockSize);
  620. blocksRemaining = uint.MaxValue - 1;
  621. bufOff = 0;
  622. totalLength = 0;
  623. if (bufBlock != null)
  624. {
  625. //Arrays.Fill(bufBlock, 0);
  626. }
  627. if (clearMac)
  628. {
  629. //macBlock = null;
  630. Array.Clear(this.macBlock, 0, this.macSize);
  631. }
  632. if (forEncryption)
  633. {
  634. initialised = false;
  635. }
  636. else
  637. {
  638. if (initialAssociatedText != null)
  639. {
  640. ProcessAadBytes(initialAssociatedText, 0, initialAssociatedText.Length);
  641. }
  642. }
  643. }
  644. private void ProcessPartial(byte[] buf, int off, int len, byte[] output, int outOff)
  645. {
  646. //byte[] ctrBlock = new byte[BlockSize];
  647. GetNextCtrBlock(ctrBlock);
  648. if (forEncryption)
  649. {
  650. GcmUtilities.Xor(buf, off, ctrBlock, 0, len);
  651. gHASHPartial(S, buf, off, len);
  652. }
  653. else
  654. {
  655. gHASHPartial(S, buf, off, len);
  656. GcmUtilities.Xor(buf, off, ctrBlock, 0, len);
  657. }
  658. Array.Copy(buf, off, output, outOff, len);
  659. totalLength += (uint)len;
  660. }
  661. private void gHASH(byte[] Y, byte[] b, int len)
  662. {
  663. for (int pos = 0; pos < len; pos += BlockSize)
  664. {
  665. int num = System.Math.Min(len - pos, BlockSize);
  666. gHASHPartial(Y, b, pos, num);
  667. }
  668. }
  669. private void gHASHBlock(byte[] Y, byte[] b)
  670. {
  671. GcmUtilities.Xor(Y, b);
  672. Tables8kGcmMultiplier_MultiplyH(Y);
  673. }
  674. private void gHASHBlock(byte[] Y, byte[] b, int off)
  675. {
  676. GcmUtilities.Xor(Y, b, off);
  677. Tables8kGcmMultiplier_MultiplyH(Y);
  678. }
  679. private void gHASHPartial(byte[] Y, byte[] b, int off, int len)
  680. {
  681. GcmUtilities.Xor(Y, b, off, len);
  682. Tables8kGcmMultiplier_MultiplyH(Y);
  683. }
  684. private void GetNextCtrBlock(byte[] block)
  685. {
  686. if (blocksRemaining == 0)
  687. throw new InvalidOperationException("Attempt to process too many blocks");
  688. blocksRemaining--;
  689. uint c = 1;
  690. c += counter[15]; counter[15] = (byte)c; c >>= 8;
  691. c += counter[14]; counter[14] = (byte)c; c >>= 8;
  692. c += counter[13]; counter[13] = (byte)c; c >>= 8;
  693. c += counter[12]; counter[12] = (byte)c;
  694. cipher.ProcessBlock(counter, 0, block, 0);
  695. }
  696. private void CheckStatus()
  697. {
  698. if (!initialised)
  699. {
  700. if (forEncryption)
  701. {
  702. throw new InvalidOperationException("GCM cipher cannot be reused for encryption");
  703. }
  704. throw new InvalidOperationException("GCM cipher needs to be initialised");
  705. }
  706. }
  707. #region Tables8kGcmMultiplier
  708. private byte[] Tables8kGcmMultiplier_H;
  709. private uint[][][] Tables8kGcmMultiplier_M;
  710. public void Tables8kGcmMultiplier_Init(byte[] H)
  711. {
  712. if (Tables8kGcmMultiplier_M == null)
  713. {
  714. Tables8kGcmMultiplier_M = new uint[32][][];
  715. }
  716. else if (Arrays.AreEqual(this.Tables8kGcmMultiplier_H, H))
  717. {
  718. return;
  719. }
  720. this.Tables8kGcmMultiplier_H = Arrays.Clone(H);
  721. Tables8kGcmMultiplier_M[0] = new uint[16][];
  722. Tables8kGcmMultiplier_M[1] = new uint[16][];
  723. Tables8kGcmMultiplier_M[0][0] = new uint[4];
  724. Tables8kGcmMultiplier_M[1][0] = new uint[4];
  725. Tables8kGcmMultiplier_M[1][8] = GcmUtilities.AsUints(H);
  726. for (int j = 4; j >= 1; j >>= 1)
  727. {
  728. uint[] tmp = (uint[])Tables8kGcmMultiplier_M[1][j + j].Clone();
  729. GcmUtilities.MultiplyP(tmp);
  730. Tables8kGcmMultiplier_M[1][j] = tmp;
  731. }
  732. {
  733. uint[] tmp = (uint[])Tables8kGcmMultiplier_M[1][1].Clone();
  734. GcmUtilities.MultiplyP(tmp);
  735. Tables8kGcmMultiplier_M[0][8] = tmp;
  736. }
  737. for (int j = 4; j >= 1; j >>= 1)
  738. {
  739. uint[] tmp = (uint[])Tables8kGcmMultiplier_M[0][j + j].Clone();
  740. GcmUtilities.MultiplyP(tmp);
  741. Tables8kGcmMultiplier_M[0][j] = tmp;
  742. }
  743. for (int i = 0; ;)
  744. {
  745. for (int j = 2; j < 16; j += j)
  746. {
  747. for (int k = 1; k < j; ++k)
  748. {
  749. uint[] tmp = (uint[])Tables8kGcmMultiplier_M[i][j].Clone();
  750. GcmUtilities.Xor(tmp, Tables8kGcmMultiplier_M[i][k]);
  751. Tables8kGcmMultiplier_M[i][j + k] = tmp;
  752. }
  753. }
  754. if (++i == 32) return;
  755. if (i > 1)
  756. {
  757. Tables8kGcmMultiplier_M[i] = new uint[16][];
  758. Tables8kGcmMultiplier_M[i][0] = new uint[4];
  759. for (int j = 8; j > 0; j >>= 1)
  760. {
  761. uint[] tmp = (uint[])Tables8kGcmMultiplier_M[i - 2][j].Clone();
  762. GcmUtilities.MultiplyP8(tmp);
  763. Tables8kGcmMultiplier_M[i][j] = tmp;
  764. }
  765. }
  766. }
  767. }
  768. uint[] Tables8kGcmMultiplier_z = new uint[4];
  769. public unsafe void Tables8kGcmMultiplier_MultiplyH(byte[] x)
  770. {
  771. fixed (byte* px = x)
  772. fixed (uint* pz = Tables8kGcmMultiplier_z)
  773. {
  774. ulong* pulongZ = (ulong*)pz;
  775. pulongZ[0] = 0;
  776. pulongZ[1] = 0;
  777. for (int i = 15; i >= 0; --i)
  778. {
  779. uint[] m = Tables8kGcmMultiplier_M[i + i][px[i] & 0x0f];
  780. fixed (uint* pm = m)
  781. {
  782. ulong* pulongm = (ulong*)pm;
  783. pulongZ[0] ^= pulongm[0];
  784. pulongZ[1] ^= pulongm[1];
  785. }
  786. m = Tables8kGcmMultiplier_M[i + i + 1][(px[i] & 0xf0) >> 4];
  787. fixed (uint* pm = m)
  788. {
  789. ulong* pulongm = (ulong*)pm;
  790. pulongZ[0] ^= pulongm[0];
  791. pulongZ[1] ^= pulongm[1];
  792. }
  793. }
  794. byte* pbyteZ = (byte*)pz;
  795. px[0] = pbyteZ[3];
  796. px[1] = pbyteZ[2];
  797. px[2] = pbyteZ[1];
  798. px[3] = pbyteZ[0];
  799. px[4] = pbyteZ[7];
  800. px[5] = pbyteZ[6];
  801. px[6] = pbyteZ[5];
  802. px[7] = pbyteZ[4];
  803. px[8] = pbyteZ[11];
  804. px[9] = pbyteZ[10];
  805. px[10] = pbyteZ[9];
  806. px[11] = pbyteZ[8];
  807. px[12] = pbyteZ[15];
  808. px[13] = pbyteZ[14];
  809. px[14] = pbyteZ[13];
  810. px[15] = pbyteZ[12];
  811. }
  812. }
  813. #endregion
  814. }
  815. }
  816. #pragma warning restore
  817. #endif