Blake2sDigest.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. #if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
  5. using System.Runtime.CompilerServices;
  6. #endif
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests
  10. {
  11. /*
  12. The BLAKE2 cryptographic hash function was designed by Jean-
  13. Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian
  14. Winnerlein.
  15. Reference Implementation and Description can be found at: https://blake2.net/
  16. RFC: https://tools.ietf.org/html/rfc7693
  17. This implementation does not support the Tree Hashing Mode.
  18. For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based
  19. message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2.
  20. Algorithm | Target | Collision | Hash | Hash ASN.1 |
  21. Identifier | Arch | Security | nn | OID Suffix |
  22. ---------------+--------+-----------+------+------------+
  23. id-blake2s128 | 32-bit | 2**64 | 16 | x.2.4 |
  24. id-blake2s160 | 32-bit | 2**80 | 20 | x.2.5 |
  25. id-blake2s224 | 32-bit | 2**112 | 28 | x.2.7 |
  26. id-blake2s256 | 32-bit | 2**128 | 32 | x.2.8 |
  27. ---------------+--------+-----------+------+------------+
  28. */
  29. /**
  30. * Implementation of the cryptographic hash function BLAKE2s.
  31. * <p/>
  32. * BLAKE2s offers a built-in keying mechanism to be used directly
  33. * for authentication ("Prefix-MAC") rather than a HMAC construction.
  34. * <p/>
  35. * BLAKE2s offers a built-in support for a salt for randomized hashing
  36. * and a personal string for defining a unique hash function for each application.
  37. * <p/>
  38. * BLAKE2s is optimized for 32-bit platforms and produces digests of any size
  39. * between 1 and 32 bytes.
  40. */
  41. public sealed class Blake2sDigest
  42. : IDigest
  43. {
  44. /**
  45. * BLAKE2s Initialization Vector
  46. **/
  47. private static readonly uint[] blake2s_IV =
  48. // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19.
  49. // The same as SHA-256 IV.
  50. {
  51. 0x6a09e667, 0xbb67ae85, 0x3c6ef372,
  52. 0xa54ff53a, 0x510e527f, 0x9b05688c,
  53. 0x1f83d9ab, 0x5be0cd19
  54. };
  55. /**
  56. * Message word permutations
  57. **/
  58. private static readonly byte[,] blake2s_sigma =
  59. {
  60. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
  61. { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
  62. { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
  63. { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
  64. { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
  65. { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
  66. { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
  67. { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
  68. { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
  69. { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }
  70. };
  71. private const int ROUNDS = 10; // to use for Catenas H'
  72. private const int BLOCK_LENGTH_BYTES = 64;// bytes
  73. // General parameters:
  74. private int digestLength = 32; // 1- 32 bytes
  75. private int keyLength = 0; // 0 - 32 bytes for keyed hashing for MAC
  76. private byte[] salt = null;
  77. private byte[] personalization = null;
  78. private byte[] key = null;
  79. // Tree hashing parameters:
  80. // The Tree Hashing Mode is not supported but these are used for the XOF implementation
  81. private int fanout = 1; // 0-255
  82. private int depth = 1; // 0-255
  83. private int leafLength = 0;
  84. private long nodeOffset = 0L;
  85. private int nodeDepth = 0;
  86. private int innerHashLength = 0;
  87. /**
  88. * Whenever this buffer overflows, it will be processed in the Compress()
  89. * function. For performance issues, long messages will not use this buffer.
  90. */
  91. private byte[] buffer = null;
  92. /**
  93. * Position of last inserted byte
  94. **/
  95. private int bufferPos = 0;// a value from 0 up to BLOCK_LENGTH_BYTES
  96. /**
  97. * Internal state, in the BLAKE2 paper it is called v
  98. **/
  99. private uint[] internalState = new uint[16];
  100. /**
  101. * State vector, in the BLAKE2 paper it is called h
  102. **/
  103. private uint[] chainValue = null;
  104. // counter (counts bytes): Length up to 2^64 are supported
  105. /**
  106. * holds least significant bits of counter
  107. **/
  108. private uint t0 = 0;
  109. /**
  110. * holds most significant bits of counter
  111. **/
  112. private uint t1 = 0;
  113. /**
  114. * finalization flag, for last block: ~0
  115. **/
  116. private uint f0 = 0;
  117. // For Tree Hashing Mode, not used here:
  118. // private long f1 = 0L; // finalization flag, for last node: ~0L
  119. /**
  120. * BLAKE2s-256 for hashing.
  121. */
  122. public Blake2sDigest()
  123. : this(256)
  124. {
  125. }
  126. public Blake2sDigest(Blake2sDigest digest)
  127. {
  128. this.bufferPos = digest.bufferPos;
  129. this.buffer = Arrays.Clone(digest.buffer);
  130. this.keyLength = digest.keyLength;
  131. this.key = Arrays.Clone(digest.key);
  132. this.digestLength = digest.digestLength;
  133. this.internalState = Arrays.Clone(digest.internalState);
  134. this.chainValue = Arrays.Clone(digest.chainValue);
  135. this.t0 = digest.t0;
  136. this.t1 = digest.t1;
  137. this.f0 = digest.f0;
  138. this.salt = Arrays.Clone(digest.salt);
  139. this.personalization = Arrays.Clone(digest.personalization);
  140. this.fanout = digest.fanout;
  141. this.depth = digest.depth;
  142. this.leafLength = digest.leafLength;
  143. this.nodeOffset = digest.nodeOffset;
  144. this.nodeDepth = digest.nodeDepth;
  145. this.innerHashLength = digest.innerHashLength;
  146. }
  147. /**
  148. * BLAKE2s for hashing.
  149. *
  150. * @param digestBits the desired digest length in bits. Must be a multiple of 8 and less than 256.
  151. */
  152. public Blake2sDigest(int digestBits)
  153. {
  154. if (digestBits < 8 || digestBits > 256 || digestBits % 8 != 0)
  155. throw new ArgumentException("BLAKE2s digest bit length must be a multiple of 8 and not greater than 256");
  156. digestLength = digestBits / 8;
  157. Init(null, null, null);
  158. }
  159. /**
  160. * BLAKE2s for authentication ("Prefix-MAC mode").
  161. * <p/>
  162. * After calling the doFinal() method, the key will remain to be used for
  163. * further computations of this instance. The key can be overwritten using
  164. * the clearKey() method.
  165. *
  166. * @param key a key up to 32 bytes or null
  167. */
  168. public Blake2sDigest(byte[] key)
  169. {
  170. Init(null, null, key);
  171. }
  172. /**
  173. * BLAKE2s with key, required digest length, salt and personalization.
  174. * <p/>
  175. * After calling the doFinal() method, the key, the salt and the personal
  176. * string will remain and might be used for further computations with this
  177. * instance. The key can be overwritten using the clearKey() method, the
  178. * salt (pepper) can be overwritten using the clearSalt() method.
  179. *
  180. * @param key a key up to 32 bytes or null
  181. * @param digestBytes from 1 up to 32 bytes
  182. * @param salt 8 bytes or null
  183. * @param personalization 8 bytes or null
  184. */
  185. public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, byte[] personalization)
  186. {
  187. if (digestBytes < 1 || digestBytes > 32)
  188. throw new ArgumentException("Invalid digest length (required: 1 - 32)");
  189. this.digestLength = digestBytes;
  190. Init(salt, personalization, key);
  191. }
  192. // XOF root hash parameters
  193. internal Blake2sDigest(int digestBytes, byte[] key, byte[] salt, byte[] personalization, long offset)
  194. {
  195. digestLength = digestBytes;
  196. nodeOffset = offset;
  197. Init(salt, personalization, key);
  198. }
  199. // XOF internal hash parameters
  200. internal Blake2sDigest(int digestBytes, int hashLength, long offset)
  201. {
  202. digestLength = digestBytes;
  203. nodeOffset = offset;
  204. fanout = 0;
  205. depth = 0;
  206. leafLength = hashLength;
  207. innerHashLength = hashLength;
  208. nodeDepth = 0;
  209. Init(null, null, null);
  210. }
  211. // initialize the digest's parameters
  212. private void Init(byte[] salt, byte[] personalization, byte[] key)
  213. {
  214. buffer = new byte[BLOCK_LENGTH_BYTES];
  215. if (key != null && key.Length > 0)
  216. {
  217. keyLength = key.Length;
  218. if (keyLength > 32)
  219. throw new ArgumentException("Keys > 32 bytes are not supported");
  220. this.key = new byte[keyLength];
  221. Array.Copy(key, 0, this.key, 0, keyLength);
  222. Array.Copy(key, 0, buffer, 0, keyLength);
  223. bufferPos = BLOCK_LENGTH_BYTES; // zero padding
  224. }
  225. if (chainValue == null)
  226. {
  227. chainValue = new uint[8];
  228. chainValue[0] = blake2s_IV[0]
  229. ^ (uint)(digestLength | (keyLength << 8) | ((fanout << 16) | (depth << 24)));
  230. chainValue[1] = blake2s_IV[1] ^ (uint)leafLength;
  231. int nofHi = (int)(nodeOffset >> 32);
  232. int nofLo = (int)nodeOffset;
  233. chainValue[2] = blake2s_IV[2] ^ (uint)nofLo;
  234. chainValue[3] = blake2s_IV[3] ^ (uint)(nofHi | (nodeDepth << 16) | (innerHashLength << 24));
  235. chainValue[4] = blake2s_IV[4];
  236. chainValue[5] = blake2s_IV[5];
  237. if (salt != null)
  238. {
  239. if (salt.Length != 8)
  240. throw new ArgumentException("Salt length must be exactly 8 bytes");
  241. this.salt = new byte[8];
  242. Array.Copy(salt, 0, this.salt, 0, salt.Length);
  243. chainValue[4] ^= Pack.LE_To_UInt32(salt, 0);
  244. chainValue[5] ^= Pack.LE_To_UInt32(salt, 4);
  245. }
  246. chainValue[6] = blake2s_IV[6];
  247. chainValue[7] = blake2s_IV[7];
  248. if (personalization != null)
  249. {
  250. if (personalization.Length != 8)
  251. throw new ArgumentException("Personalization length must be exactly 8 bytes");
  252. this.personalization = new byte[8];
  253. Array.Copy(personalization, 0, this.personalization, 0, personalization.Length);
  254. chainValue[6] ^= Pack.LE_To_UInt32(personalization, 0);
  255. chainValue[7] ^= Pack.LE_To_UInt32(personalization, 4);
  256. }
  257. }
  258. }
  259. private void InitializeInternalState()
  260. {
  261. // initialize v:
  262. Array.Copy(chainValue, 0, internalState, 0, chainValue.Length);
  263. Array.Copy(blake2s_IV, 0, internalState, chainValue.Length, 4);
  264. internalState[12] = t0 ^ blake2s_IV[4];
  265. internalState[13] = t1 ^ blake2s_IV[5];
  266. internalState[14] = f0 ^ blake2s_IV[6];
  267. internalState[15] = blake2s_IV[7];// ^ f1 with f1 = 0
  268. }
  269. /**
  270. * Update the message digest with a single byte.
  271. *
  272. * @param b the input byte to be entered.
  273. */
  274. public void Update(byte b)
  275. {
  276. // process the buffer if full else add to buffer:
  277. int remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
  278. if (remainingLength == 0)
  279. { // full buffer
  280. t0 += BLOCK_LENGTH_BYTES;
  281. if (t0 == 0)
  282. { // if message > 2^32
  283. t1++;
  284. }
  285. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  286. Compress(buffer);
  287. #else
  288. Compress(buffer, 0);
  289. #endif
  290. Array.Clear(buffer, 0, buffer.Length);// clear buffer
  291. buffer[0] = b;
  292. bufferPos = 1;
  293. }
  294. else
  295. {
  296. buffer[bufferPos] = b;
  297. bufferPos++;
  298. }
  299. }
  300. /**
  301. * Update the message digest with a block of bytes.
  302. *
  303. * @param message the byte array containing the data.
  304. * @param offset the offset into the byte array where the data starts.
  305. * @param len the length of the data.
  306. */
  307. public void BlockUpdate(byte[] message, int offset, int len)
  308. {
  309. if (message == null || len == 0)
  310. return;
  311. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  312. BlockUpdate(message.AsSpan(offset, len));
  313. #else
  314. int remainingLength = 0; // left bytes of buffer
  315. if (bufferPos != 0)
  316. { // commenced, incomplete buffer
  317. // complete the buffer:
  318. remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
  319. if (remainingLength < len)
  320. { // full buffer + at least 1 byte
  321. Array.Copy(message, offset, buffer, bufferPos, remainingLength);
  322. t0 += BLOCK_LENGTH_BYTES;
  323. if (t0 == 0)
  324. { // if message > 2^32
  325. t1++;
  326. }
  327. Compress(buffer, 0);
  328. bufferPos = 0;
  329. Array.Clear(buffer, 0, buffer.Length);// clear buffer
  330. }
  331. else
  332. {
  333. Array.Copy(message, offset, buffer, bufferPos, len);
  334. bufferPos += len;
  335. return;
  336. }
  337. }
  338. // process blocks except last block (also if last block is full)
  339. int messagePos;
  340. int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES;
  341. for (messagePos = offset + remainingLength;
  342. messagePos < blockWiseLastPos;
  343. messagePos += BLOCK_LENGTH_BYTES)
  344. { // block wise 64 bytes
  345. // without buffer:
  346. t0 += BLOCK_LENGTH_BYTES;
  347. if (t0 == 0)
  348. {
  349. t1++;
  350. }
  351. Compress(message, messagePos);
  352. }
  353. // fill the buffer with left bytes, this might be a full block
  354. Array.Copy(message, messagePos, buffer, 0, offset + len
  355. - messagePos);
  356. bufferPos += offset + len - messagePos;
  357. #endif
  358. }
  359. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  360. public void BlockUpdate(ReadOnlySpan<byte> input)
  361. {
  362. if (input.IsEmpty)
  363. return;
  364. int remainingLength = 0; // left bytes of buffer
  365. if (bufferPos != 0)
  366. { // commenced, incomplete buffer
  367. // complete the buffer:
  368. remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
  369. if (remainingLength < input.Length)
  370. { // full buffer + at least 1 byte
  371. input[..remainingLength].CopyTo(buffer.AsSpan(bufferPos));
  372. t0 += BLOCK_LENGTH_BYTES;
  373. if (t0 == 0)
  374. { // if message > 2^32
  375. t1++;
  376. }
  377. Compress(buffer);
  378. bufferPos = 0;
  379. Array.Clear(buffer, 0, buffer.Length);// clear buffer
  380. }
  381. else
  382. {
  383. input.CopyTo(buffer.AsSpan(bufferPos));
  384. bufferPos += input.Length;
  385. return;
  386. }
  387. }
  388. // process blocks except last block (also if last block is full)
  389. int messagePos;
  390. int blockWiseLastPos = input.Length - BLOCK_LENGTH_BYTES;
  391. for (messagePos = remainingLength;
  392. messagePos < blockWiseLastPos;
  393. messagePos += BLOCK_LENGTH_BYTES)
  394. { // block wise 64 bytes
  395. // without buffer:
  396. t0 += BLOCK_LENGTH_BYTES;
  397. if (t0 == 0)
  398. {
  399. t1++;
  400. }
  401. Compress(input[messagePos..]);
  402. }
  403. // fill the buffer with left bytes, this might be a full block
  404. input[messagePos..].CopyTo(buffer.AsSpan());
  405. bufferPos += input.Length - messagePos;
  406. }
  407. #endif
  408. /**
  409. * Close the digest, producing the final digest value. The doFinal() call
  410. * leaves the digest reset. Key, salt and personal string remain.
  411. *
  412. * @param out the array the digest is to be copied into.
  413. * @param outOffset the offset into the out array the digest is to start at.
  414. */
  415. public int DoFinal(byte[] output, int outOffset)
  416. {
  417. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  418. return DoFinal(output.AsSpan(outOffset));
  419. #else
  420. f0 = 0xFFFFFFFFU;
  421. t0 += (uint)bufferPos;
  422. // bufferPos may be < 64, so (t0 == 0) does not work
  423. // for 2^32 < message length > 2^32 - 63
  424. if ((t0 < 0) && (bufferPos > -t0))
  425. {
  426. t1++;
  427. }
  428. Compress(buffer, 0);
  429. Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
  430. Array.Clear(internalState, 0, internalState.Length);
  431. int full = digestLength >> 2, partial = digestLength & 3;
  432. Pack.UInt32_To_LE(chainValue, 0, full, output, outOffset);
  433. if (partial > 0)
  434. {
  435. byte[] bytes = new byte[4];
  436. Pack.UInt32_To_LE(chainValue[full], bytes, 0);
  437. Array.Copy(bytes, 0, output, outOffset + digestLength - partial, partial);
  438. }
  439. Array.Clear(chainValue, 0, chainValue.Length);
  440. Reset();
  441. return digestLength;
  442. #endif
  443. }
  444. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  445. public int DoFinal(Span<byte> output)
  446. {
  447. f0 = 0xFFFFFFFFU;
  448. t0 += (uint)bufferPos;
  449. // bufferPos may be < 64, so (t0 == 0) does not work
  450. // for 2^32 < message length > 2^32 - 63
  451. if ((t0 < 0) && (bufferPos > -t0))
  452. {
  453. t1++;
  454. }
  455. Compress(buffer);
  456. Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
  457. Array.Clear(internalState, 0, internalState.Length);
  458. int full = digestLength >> 2, partial = digestLength & 3;
  459. Pack.UInt32_To_LE(chainValue.AsSpan(0, full), output);
  460. if (partial > 0)
  461. {
  462. Span<byte> bytes = stackalloc byte[4];
  463. Pack.UInt32_To_LE(chainValue[full], bytes);
  464. bytes[..partial].CopyTo(output[(digestLength - partial)..]);
  465. }
  466. Array.Clear(chainValue, 0, chainValue.Length);
  467. Reset();
  468. return digestLength;
  469. }
  470. #endif
  471. /**
  472. * Reset the digest back to its initial state. The key, the salt and the
  473. * personal string will remain for further computations.
  474. */
  475. public void Reset()
  476. {
  477. bufferPos = 0;
  478. f0 = 0;
  479. t0 = 0;
  480. t1 = 0;
  481. chainValue = null;
  482. Array.Clear(buffer, 0, buffer.Length);
  483. if (key != null)
  484. {
  485. Array.Copy(key, 0, buffer, 0, key.Length);
  486. bufferPos = BLOCK_LENGTH_BYTES; // zero padding
  487. }
  488. Init(this.salt, this.personalization, this.key);
  489. }
  490. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || _UNITY_2021_2_OR_NEWER_
  491. private void Compress(ReadOnlySpan<byte> message)
  492. {
  493. InitializeInternalState();
  494. Span<uint> m = stackalloc uint[16];
  495. Pack.LE_To_UInt32(message, m);
  496. for (int round = 0; round < ROUNDS; round++)
  497. {
  498. // G apply to columns of internalState: m[blake2s_sigma[round][2 * blockPos]] /+1
  499. G(m[blake2s_sigma[round, 0]], m[blake2s_sigma[round, 1]], 0, 4, 8, 12);
  500. G(m[blake2s_sigma[round, 2]], m[blake2s_sigma[round, 3]], 1, 5, 9, 13);
  501. G(m[blake2s_sigma[round, 4]], m[blake2s_sigma[round, 5]], 2, 6, 10, 14);
  502. G(m[blake2s_sigma[round, 6]], m[blake2s_sigma[round, 7]], 3, 7, 11, 15);
  503. // G apply to diagonals of internalState:
  504. G(m[blake2s_sigma[round, 8]], m[blake2s_sigma[round, 9]], 0, 5, 10, 15);
  505. G(m[blake2s_sigma[round, 10]], m[blake2s_sigma[round, 11]], 1, 6, 11, 12);
  506. G(m[blake2s_sigma[round, 12]], m[blake2s_sigma[round, 13]], 2, 7, 8, 13);
  507. G(m[blake2s_sigma[round, 14]], m[blake2s_sigma[round, 15]], 3, 4, 9, 14);
  508. }
  509. // update chain values:
  510. for (int offset = 0; offset < chainValue.Length; offset++)
  511. {
  512. chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8];
  513. }
  514. }
  515. #else
  516. private void Compress(byte[] message, int messagePos)
  517. {
  518. InitializeInternalState();
  519. uint[] m = new uint[16];
  520. Pack.LE_To_UInt32(message, messagePos, m);
  521. for (int round = 0; round < ROUNDS; round++)
  522. {
  523. // G apply to columns of internalState: m[blake2s_sigma[round][2 * blockPos]] /+1
  524. G(m[blake2s_sigma[round,0]], m[blake2s_sigma[round,1]], 0, 4, 8, 12);
  525. G(m[blake2s_sigma[round,2]], m[blake2s_sigma[round,3]], 1, 5, 9, 13);
  526. G(m[blake2s_sigma[round,4]], m[blake2s_sigma[round,5]], 2, 6, 10, 14);
  527. G(m[blake2s_sigma[round,6]], m[blake2s_sigma[round,7]], 3, 7, 11, 15);
  528. // G apply to diagonals of internalState:
  529. G(m[blake2s_sigma[round,8]], m[blake2s_sigma[round,9]], 0, 5, 10, 15);
  530. G(m[blake2s_sigma[round,10]], m[blake2s_sigma[round,11]], 1, 6, 11, 12);
  531. G(m[blake2s_sigma[round,12]], m[blake2s_sigma[round,13]], 2, 7, 8, 13);
  532. G(m[blake2s_sigma[round,14]], m[blake2s_sigma[round,15]], 3, 4, 9, 14);
  533. }
  534. // update chain values:
  535. for (int offset = 0; offset < chainValue.Length; offset++)
  536. {
  537. chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8];
  538. }
  539. }
  540. #endif
  541. #if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
  542. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  543. #endif
  544. private void G(uint m1, uint m2, int posA, int posB, int posC, int posD)
  545. {
  546. internalState[posA] = internalState[posA] + internalState[posB] + m1;
  547. internalState[posD] = Integers.RotateRight(internalState[posD] ^ internalState[posA], 16);
  548. internalState[posC] = internalState[posC] + internalState[posD];
  549. internalState[posB] = Integers.RotateRight(internalState[posB] ^ internalState[posC], 12);
  550. internalState[posA] = internalState[posA] + internalState[posB] + m2;
  551. internalState[posD] = Integers.RotateRight(internalState[posD] ^ internalState[posA], 8);
  552. internalState[posC] = internalState[posC] + internalState[posD];
  553. internalState[posB] = Integers.RotateRight(internalState[posB] ^ internalState[posC], 7);
  554. }
  555. /**
  556. * Return the algorithm name.
  557. *
  558. * @return the algorithm name
  559. */
  560. public string AlgorithmName => "BLAKE2s";
  561. /**
  562. * Return the size in bytes of the digest produced by this message digest.
  563. *
  564. * @return the size in bytes of the digest produced by this message digest.
  565. */
  566. public int GetDigestSize()
  567. {
  568. return digestLength;
  569. }
  570. /**
  571. * Return the size in bytes of the internal buffer the digest applies its
  572. * compression function to.
  573. *
  574. * @return byte length of the digest's internal buffer.
  575. */
  576. public int GetByteLength()
  577. {
  578. return BLOCK_LENGTH_BYTES;
  579. }
  580. /**
  581. * Overwrite the key if it is no longer used (zeroization).
  582. */
  583. public void ClearKey()
  584. {
  585. if (key != null)
  586. {
  587. Array.Clear(key, 0, key.Length);
  588. Array.Clear(buffer, 0, buffer.Length);
  589. }
  590. }
  591. /**
  592. * Overwrite the salt (pepper) if it is secret and no longer used
  593. * (zeroization).
  594. */
  595. public void ClearSalt()
  596. {
  597. if (salt != null)
  598. {
  599. Array.Clear(salt, 0, salt.Length);
  600. }
  601. }
  602. }
  603. }
  604. #pragma warning restore
  605. #endif