GcmSivBlockCipher.cs 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes.Gcm;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities.IO;
  10. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Modes
  11. {
  12. /**
  13. * GCM-SIV Mode.
  14. * <p>It should be noted that the specified limit of 2<sup>36</sup> bytes is not supported. This is because all bytes are
  15. * cached in a <b>ByteArrayOutputStream</b> object (which has a limit of a little less than 2<sup>31</sup> bytes),
  16. * and are output on the <b>DoFinal</b>() call (which can only process a maximum of 2<sup>31</sup> bytes).</p>
  17. * <p>The practical limit of 2<sup>31</sup> - 24 bytes is policed, and attempts to breach the limit will be rejected</p>
  18. * <p>In order to properly support the higher limit, an extended form of <b>ByteArrayOutputStream</b> would be needed
  19. * which would use multiple arrays to store the data. In addition, a new <b>doOutput</b> method would be required (similar
  20. * to that in <b>XOF</b> digests), which would allow the data to be output over multiple calls. Alternatively an extended
  21. * form of <b>ByteArrayInputStream</b> could be used to deliver the data.</p>
  22. */
  23. public class GcmSivBlockCipher
  24. : IAeadBlockCipher
  25. {
  26. /// <summary>The buffer length.</summary>
  27. private static readonly int BUFLEN = 16;
  28. /// <summary>The halfBuffer length.</summary>
  29. private static readonly int HALFBUFLEN = BUFLEN >> 1;
  30. /// <summary>The nonce length.</summary>
  31. private static readonly int NONCELEN = 12;
  32. /**
  33. * The maximum data length (AEAD/PlainText). Due to implementation constraints this is restricted to the maximum
  34. * array length (https://programming.guide/java/array-maximum-length.html) minus the BUFLEN to allow for the MAC
  35. */
  36. private static readonly int MAX_DATALEN = int.MaxValue - 8 - BUFLEN;
  37. /**
  38. * The top bit mask.
  39. */
  40. private static readonly byte MASK = 0x80;
  41. /**
  42. * The addition constant.
  43. */
  44. private static readonly byte ADD = 0xE1;
  45. /**
  46. * The initialisation flag.
  47. */
  48. private static readonly int INIT = 1;
  49. /**
  50. * The aeadComplete flag.
  51. */
  52. private static readonly int AEAD_COMPLETE = 2;
  53. /**
  54. * The cipher.
  55. */
  56. private readonly IBlockCipher theCipher;
  57. /**
  58. * The multiplier.
  59. */
  60. private readonly IGcmMultiplier theMultiplier;
  61. /**
  62. * The gHash buffer.
  63. */
  64. internal readonly byte[] theGHash = new byte[BUFLEN];
  65. /**
  66. * The reverse buffer.
  67. */
  68. internal readonly byte[] theReverse = new byte[BUFLEN];
  69. /**
  70. * The aeadHasher.
  71. */
  72. private readonly GcmSivHasher theAEADHasher;
  73. /**
  74. * The dataHasher.
  75. */
  76. private readonly GcmSivHasher theDataHasher;
  77. /**
  78. * The plainDataStream.
  79. */
  80. private GcmSivCache thePlain;
  81. /**
  82. * The encryptedDataStream (decryption only).
  83. */
  84. private GcmSivCache theEncData;
  85. /**
  86. * Are we encrypting?
  87. */
  88. private bool forEncryption;
  89. /**
  90. * The initialAEAD.
  91. */
  92. private byte[] theInitialAEAD;
  93. /**
  94. * The nonce.
  95. */
  96. private byte[] theNonce;
  97. /**
  98. * The flags.
  99. */
  100. private int theFlags;
  101. /**
  102. * Constructor.
  103. */
  104. public GcmSivBlockCipher()
  105. : this(AesUtilities.CreateEngine())
  106. {
  107. }
  108. /**
  109. * Constructor.
  110. * @param pCipher the underlying cipher
  111. */
  112. public GcmSivBlockCipher(IBlockCipher pCipher)
  113. : this(pCipher, new Tables4kGcmMultiplier())
  114. {
  115. }
  116. /**
  117. * Constructor.
  118. * @param pCipher the underlying cipher
  119. * @param pMultiplier the multiplier
  120. */
  121. public GcmSivBlockCipher(IBlockCipher pCipher, IGcmMultiplier pMultiplier)
  122. {
  123. /* Ensure that the cipher is the correct size */
  124. if (pCipher.GetBlockSize() != BUFLEN)
  125. throw new ArgumentException("Cipher required with a block size of " + BUFLEN + ".");
  126. /* Store parameters */
  127. theCipher = pCipher;
  128. theMultiplier = pMultiplier;
  129. /* Create the hashers */
  130. theAEADHasher = new GcmSivHasher(this);
  131. theDataHasher = new GcmSivHasher(this);
  132. }
  133. public virtual IBlockCipher UnderlyingCipher => theCipher;
  134. public virtual int GetBlockSize()
  135. {
  136. return theCipher.GetBlockSize();
  137. }
  138. public virtual void Init(bool pEncrypt, ICipherParameters cipherParameters)
  139. {
  140. /* Set defaults */
  141. byte[] myInitialAEAD = null;
  142. byte[] myNonce;
  143. KeyParameter myKey;
  144. /* Access parameters */
  145. if (cipherParameters is AeadParameters)
  146. {
  147. AeadParameters myAEAD = (AeadParameters)cipherParameters;
  148. myInitialAEAD = myAEAD.GetAssociatedText();
  149. myNonce = myAEAD.GetNonce();
  150. myKey = myAEAD.Key;
  151. }
  152. else if (cipherParameters is ParametersWithIV)
  153. {
  154. ParametersWithIV myParms = (ParametersWithIV)cipherParameters;
  155. myNonce = myParms.GetIV();
  156. myKey = (KeyParameter)myParms.Parameters;
  157. }
  158. else
  159. {
  160. throw new ArgumentException("invalid parameters passed to GCM_SIV");
  161. }
  162. /* Check nonceSize */
  163. if (myNonce == null || myNonce.Length != NONCELEN)
  164. {
  165. throw new ArgumentException("Invalid nonce");
  166. }
  167. /* Check keysize */
  168. if (myKey == null)
  169. {
  170. throw new ArgumentException("Invalid key");
  171. }
  172. byte[] k = myKey.GetKey();
  173. if (k.Length != BUFLEN && k.Length != (BUFLEN << 1))
  174. {
  175. throw new ArgumentException("Invalid key");
  176. }
  177. /* Reset details */
  178. forEncryption = pEncrypt;
  179. theInitialAEAD = myInitialAEAD;
  180. theNonce = myNonce;
  181. /* Initialise the keys */
  182. DeriveKeys(myKey);
  183. ResetStreams();
  184. }
  185. public virtual string AlgorithmName => theCipher.AlgorithmName + "-GCM-SIV";
  186. /**
  187. * check AEAD status.
  188. * @param pLen the aeadLength
  189. */
  190. private void CheckAeadStatus(int pLen)
  191. {
  192. /* Check we are initialised */
  193. if ((theFlags & INIT) == 0)
  194. {
  195. throw new InvalidOperationException("Cipher is not initialised");
  196. }
  197. /* Check AAD is allowed */
  198. if ((theFlags & AEAD_COMPLETE) != 0)
  199. {
  200. throw new InvalidOperationException("AEAD data cannot be processed after ordinary data");
  201. }
  202. /* Make sure that we haven't breached AEAD data limit */
  203. if ((long)theAEADHasher.getBytesProcessed() + long.MinValue > (MAX_DATALEN - pLen) + long.MinValue)
  204. {
  205. throw new InvalidOperationException("AEAD byte count exceeded");
  206. }
  207. }
  208. /**
  209. * check status.
  210. * @param pLen the dataLength
  211. */
  212. private void CheckStatus(int pLen)
  213. {
  214. /* Check we are initialised */
  215. if ((theFlags & INIT) == 0)
  216. {
  217. throw new InvalidOperationException("Cipher is not initialised");
  218. }
  219. /* Complete the AEAD section if this is the first data */
  220. if ((theFlags & AEAD_COMPLETE) == 0)
  221. {
  222. theAEADHasher.completeHash();
  223. theFlags |= AEAD_COMPLETE;
  224. }
  225. /* Make sure that we haven't breached data limit */
  226. long dataLimit = MAX_DATALEN;
  227. long currBytes = thePlain.Length;
  228. if (!forEncryption)
  229. {
  230. dataLimit += BUFLEN;
  231. currBytes = theEncData.Length;
  232. }
  233. if (currBytes + long.MinValue > (dataLimit - pLen) + long.MinValue)
  234. {
  235. throw new InvalidOperationException("byte count exceeded");
  236. }
  237. }
  238. public virtual void ProcessAadByte(byte pByte)
  239. {
  240. /* Check that we can supply AEAD */
  241. CheckAeadStatus(1);
  242. /* Process the aead */
  243. theAEADHasher.UpdateHash(pByte);
  244. }
  245. public virtual void ProcessAadBytes(byte[] pData, int pOffset, int pLen)
  246. {
  247. Check.DataLength(pData, pOffset, pLen, "input buffer too short");
  248. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  249. ProcessAadBytes(pData.AsSpan(pOffset, pLen));
  250. #else
  251. /* Check that we can supply AEAD */
  252. CheckAeadStatus(pLen);
  253. /* Process the aead */
  254. theAEADHasher.UpdateHash(pData, pOffset, pLen);
  255. #endif
  256. }
  257. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  258. public virtual void ProcessAadBytes(ReadOnlySpan<byte> input)
  259. {
  260. /* Check that we can supply AEAD */
  261. CheckAeadStatus(input.Length);
  262. /* Process the aead */
  263. theAEADHasher.UpdateHash(input);
  264. }
  265. #endif
  266. public virtual int ProcessByte(byte pByte, byte[] pOutput, int pOutOffset)
  267. {
  268. /* Check that we have initialised */
  269. CheckStatus(1);
  270. /* Store the data */
  271. if (forEncryption)
  272. {
  273. thePlain.WriteByte(pByte);
  274. theDataHasher.UpdateHash(pByte);
  275. }
  276. else
  277. {
  278. theEncData.WriteByte(pByte);
  279. }
  280. /* No data returned */
  281. return 0;
  282. }
  283. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  284. public virtual int ProcessByte(byte input, Span<byte> output)
  285. {
  286. /* Check that we have initialised */
  287. CheckStatus(1);
  288. /* Store the data */
  289. if (forEncryption)
  290. {
  291. thePlain.WriteByte(input);
  292. theDataHasher.UpdateHash(input);
  293. }
  294. else
  295. {
  296. theEncData.WriteByte(input);
  297. }
  298. /* No data returned */
  299. return 0;
  300. }
  301. #endif
  302. public virtual int ProcessBytes(byte[] pData, int pOffset, int pLen, byte[] pOutput, int pOutOffset)
  303. {
  304. Check.DataLength(pData, pOffset, pLen, "input buffer too short");
  305. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  306. return ProcessBytes(pData.AsSpan(pOffset, pLen), Spans.FromNullable(pOutput, pOutOffset));
  307. #else
  308. /* Check that we have initialised */
  309. CheckStatus(pLen);
  310. /* Store the data */
  311. if (forEncryption)
  312. {
  313. thePlain.Write(pData, pOffset, pLen);
  314. theDataHasher.UpdateHash(pData, pOffset, pLen);
  315. }
  316. else
  317. {
  318. theEncData.Write(pData, pOffset, pLen);
  319. }
  320. /* No data returned */
  321. return 0;
  322. #endif
  323. }
  324. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  325. public virtual int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
  326. {
  327. /* Check that we have initialised */
  328. CheckStatus(input.Length);
  329. /* Store the data */
  330. if (forEncryption)
  331. {
  332. thePlain.Write(input);
  333. theDataHasher.UpdateHash(input);
  334. }
  335. else
  336. {
  337. theEncData.Write(input);
  338. }
  339. /* No data returned */
  340. return 0;
  341. }
  342. #endif
  343. public virtual int DoFinal(byte[] pOutput, int pOffset)
  344. {
  345. Check.OutputLength(pOutput, pOffset, GetOutputSize(0), "output buffer too short");
  346. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  347. return DoFinal(pOutput.AsSpan(pOffset));
  348. #else
  349. /* Check that we have initialised */
  350. CheckStatus(0);
  351. /* If we are encrypting */
  352. if (forEncryption)
  353. {
  354. /* Derive the tag */
  355. byte[] myTag = CalculateTag();
  356. /* encrypt the plain text */
  357. int myDataLen = BUFLEN + EncryptPlain(myTag, pOutput, pOffset);
  358. /* Add the tag to the output */
  359. Array.Copy(myTag, 0, pOutput, pOffset + Convert.ToInt32(thePlain.Length), BUFLEN);
  360. /* Reset the streams */
  361. ResetStreams();
  362. return myDataLen;
  363. /* else we are decrypting */
  364. }
  365. else
  366. {
  367. /* decrypt to plain text */
  368. DecryptPlain();
  369. /* Release plain text */
  370. int myDataLen = Streams.WriteBufTo(thePlain, pOutput, pOffset);
  371. /* Reset the streams */
  372. ResetStreams();
  373. return myDataLen;
  374. }
  375. #endif
  376. }
  377. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  378. public virtual int DoFinal(Span<byte> output)
  379. {
  380. /* Check that we have initialised */
  381. CheckStatus(0);
  382. Check.OutputLength(output, GetOutputSize(0), "output buffer too short");
  383. /* If we are encrypting */
  384. if (forEncryption)
  385. {
  386. /* Derive the tag */
  387. byte[] myTag = CalculateTag();
  388. /* encrypt the plain text */
  389. int myDataLen = BUFLEN + EncryptPlain(myTag, output);
  390. /* Add the tag to the output */
  391. myTag.AsSpan(0, BUFLEN).CopyTo(output[Convert.ToInt32(thePlain.Length)..]);
  392. /* Reset the streams */
  393. ResetStreams();
  394. return myDataLen;
  395. /* else we are decrypting */
  396. }
  397. else
  398. {
  399. /* decrypt to plain text */
  400. DecryptPlain();
  401. /* Release plain text */
  402. if (!thePlain.TryGetBuffer(out var buffer))
  403. throw new InvalidOperationException();
  404. buffer.AsSpan().CopyTo(output);
  405. int myDataLen = buffer.Count;
  406. /* Reset the streams */
  407. ResetStreams();
  408. return myDataLen;
  409. }
  410. }
  411. #endif
  412. public virtual byte[] GetMac()
  413. {
  414. throw new InvalidOperationException();
  415. }
  416. public virtual int GetUpdateOutputSize(int pLen)
  417. {
  418. return 0;
  419. }
  420. public virtual int GetOutputSize(int pLen)
  421. {
  422. if (forEncryption)
  423. {
  424. return pLen + Convert.ToInt32(thePlain.Length) + BUFLEN;
  425. }
  426. int myCurr = pLen + Convert.ToInt32(theEncData.Length);
  427. return myCurr > BUFLEN ? myCurr - BUFLEN : 0;
  428. }
  429. public virtual void Reset()
  430. {
  431. ResetStreams();
  432. }
  433. /**
  434. * Reset Streams.
  435. */
  436. private void ResetStreams()
  437. {
  438. /* Clear the plainText buffer */
  439. if (thePlain != null)
  440. {
  441. int count = Convert.ToInt32(thePlain.Length);
  442. Array.Clear(thePlain.GetBuffer(), 0, count);
  443. thePlain.SetLength(0);
  444. }
  445. /* Reset hashers */
  446. theAEADHasher.Reset();
  447. theDataHasher.Reset();
  448. /* Recreate streams (to release memory) */
  449. thePlain = new GcmSivCache();
  450. theEncData = forEncryption ? null : new GcmSivCache();
  451. /* Initialise AEAD if required */
  452. theFlags &= ~AEAD_COMPLETE;
  453. Arrays.Fill(theGHash, (byte)0);
  454. if (theInitialAEAD != null)
  455. {
  456. theAEADHasher.UpdateHash(theInitialAEAD, 0, theInitialAEAD.Length);
  457. }
  458. }
  459. /**
  460. * Obtain buffer length (allowing for null).
  461. * @param pBuffer the buffere
  462. * @return the length
  463. */
  464. private static int bufLength(byte[] pBuffer)
  465. {
  466. return pBuffer == null ? 0 : pBuffer.Length;
  467. }
  468. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  469. private int EncryptPlain(byte[] pCounter, Span<byte> target)
  470. {
  471. byte[] thePlainBuf = thePlain.GetBuffer();
  472. int thePlainLen = Convert.ToInt32(thePlain.Length);
  473. byte[] mySrc = thePlainBuf;
  474. byte[] myCounter = Arrays.Clone(pCounter);
  475. myCounter[BUFLEN - 1] |= MASK;
  476. byte[] myMask = new byte[BUFLEN];
  477. long myRemaining = thePlainLen;
  478. int myOff = 0;
  479. /* While we have data to process */
  480. while (myRemaining > 0)
  481. {
  482. /* Generate the next mask */
  483. theCipher.ProcessBlock(myCounter, 0, myMask, 0);
  484. /* Xor data into mask */
  485. int myLen = (int)System.Math.Min(BUFLEN, myRemaining);
  486. xorBlock(myMask, mySrc, myOff, myLen);
  487. /* Copy encrypted data to output */
  488. myMask.AsSpan(0, myLen).CopyTo(target[myOff..]);
  489. /* Adjust counters */
  490. myRemaining -= myLen;
  491. myOff += myLen;
  492. incrementCounter(myCounter);
  493. }
  494. /* Return the amount of data processed */
  495. return thePlainLen;
  496. }
  497. #else
  498. private int EncryptPlain(byte[] pCounter, byte[] pTarget, int pOffset)
  499. {
  500. byte[] thePlainBuf = thePlain.GetBuffer();
  501. int thePlainLen = Convert.ToInt32(thePlain.Length);
  502. byte[] mySrc = thePlainBuf;
  503. byte[] myCounter = Arrays.Clone(pCounter);
  504. myCounter[BUFLEN - 1] |= MASK;
  505. byte[] myMask = new byte[BUFLEN];
  506. long myRemaining = thePlainLen;
  507. int myOff = 0;
  508. /* While we have data to process */
  509. while (myRemaining > 0)
  510. {
  511. /* Generate the next mask */
  512. theCipher.ProcessBlock(myCounter, 0, myMask, 0);
  513. /* Xor data into mask */
  514. int myLen = (int)System.Math.Min(BUFLEN, myRemaining);
  515. xorBlock(myMask, mySrc, myOff, myLen);
  516. /* Copy encrypted data to output */
  517. Array.Copy(myMask, 0, pTarget, pOffset + myOff, myLen);
  518. /* Adjust counters */
  519. myRemaining -= myLen;
  520. myOff += myLen;
  521. incrementCounter(myCounter);
  522. }
  523. /* Return the amount of data processed */
  524. return thePlainLen;
  525. }
  526. #endif
  527. private void DecryptPlain()
  528. {
  529. byte[] theEncDataBuf = theEncData.GetBuffer();
  530. int theEncDataLen = Convert.ToInt32(theEncData.Length);
  531. byte[] mySrc = theEncDataBuf;
  532. int myRemaining = theEncDataLen - BUFLEN;
  533. /* Check for insufficient data */
  534. if (myRemaining < 0)
  535. {
  536. throw new InvalidCipherTextException("Data too short");
  537. }
  538. /* Access counter */
  539. byte[] myExpected = Arrays.CopyOfRange(mySrc, myRemaining, myRemaining + BUFLEN);
  540. byte[] myCounter = Arrays.Clone(myExpected);
  541. myCounter[BUFLEN - 1] |= MASK;
  542. byte[] myMask = new byte[BUFLEN];
  543. int myOff = 0;
  544. /* While we have data to process */
  545. while (myRemaining > 0)
  546. {
  547. /* Generate the next mask */
  548. theCipher.ProcessBlock(myCounter, 0, myMask, 0);
  549. /* Xor data into mask */
  550. int myLen = System.Math.Min(BUFLEN, myRemaining);
  551. xorBlock(myMask, mySrc, myOff, myLen);
  552. /* Write data to plain dataStream */
  553. thePlain.Write(myMask, 0, myLen);
  554. theDataHasher.UpdateHash(myMask, 0, myLen);
  555. /* Adjust counters */
  556. myRemaining -= myLen;
  557. myOff += myLen;
  558. incrementCounter(myCounter);
  559. }
  560. /* Derive and check the tag */
  561. byte[] myTag = CalculateTag();
  562. if (!Arrays.ConstantTimeAreEqual(myTag, myExpected))
  563. {
  564. Reset();
  565. throw new InvalidCipherTextException("mac check failed");
  566. }
  567. }
  568. /**
  569. * calculate tag.
  570. * @return the calculated tag
  571. */
  572. private byte[] CalculateTag()
  573. {
  574. /* Complete the hash */
  575. theDataHasher.completeHash();
  576. byte[] myPolyVal = completePolyVal();
  577. /* calculate polyVal */
  578. byte[] myResult = new byte[BUFLEN];
  579. /* Fold in the nonce */
  580. for (int i = 0; i < NONCELEN; i++)
  581. {
  582. myPolyVal[i] ^= theNonce[i];
  583. }
  584. /* Clear top bit */
  585. myPolyVal[BUFLEN - 1] &= (byte)(MASK - 1);
  586. /* Calculate tag and return it */
  587. theCipher.ProcessBlock(myPolyVal, 0, myResult, 0);
  588. return myResult;
  589. }
  590. /**
  591. * complete polyVAL.
  592. * @return the calculated value
  593. */
  594. private byte[] completePolyVal()
  595. {
  596. /* Build the polyVal result */
  597. byte[] myResult = new byte[BUFLEN];
  598. gHashLengths();
  599. fillReverse(theGHash, 0, BUFLEN, myResult);
  600. return myResult;
  601. }
  602. /**
  603. * process lengths.
  604. */
  605. private void gHashLengths()
  606. {
  607. /* Create reversed bigEndian buffer to keep it simple */
  608. byte[] myIn = new byte[BUFLEN];
  609. Pack.UInt64_To_BE((ulong)Bytes.NumBits * theDataHasher.getBytesProcessed(), myIn, 0);
  610. Pack.UInt64_To_BE((ulong)Bytes.NumBits * theAEADHasher.getBytesProcessed(), myIn, Longs.NumBytes);
  611. /* hash value */
  612. gHASH(myIn);
  613. }
  614. /**
  615. * perform the next GHASH step.
  616. * @param pNext the next value
  617. */
  618. private void gHASH(byte[] pNext)
  619. {
  620. xorBlock(theGHash, pNext);
  621. theMultiplier.MultiplyH(theGHash);
  622. }
  623. private static void fillReverse(byte[] pInput, int pOffset, int pLength, byte[] pOutput)
  624. {
  625. /* Loop through the buffer */
  626. for (int i = 0, j = BUFLEN - 1; i < pLength; i++, j--)
  627. {
  628. /* Copy byte */
  629. pOutput[j] = pInput[pOffset + i];
  630. }
  631. }
  632. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  633. private static void fillReverse(ReadOnlySpan<byte> input, Span<byte> output)
  634. {
  635. /* Loop through the buffer */
  636. for (int i = 0, j = BUFLEN - 1; i < input.Length; i++, j--)
  637. {
  638. /* Copy byte */
  639. output[j] = input[i];
  640. }
  641. }
  642. #endif
  643. /**
  644. * xor a full block buffer.
  645. * @param pLeft the left operand and result
  646. * @param pRight the right operand
  647. */
  648. private static void xorBlock(byte[] pLeft, byte[] pRight)
  649. {
  650. /* Loop through the bytes */
  651. for (int i = 0; i < BUFLEN; i++)
  652. {
  653. pLeft[i] ^= pRight[i];
  654. }
  655. }
  656. /**
  657. * xor a partial block buffer.
  658. * @param pLeft the left operand and result
  659. * @param pRight the right operand
  660. * @param pOffset the offset in the right operand
  661. * @param pLength the length of data in the right operand
  662. */
  663. private static void xorBlock(byte[] pLeft, byte[] pRight, int pOffset, int pLength)
  664. {
  665. /* Loop through the bytes */
  666. for (int i = 0; i < pLength; i++)
  667. {
  668. pLeft[i] ^= pRight[i + pOffset];
  669. }
  670. }
  671. /**
  672. * increment the counter.
  673. * @param pCounter the counter to increment
  674. */
  675. private static void incrementCounter(byte[] pCounter)
  676. {
  677. /* Loop through the bytes incrementing counter */
  678. for (int i = 0; i < Integers.NumBytes; i++)
  679. {
  680. if (++pCounter[i] != 0)
  681. {
  682. break;
  683. }
  684. }
  685. }
  686. /**
  687. * multiply by X.
  688. * @param pValue the value to adjust
  689. */
  690. private static void mulX(byte[] pValue)
  691. {
  692. /* Loop through the bytes */
  693. byte myMask = (byte)0;
  694. for (int i = 0; i < BUFLEN; i++)
  695. {
  696. byte myValue = pValue[i];
  697. pValue[i] = (byte)(((myValue >> 1) & ~MASK) | myMask);
  698. myMask = (byte)((myValue & 1) == 0 ? (byte)0 : MASK);
  699. }
  700. /* Xor in addition if last bit was set */
  701. if (myMask != 0)
  702. {
  703. pValue[0] ^= ADD;
  704. }
  705. }
  706. /**
  707. * Derive Keys.
  708. * @param pKey the keyGeneration key
  709. */
  710. private void DeriveKeys(KeyParameter pKey)
  711. {
  712. /* Create the buffers */
  713. byte[] myIn = new byte[BUFLEN];
  714. byte[] myOut = new byte[BUFLEN];
  715. byte[] myResult = new byte[BUFLEN];
  716. byte[] myEncKey = new byte[pKey.GetKey().Length];
  717. /* Prepare for encryption */
  718. Array.Copy(theNonce, 0, myIn, BUFLEN - NONCELEN, NONCELEN);
  719. theCipher.Init(true, pKey);
  720. /* Derive authentication key */
  721. int myOff = 0;
  722. theCipher.ProcessBlock(myIn, 0, myOut, 0);
  723. Array.Copy(myOut, 0, myResult, myOff, HALFBUFLEN);
  724. myIn[0]++;
  725. myOff += HALFBUFLEN;
  726. theCipher.ProcessBlock(myIn, 0, myOut, 0);
  727. Array.Copy(myOut, 0, myResult, myOff, HALFBUFLEN);
  728. /* Derive encryption key */
  729. myIn[0]++;
  730. myOff = 0;
  731. theCipher.ProcessBlock(myIn, 0, myOut, 0);
  732. Array.Copy(myOut, 0, myEncKey, myOff, HALFBUFLEN);
  733. myIn[0]++;
  734. myOff += HALFBUFLEN;
  735. theCipher.ProcessBlock(myIn, 0, myOut, 0);
  736. Array.Copy(myOut, 0, myEncKey, myOff, HALFBUFLEN);
  737. /* If we have a 32byte key */
  738. if (myEncKey.Length == BUFLEN << 1)
  739. {
  740. /* Derive remainder of encryption key */
  741. myIn[0]++;
  742. myOff += HALFBUFLEN;
  743. theCipher.ProcessBlock(myIn, 0, myOut, 0);
  744. Array.Copy(myOut, 0, myEncKey, myOff, HALFBUFLEN);
  745. myIn[0]++;
  746. myOff += HALFBUFLEN;
  747. theCipher.ProcessBlock(myIn, 0, myOut, 0);
  748. Array.Copy(myOut, 0, myEncKey, myOff, HALFBUFLEN);
  749. }
  750. /* Initialise the Cipher */
  751. theCipher.Init(true, new KeyParameter(myEncKey));
  752. /* Initialise the multiplier */
  753. fillReverse(myResult, 0, BUFLEN, myOut);
  754. mulX(myOut);
  755. theMultiplier.Init(myOut);
  756. theFlags |= INIT;
  757. }
  758. private class GcmSivCache
  759. : MemoryStream
  760. {
  761. internal GcmSivCache()
  762. {
  763. }
  764. }
  765. /**
  766. * Hash Control.
  767. */
  768. private class GcmSivHasher
  769. {
  770. /**
  771. * Cache.
  772. */
  773. private readonly byte[] theBuffer = new byte[BUFLEN];
  774. /**
  775. * Single byte cache.
  776. */
  777. private readonly byte[] theByte = new byte[1];
  778. /**
  779. * Count of active bytes in cache.
  780. */
  781. private int numActive;
  782. /**
  783. * Count of hashed bytes.
  784. */
  785. private ulong numHashed;
  786. private readonly GcmSivBlockCipher parent;
  787. internal GcmSivHasher(GcmSivBlockCipher parent)
  788. {
  789. this.parent = parent;
  790. }
  791. /**
  792. * Obtain the count of bytes hashed.
  793. * @return the count
  794. */
  795. internal ulong getBytesProcessed()
  796. {
  797. return numHashed;
  798. }
  799. /**
  800. * Reset the hasher.
  801. */
  802. internal void Reset()
  803. {
  804. numActive = 0;
  805. numHashed = 0;
  806. }
  807. /**
  808. * update hash.
  809. * @param pByte the byte
  810. */
  811. internal void UpdateHash(byte pByte)
  812. {
  813. theByte[0] = pByte;
  814. UpdateHash(theByte, 0, 1);
  815. }
  816. /**
  817. * update hash.
  818. * @param pBuffer the buffer
  819. * @param pOffset the offset within the buffer
  820. * @param pLen the length of data
  821. */
  822. internal void UpdateHash(byte[] pBuffer, int pOffset, int pLen)
  823. {
  824. /* If we should process the cache */
  825. int mySpace = BUFLEN - numActive;
  826. int numProcessed = 0;
  827. int myRemaining = pLen;
  828. if (numActive > 0 && pLen >= mySpace)
  829. {
  830. /* Copy data into the cache and hash it */
  831. Array.Copy(pBuffer, pOffset, theBuffer, numActive, mySpace);
  832. fillReverse(theBuffer, 0, BUFLEN, parent.theReverse);
  833. parent.gHASH(parent.theReverse);
  834. /* Adjust counters */
  835. numProcessed += mySpace;
  836. myRemaining -= mySpace;
  837. numActive = 0;
  838. }
  839. /* While we have full blocks */
  840. while (myRemaining >= BUFLEN)
  841. {
  842. /* Access the next data */
  843. fillReverse(pBuffer, pOffset + numProcessed, BUFLEN, parent.theReverse);
  844. parent.gHASH(parent.theReverse);
  845. /* Adjust counters */
  846. numProcessed += BUFLEN;
  847. myRemaining -= BUFLEN;
  848. }
  849. /* If we have remaining data */
  850. if (myRemaining > 0)
  851. {
  852. /* Copy data into the cache */
  853. Array.Copy(pBuffer, pOffset + numProcessed, theBuffer, numActive, myRemaining);
  854. numActive += myRemaining;
  855. }
  856. /* Adjust the number of bytes processed */
  857. numHashed += (ulong)pLen;
  858. }
  859. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  860. internal void UpdateHash(ReadOnlySpan<byte> buffer)
  861. {
  862. int pLen = buffer.Length;
  863. /* If we should process the cache */
  864. int mySpace = BUFLEN - numActive;
  865. if (numActive > 0 && buffer.Length >= mySpace)
  866. {
  867. /* Copy data into the cache and hash it */
  868. buffer[..mySpace].CopyTo(theBuffer.AsSpan(numActive));
  869. fillReverse(theBuffer, parent.theReverse);
  870. parent.gHASH(parent.theReverse);
  871. /* Adjust counters */
  872. buffer = buffer[mySpace..];
  873. numActive = 0;
  874. }
  875. /* While we have full blocks */
  876. while (buffer.Length >= BUFLEN)
  877. {
  878. /* Access the next data */
  879. fillReverse(buffer[..BUFLEN], parent.theReverse);
  880. parent.gHASH(parent.theReverse);
  881. /* Adjust counters */
  882. buffer = buffer[BUFLEN..];
  883. }
  884. /* If we have remaining data */
  885. if (!buffer.IsEmpty)
  886. {
  887. /* Copy data into the cache */
  888. buffer.CopyTo(theBuffer.AsSpan(numActive));
  889. numActive += buffer.Length;
  890. }
  891. /* Adjust the number of bytes processed */
  892. numHashed += (ulong)pLen;
  893. }
  894. #endif
  895. /**
  896. * complete hash.
  897. */
  898. internal void completeHash()
  899. {
  900. /* If we have remaining data */
  901. if (numActive > 0)
  902. {
  903. /* Access the next data */
  904. Arrays.Fill(parent.theReverse, (byte)0);
  905. fillReverse(theBuffer, 0, numActive, parent.theReverse);
  906. /* hash value */
  907. parent.gHASH(parent.theReverse);
  908. }
  909. }
  910. }
  911. }
  912. }
  913. #pragma warning restore
  914. #endif