Blake2sDigest.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  6. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests
  7. {
  8. /*
  9. The BLAKE2 cryptographic hash function was designed by Jean-
  10. Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian
  11. Winnerlein.
  12. Reference Implementation and Description can be found at: https://blake2.net/
  13. RFC: https://tools.ietf.org/html/rfc7693
  14. This implementation does not support the Tree Hashing Mode.
  15. For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based
  16. message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2.
  17. Algorithm | Target | Collision | Hash | Hash ASN.1 |
  18. Identifier | Arch | Security | nn | OID Suffix |
  19. ---------------+--------+-----------+------+------------+
  20. id-blake2s128 | 32-bit | 2**64 | 16 | x.2.4 |
  21. id-blake2s160 | 32-bit | 2**80 | 20 | x.2.5 |
  22. id-blake2s224 | 32-bit | 2**112 | 28 | x.2.7 |
  23. id-blake2s256 | 32-bit | 2**128 | 32 | x.2.8 |
  24. ---------------+--------+-----------+------+------------+
  25. */
  26. /**
  27. * Implementation of the cryptographic hash function BLAKE2s.
  28. * <p/>
  29. * BLAKE2s offers a built-in keying mechanism to be used directly
  30. * for authentication ("Prefix-MAC") rather than a HMAC construction.
  31. * <p/>
  32. * BLAKE2s offers a built-in support for a salt for randomized hashing
  33. * and a personal string for defining a unique hash function for each application.
  34. * <p/>
  35. * BLAKE2s is optimized for 32-bit platforms and produces digests of any size
  36. * between 1 and 32 bytes.
  37. */
  38. public class Blake2sDigest
  39. : IDigest
  40. {
  41. /**
  42. * BLAKE2s Initialization Vector
  43. **/
  44. private static readonly uint[] blake2s_IV =
  45. // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19.
  46. // The same as SHA-256 IV.
  47. {
  48. 0x6a09e667, 0xbb67ae85, 0x3c6ef372,
  49. 0xa54ff53a, 0x510e527f, 0x9b05688c,
  50. 0x1f83d9ab, 0x5be0cd19
  51. };
  52. /**
  53. * Message word permutations
  54. **/
  55. private static readonly byte[,] blake2s_sigma =
  56. {
  57. { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
  58. { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
  59. { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
  60. { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
  61. { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
  62. { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
  63. { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
  64. { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
  65. { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
  66. { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }
  67. };
  68. private const int ROUNDS = 10; // to use for Catenas H'
  69. private const int BLOCK_LENGTH_BYTES = 64;// bytes
  70. // General parameters:
  71. private int digestLength = 32; // 1- 32 bytes
  72. private int keyLength = 0; // 0 - 32 bytes for keyed hashing for MAC
  73. private byte[] salt = null;
  74. private byte[] personalization = null;
  75. private byte[] key = null;
  76. // Tree hashing parameters:
  77. // Because this class does not implement the Tree Hashing Mode,
  78. // these parameters can be treated as constants (see Init() function)
  79. /*
  80. * private int fanout = 1; // 0-255
  81. * private int depth = 1; // 1 - 255
  82. * private int leafLength= 0;
  83. * private long nodeOffset = 0L;
  84. * private int nodeDepth = 0;
  85. * private int innerHashLength = 0;
  86. */
  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.chainValue = Arrays.Clone(digest.chainValue);
  134. this.personalization = Arrays.Clone(digest.personalization);
  135. }
  136. /**
  137. * BLAKE2s for hashing.
  138. *
  139. * @param digestBits the desired digest length in bits. Must be a multiple of 8 and less than 256.
  140. */
  141. public Blake2sDigest(int digestBits)
  142. {
  143. if (digestBits < 8 || digestBits > 256 || digestBits % 8 != 0)
  144. throw new ArgumentException("BLAKE2s digest bit length must be a multiple of 8 and not greater than 256");
  145. buffer = new byte[BLOCK_LENGTH_BYTES];
  146. keyLength = 0;
  147. digestLength = digestBits / 8;
  148. Init();
  149. }
  150. /**
  151. * BLAKE2s for authentication ("Prefix-MAC mode").
  152. * <p/>
  153. * After calling the doFinal() method, the key will remain to be used for
  154. * further computations of this instance. The key can be overwritten using
  155. * the clearKey() method.
  156. *
  157. * @param key a key up to 32 bytes or null
  158. */
  159. public Blake2sDigest(byte[] key)
  160. {
  161. buffer = new byte[BLOCK_LENGTH_BYTES];
  162. if (key != null)
  163. {
  164. if (key.Length > 32)
  165. throw new ArgumentException("Keys > 32 are not supported");
  166. this.key = new byte[key.Length];
  167. Array.Copy(key, 0, this.key, 0, key.Length);
  168. keyLength = key.Length;
  169. Array.Copy(key, 0, buffer, 0, key.Length);
  170. bufferPos = BLOCK_LENGTH_BYTES; // zero padding
  171. }
  172. digestLength = 32;
  173. Init();
  174. }
  175. /**
  176. * BLAKE2s with key, required digest length, salt and personalization.
  177. * <p/>
  178. * After calling the doFinal() method, the key, the salt and the personal
  179. * string will remain and might be used for further computations with this
  180. * instance. The key can be overwritten using the clearKey() method, the
  181. * salt (pepper) can be overwritten using the clearSalt() method.
  182. *
  183. * @param key a key up to 32 bytes or null
  184. * @param digestBytes from 1 up to 32 bytes
  185. * @param salt 8 bytes or null
  186. * @param personalization 8 bytes or null
  187. */
  188. public Blake2sDigest(byte[] key, int digestBytes, byte[] salt,
  189. byte[] personalization)
  190. {
  191. if (digestBytes < 1 || digestBytes > 32)
  192. throw new ArgumentException("Invalid digest length (required: 1 - 32)");
  193. this.digestLength = digestBytes;
  194. this.buffer = new byte[BLOCK_LENGTH_BYTES];
  195. if (salt != null)
  196. {
  197. if (salt.Length != 8)
  198. throw new ArgumentException("Salt length must be exactly 8 bytes");
  199. this.salt = new byte[8];
  200. Array.Copy(salt, 0, this.salt, 0, salt.Length);
  201. }
  202. if (personalization != null)
  203. {
  204. if (personalization.Length != 8)
  205. throw new ArgumentException("Personalization length must be exactly 8 bytes");
  206. this.personalization = new byte[8];
  207. Array.Copy(personalization, 0, this.personalization, 0, personalization.Length);
  208. }
  209. if (key != null)
  210. {
  211. if (key.Length > 32)
  212. throw new ArgumentException("Keys > 32 bytes are not supported");
  213. this.key = new byte[key.Length];
  214. Array.Copy(key, 0, this.key, 0, key.Length);
  215. keyLength = key.Length;
  216. Array.Copy(key, 0, buffer, 0, key.Length);
  217. bufferPos = BLOCK_LENGTH_BYTES; // zero padding
  218. }
  219. Init();
  220. }
  221. // initialize chainValue
  222. private void Init()
  223. {
  224. if (chainValue == null)
  225. {
  226. chainValue = new uint[8];
  227. chainValue[0] = blake2s_IV[0] ^ (uint)(digestLength | (keyLength << 8) | 0x1010000);
  228. // 0x1010000 = ((fanout << 16) | (depth << 24));
  229. // with fanout = 1; depth = 0;
  230. chainValue[1] = blake2s_IV[1];// ^ leafLength; with leafLength = 0;
  231. chainValue[2] = blake2s_IV[2];// ^ nodeOffset; with nodeOffset = 0;
  232. chainValue[3] = blake2s_IV[3];// ^ ( (nodeOffset << 32) | (nodeDepth << 16) | (innerHashLength << 24) );
  233. // with nodeDepth = 0; innerHashLength = 0;
  234. chainValue[4] = blake2s_IV[4];
  235. chainValue[5] = blake2s_IV[5];
  236. if (salt != null)
  237. {
  238. chainValue[4] ^= Pack.LE_To_UInt32(salt, 0);
  239. chainValue[5] ^= Pack.LE_To_UInt32(salt, 4);
  240. }
  241. chainValue[6] = blake2s_IV[6];
  242. chainValue[7] = blake2s_IV[7];
  243. if (personalization != null)
  244. {
  245. chainValue[6] ^= Pack.LE_To_UInt32(personalization, 0);
  246. chainValue[7] ^= Pack.LE_To_UInt32(personalization, 4);
  247. }
  248. }
  249. }
  250. private void InitializeInternalState()
  251. {
  252. // initialize v:
  253. Array.Copy(chainValue, 0, internalState, 0, chainValue.Length);
  254. Array.Copy(blake2s_IV, 0, internalState, chainValue.Length, 4);
  255. internalState[12] = t0 ^ blake2s_IV[4];
  256. internalState[13] = t1 ^ blake2s_IV[5];
  257. internalState[14] = f0 ^ blake2s_IV[6];
  258. internalState[15] = blake2s_IV[7];// ^ f1 with f1 = 0
  259. }
  260. /**
  261. * Update the message digest with a single byte.
  262. *
  263. * @param b the input byte to be entered.
  264. */
  265. public virtual void Update(byte b)
  266. {
  267. int remainingLength; // left bytes of buffer
  268. // process the buffer if full else add to buffer:
  269. remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
  270. if (remainingLength == 0)
  271. { // full buffer
  272. t0 += BLOCK_LENGTH_BYTES;
  273. if (t0 == 0)
  274. { // if message > 2^32
  275. t1++;
  276. }
  277. Compress(buffer, 0);
  278. Array.Clear(buffer, 0, buffer.Length);// clear buffer
  279. buffer[0] = b;
  280. bufferPos = 1;
  281. }
  282. else
  283. {
  284. buffer[bufferPos] = b;
  285. bufferPos++;
  286. }
  287. }
  288. /**
  289. * Update the message digest with a block of bytes.
  290. *
  291. * @param message the byte array containing the data.
  292. * @param offset the offset into the byte array where the data starts.
  293. * @param len the length of the data.
  294. */
  295. public virtual void BlockUpdate(byte[] message, int offset, int len)
  296. {
  297. if (message == null || len == 0)
  298. return;
  299. int remainingLength = 0; // left bytes of buffer
  300. if (bufferPos != 0)
  301. { // commenced, incomplete buffer
  302. // complete the buffer:
  303. remainingLength = BLOCK_LENGTH_BYTES - bufferPos;
  304. if (remainingLength < len)
  305. { // full buffer + at least 1 byte
  306. Array.Copy(message, offset, buffer, bufferPos, remainingLength);
  307. t0 += BLOCK_LENGTH_BYTES;
  308. if (t0 == 0)
  309. { // if message > 2^32
  310. t1++;
  311. }
  312. Compress(buffer, 0);
  313. bufferPos = 0;
  314. Array.Clear(buffer, 0, buffer.Length);// clear buffer
  315. }
  316. else
  317. {
  318. Array.Copy(message, offset, buffer, bufferPos, len);
  319. bufferPos += len;
  320. return;
  321. }
  322. }
  323. // process blocks except last block (also if last block is full)
  324. int messagePos;
  325. int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES;
  326. for (messagePos = offset + remainingLength;
  327. messagePos < blockWiseLastPos;
  328. messagePos += BLOCK_LENGTH_BYTES)
  329. { // block wise 64 bytes
  330. // without buffer:
  331. t0 += BLOCK_LENGTH_BYTES;
  332. if (t0 == 0)
  333. {
  334. t1++;
  335. }
  336. Compress(message, messagePos);
  337. }
  338. // fill the buffer with left bytes, this might be a full block
  339. Array.Copy(message, messagePos, buffer, 0, offset + len
  340. - messagePos);
  341. bufferPos += offset + len - messagePos;
  342. }
  343. /**
  344. * Close the digest, producing the final digest value. The doFinal() call
  345. * leaves the digest reset. Key, salt and personal string remain.
  346. *
  347. * @param out the array the digest is to be copied into.
  348. * @param outOffset the offset into the out array the digest is to start at.
  349. */
  350. public virtual int DoFinal(byte[] output, int outOffset)
  351. {
  352. f0 = 0xFFFFFFFFU;
  353. t0 += (uint)bufferPos;
  354. // bufferPos may be < 64, so (t0 == 0) does not work
  355. // for 2^32 < message length > 2^32 - 63
  356. if ((t0 < 0) && (bufferPos > -t0))
  357. {
  358. t1++;
  359. }
  360. Compress(buffer, 0);
  361. Array.Clear(buffer, 0, buffer.Length);// Holds eventually the key if input is null
  362. Array.Clear(internalState, 0, internalState.Length);
  363. for (int i = 0; i < chainValue.Length && (i * 4 < digestLength); i++)
  364. {
  365. byte[] bytes = Pack.UInt32_To_LE(chainValue[i]);
  366. if (i * 4 < digestLength - 4)
  367. {
  368. Array.Copy(bytes, 0, output, outOffset + i * 4, 4);
  369. }
  370. else
  371. {
  372. Array.Copy(bytes, 0, output, outOffset + i * 4, digestLength - (i * 4));
  373. }
  374. }
  375. Array.Clear(chainValue, 0, chainValue.Length);
  376. Reset();
  377. return digestLength;
  378. }
  379. /**
  380. * Reset the digest back to its initial state. The key, the salt and the
  381. * personal string will remain for further computations.
  382. */
  383. public virtual void Reset()
  384. {
  385. bufferPos = 0;
  386. f0 = 0;
  387. t0 = 0;
  388. t1 = 0;
  389. chainValue = null;
  390. Array.Clear(buffer, 0, buffer.Length);
  391. if (key != null)
  392. {
  393. Array.Copy(key, 0, buffer, 0, key.Length);
  394. bufferPos = BLOCK_LENGTH_BYTES; // zero padding
  395. }
  396. Init();
  397. }
  398. private void Compress(byte[] message, int messagePos)
  399. {
  400. InitializeInternalState();
  401. uint[] m = new uint[16];
  402. for (int j = 0; j < 16; j++)
  403. {
  404. m[j] = Pack.LE_To_UInt32(message, messagePos + j * 4);
  405. }
  406. for (int round = 0; round < ROUNDS; round++)
  407. {
  408. // G apply to columns of internalState:m[blake2s_sigma[round][2 *
  409. // blockPos]] /+1
  410. G(m[blake2s_sigma[round,0]], m[blake2s_sigma[round,1]], 0, 4, 8, 12);
  411. G(m[blake2s_sigma[round,2]], m[blake2s_sigma[round,3]], 1, 5, 9, 13);
  412. G(m[blake2s_sigma[round,4]], m[blake2s_sigma[round,5]], 2, 6, 10, 14);
  413. G(m[blake2s_sigma[round,6]], m[blake2s_sigma[round,7]], 3, 7, 11, 15);
  414. // G apply to diagonals of internalState:
  415. G(m[blake2s_sigma[round,8]], m[blake2s_sigma[round,9]], 0, 5, 10, 15);
  416. G(m[blake2s_sigma[round,10]], m[blake2s_sigma[round,11]], 1, 6, 11, 12);
  417. G(m[blake2s_sigma[round,12]], m[blake2s_sigma[round,13]], 2, 7, 8, 13);
  418. G(m[blake2s_sigma[round,14]], m[blake2s_sigma[round,15]], 3, 4, 9, 14);
  419. }
  420. // update chain values:
  421. for (int offset = 0; offset < chainValue.Length; offset++)
  422. {
  423. chainValue[offset] = chainValue[offset] ^ internalState[offset] ^ internalState[offset + 8];
  424. }
  425. }
  426. private void G(uint m1, uint m2, int posA, int posB, int posC, int posD)
  427. {
  428. internalState[posA] = internalState[posA] + internalState[posB] + m1;
  429. internalState[posD] = rotr32(internalState[posD] ^ internalState[posA], 16);
  430. internalState[posC] = internalState[posC] + internalState[posD];
  431. internalState[posB] = rotr32(internalState[posB] ^ internalState[posC], 12);
  432. internalState[posA] = internalState[posA] + internalState[posB] + m2;
  433. internalState[posD] = rotr32(internalState[posD] ^ internalState[posA], 8);
  434. internalState[posC] = internalState[posC] + internalState[posD];
  435. internalState[posB] = rotr32(internalState[posB] ^ internalState[posC], 7);
  436. }
  437. private uint rotr32(uint x, int rot)
  438. {
  439. return x >> rot | x << -rot;
  440. }
  441. /**
  442. * Return the algorithm name.
  443. *
  444. * @return the algorithm name
  445. */
  446. public virtual string AlgorithmName
  447. {
  448. get { return "BLAKE2s"; }
  449. }
  450. /**
  451. * Return the size in bytes of the digest produced by this message digest.
  452. *
  453. * @return the size in bytes of the digest produced by this message digest.
  454. */
  455. public virtual int GetDigestSize()
  456. {
  457. return digestLength;
  458. }
  459. /**
  460. * Return the size in bytes of the internal buffer the digest applies its
  461. * compression function to.
  462. *
  463. * @return byte length of the digest's internal buffer.
  464. */
  465. public virtual int GetByteLength()
  466. {
  467. return BLOCK_LENGTH_BYTES;
  468. }
  469. /**
  470. * Overwrite the key if it is no longer used (zeroization).
  471. */
  472. public virtual void ClearKey()
  473. {
  474. if (key != null)
  475. {
  476. Array.Clear(key, 0, key.Length);
  477. Array.Clear(buffer, 0, buffer.Length);
  478. }
  479. }
  480. /**
  481. * Overwrite the salt (pepper) if it is secret and no longer used
  482. * (zeroization).
  483. */
  484. public virtual void ClearSalt()
  485. {
  486. if (salt != null)
  487. {
  488. Array.Clear(salt, 0, salt.Length);
  489. }
  490. }
  491. }
  492. }
  493. #pragma warning restore
  494. #endif