CtrSP800Drbg.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders;
  8. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng.Drbg
  9. {
  10. /**
  11. * A SP800-90A CTR DRBG.
  12. */
  13. public sealed class CtrSP800Drbg
  14. : ISP80090Drbg
  15. {
  16. private static readonly long TDEA_RESEED_MAX = 1L << (32 - 1);
  17. private static readonly long AES_RESEED_MAX = 1L << (48 - 1);
  18. private static readonly int TDEA_MAX_BITS_REQUEST = 1 << (13 - 1);
  19. private static readonly int AES_MAX_BITS_REQUEST = 1 << (19 - 1);
  20. private readonly IEntropySource mEntropySource;
  21. private readonly IBlockCipher mEngine;
  22. private readonly int mKeySizeInBits;
  23. private readonly int mSeedLength;
  24. private readonly int mSecurityStrength;
  25. // internal state
  26. private byte[] mKey;
  27. private byte[] mV;
  28. private long mReseedCounter = 0;
  29. private bool mIsTdea = false;
  30. /**
  31. * Construct a SP800-90A CTR DRBG.
  32. * <p>
  33. * Minimum entropy requirement is the security strength requested.
  34. * </p>
  35. * @param engine underlying block cipher to use to support DRBG
  36. * @param keySizeInBits size of the key to use with the block cipher.
  37. * @param securityStrength security strength required (in bits)
  38. * @param entropySource source of entropy to use for seeding/reseeding.
  39. * @param personalizationString personalization string to distinguish this DRBG (may be null).
  40. * @param nonce nonce to further distinguish this DRBG (may be null).
  41. */
  42. public CtrSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource,
  43. byte[] personalizationString, byte[] nonce)
  44. {
  45. if (securityStrength > 256)
  46. throw new ArgumentException("Requested security strength is not supported by the derivation function");
  47. if (GetMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
  48. throw new ArgumentException("Requested security strength is not supported by block cipher and key size");
  49. if (entropySource.EntropySize < securityStrength)
  50. throw new ArgumentException("Not enough entropy for security strength required");
  51. mEntropySource = entropySource;
  52. mEngine = engine;
  53. mKeySizeInBits = keySizeInBits;
  54. mSecurityStrength = securityStrength;
  55. mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
  56. mIsTdea = IsTdea(engine);
  57. CTR_DRBG_Instantiate_algorithm(nonce, personalizationString);
  58. }
  59. private void CTR_DRBG_Instantiate_algorithm(byte[] nonce, byte[] personalisationString)
  60. {
  61. byte[] entropy = GetEntropy(); // Get_entropy_input
  62. byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
  63. byte[] seed = BlockCipherDF(seedMaterial, mSeedLength / 8);
  64. int blockSize = mEngine.GetBlockSize();
  65. mKey = new byte[(mKeySizeInBits + 7) / 8];
  66. mV = new byte[blockSize];
  67. // mKey & mV are modified by this call
  68. CTR_DRBG_Update(seed, mKey, mV);
  69. mReseedCounter = 1;
  70. }
  71. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  72. private void CTR_DRBG_Update(ReadOnlySpan<byte> seed, Span<byte> key, Span<byte> v)
  73. {
  74. int seedLength = seed.Length;
  75. Span<byte> temp = seedLength <= 256
  76. ? stackalloc byte[seedLength]
  77. : new byte[seedLength];
  78. int blockSize = mEngine.GetBlockSize();
  79. Span<byte> block = blockSize <= 64
  80. ? stackalloc byte[blockSize]
  81. : new byte[blockSize];
  82. mEngine.Init(true, ExpandToKeyParameter(key));
  83. for (int i = 0; i * blockSize < seed.Length; ++i)
  84. {
  85. AddOneTo(v);
  86. mEngine.ProcessBlock(v, block);
  87. int bytesToCopy = System.Math.Min(blockSize, temp.Length - i * blockSize);
  88. block[..bytesToCopy].CopyTo(temp[(i * blockSize)..]);
  89. }
  90. XorWith(seed, temp);
  91. key.CopyFrom(temp);
  92. v.CopyFrom(temp[key.Length..]);
  93. }
  94. #else
  95. private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
  96. {
  97. byte[] temp = new byte[seed.Length];
  98. byte[] outputBlock = new byte[mEngine.GetBlockSize()];
  99. int i = 0;
  100. int outLen = mEngine.GetBlockSize();
  101. mEngine.Init(true, ExpandToKeyParameter(key));
  102. while (i * outLen < seed.Length)
  103. {
  104. AddOneTo(v);
  105. mEngine.ProcessBlock(v, 0, outputBlock, 0);
  106. int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen);
  107. Array.Copy(outputBlock, 0, temp, i * outLen, bytesToCopy);
  108. ++i;
  109. }
  110. Xor(temp, seed, temp, 0);
  111. Array.Copy(temp, 0, key, 0, key.Length);
  112. Array.Copy(temp, key.Length, v, 0, v.Length);
  113. }
  114. #endif
  115. private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput)
  116. {
  117. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  118. CTR_DRBG_Reseed_algorithm(Spans.FromNullableReadOnly(additionalInput));
  119. #else
  120. byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput);
  121. seedMaterial = BlockCipherDF(seedMaterial, mSeedLength / 8);
  122. CTR_DRBG_Update(seedMaterial, mKey, mV);
  123. mReseedCounter = 1;
  124. #endif
  125. }
  126. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  127. private void CTR_DRBG_Reseed_algorithm(ReadOnlySpan<byte> additionalInput)
  128. {
  129. int entropyLength = GetEntropyLength();
  130. int seedLength = entropyLength + additionalInput.Length;
  131. Span<byte> seedMaterial = seedLength <= 256
  132. ? stackalloc byte[seedLength]
  133. : new byte[seedLength];
  134. GetEntropy(seedMaterial[..entropyLength]);
  135. additionalInput.CopyTo(seedMaterial[entropyLength..]);
  136. seedMaterial = BlockCipherDF(seedMaterial, mSeedLength / 8);
  137. CTR_DRBG_Update(seedMaterial, mKey, mV);
  138. mReseedCounter = 1;
  139. }
  140. #endif
  141. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  142. private void Xor(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y, Span<byte> z)
  143. {
  144. for (int i = 0; i < z.Length; ++i)
  145. {
  146. z[i] = (byte)(x[i] ^ y[i]);
  147. }
  148. }
  149. private void XorWith(ReadOnlySpan<byte> x, Span<byte> z)
  150. {
  151. for (int i = 0; i < z.Length; ++i)
  152. {
  153. z[i] ^= x[i];
  154. }
  155. }
  156. #else
  157. private void Xor(byte[] output, byte[] a, byte[] b, int bOff)
  158. {
  159. for (int i = 0; i < output.Length; i++)
  160. {
  161. output[i] = (byte)(a[i] ^ b[bOff + i]);
  162. }
  163. }
  164. #endif
  165. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  166. private void AddOneTo(Span<byte> longer)
  167. #else
  168. private void AddOneTo(byte[] longer)
  169. #endif
  170. {
  171. uint carry = 1;
  172. int i = longer.Length;
  173. while (--i >= 0)
  174. {
  175. carry += longer[i];
  176. longer[i] = (byte)carry;
  177. carry >>= 8;
  178. }
  179. }
  180. private byte[] GetEntropy()
  181. {
  182. byte[] entropy = mEntropySource.GetEntropy();
  183. if (entropy.Length < (mSecurityStrength + 7) / 8)
  184. throw new InvalidOperationException("Insufficient entropy provided by entropy source");
  185. return entropy;
  186. }
  187. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  188. private int GetEntropy(Span<byte> output)
  189. {
  190. int length = mEntropySource.GetEntropy(output);
  191. if (length < (mSecurityStrength + 7) / 8)
  192. throw new InvalidOperationException("Insufficient entropy provided by entropy source");
  193. return length;
  194. }
  195. private int GetEntropyLength()
  196. {
  197. return (mEntropySource.EntropySize + 7) / 8;
  198. }
  199. #endif
  200. // -- Internal state migration ---
  201. private static readonly byte[] K_BITS = Hex.DecodeStrict(
  202. "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
  203. // 1. If (number_of_bits_to_return > max_number_of_bits), then return an
  204. // ERROR_FLAG.
  205. // 2. L = len (input_string)/8.
  206. // 3. N = number_of_bits_to_return/8.
  207. // Comment: L is the bitstring represention of
  208. // the integer resulting from len (input_string)/8.
  209. // L shall be represented as a 32-bit integer.
  210. //
  211. // Comment : N is the bitstring represention of
  212. // the integer resulting from
  213. // number_of_bits_to_return/8. N shall be
  214. // represented as a 32-bit integer.
  215. //
  216. // 4. S = L || N || input_string || 0x80.
  217. // 5. While (len (S) mod outlen)
  218. // Comment : Pad S with zeros, if necessary.
  219. // 0, S = S || 0x00.
  220. //
  221. // Comment : Compute the starting value.
  222. // 6. temp = the Null string.
  223. // 7. i = 0.
  224. // 8. K = Leftmost keylen bits of 0x00010203...1D1E1F.
  225. // 9. While len (temp) < keylen + outlen, do
  226. //
  227. // IV = i || 0outlen - len (i).
  228. //
  229. // 9.1
  230. //
  231. // temp = temp || BCC (K, (IV || S)).
  232. //
  233. // 9.2
  234. //
  235. // i = i + 1.
  236. //
  237. // 9.3
  238. //
  239. // Comment : i shall be represented as a 32-bit
  240. // integer, i.e., len (i) = 32.
  241. //
  242. // Comment: The 32-bit integer represenation of
  243. // i is padded with zeros to outlen bits.
  244. //
  245. // Comment: Compute the requested number of
  246. // bits.
  247. //
  248. // 10. K = Leftmost keylen bits of temp.
  249. //
  250. // 11. X = Next outlen bits of temp.
  251. //
  252. // 12. temp = the Null string.
  253. //
  254. // 13. While len (temp) < number_of_bits_to_return, do
  255. //
  256. // 13.1 X = Block_Encrypt (K, X).
  257. //
  258. // 13.2 temp = temp || X.
  259. //
  260. // 14. requested_bits = Leftmost number_of_bits_to_return of temp.
  261. //
  262. // 15. Return SUCCESS and requested_bits.
  263. private byte[] BlockCipherDF(byte[] input, int N)
  264. {
  265. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  266. return BlockCipherDF(input.AsSpan(), N);
  267. #else
  268. int outLen = mEngine.GetBlockSize();
  269. int L = input.Length; // already in bytes
  270. // 4 S = L || N || input || 0x80
  271. int sLen = 4 + 4 + L + 1;
  272. int blockLen = ((sLen + outLen - 1) / outLen) * outLen;
  273. byte[] S = new byte[blockLen];
  274. Pack.UInt32_To_BE((uint)L, S, 0);
  275. Pack.UInt32_To_BE((uint)N, S, 4);
  276. Array.Copy(input, 0, S, 8, L);
  277. S[8 + L] = 0x80;
  278. // S already padded with zeros
  279. byte[] temp = new byte[mKeySizeInBits / 8 + outLen];
  280. byte[] bccOut = new byte[outLen];
  281. byte[] IV = new byte[outLen];
  282. int i = 0;
  283. byte[] K = new byte[mKeySizeInBits / 8];
  284. Array.Copy(K_BITS, 0, K, 0, K.Length);
  285. var K1 = ExpandToKeyParameter(K);
  286. mEngine.Init(true, K1);
  287. while (i*outLen*8 < mKeySizeInBits + outLen *8)
  288. {
  289. Pack.UInt32_To_BE((uint)i, IV, 0);
  290. BCC(bccOut, IV, S);
  291. int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen);
  292. Array.Copy(bccOut, 0, temp, i * outLen, bytesToCopy);
  293. ++i;
  294. }
  295. byte[] X = new byte[outLen];
  296. Array.Copy(temp, 0, K, 0, K.Length);
  297. Array.Copy(temp, K.Length, X, 0, X.Length);
  298. temp = new byte[N];
  299. i = 0;
  300. mEngine.Init(true, ExpandToKeyParameter(K));
  301. while (i * outLen < temp.Length)
  302. {
  303. mEngine.ProcessBlock(X, 0, X, 0);
  304. int bytesToCopy = System.Math.Min(outLen, temp.Length - i * outLen);
  305. Array.Copy(X, 0, temp, i * outLen, bytesToCopy);
  306. i++;
  307. }
  308. return temp;
  309. #endif
  310. }
  311. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  312. private byte[] BlockCipherDF(ReadOnlySpan<byte> input, int N)
  313. {
  314. int blockSize = mEngine.GetBlockSize();
  315. int L = input.Length; // already in bytes
  316. // 4 S = L || N || input || 0x80
  317. int sLen = 4 + 4 + L + 1;
  318. int blockLen = ((sLen + blockSize - 1) / blockSize) * blockSize;
  319. Span<byte> S = blockLen <= 256
  320. ? stackalloc byte[blockLen]
  321. : new byte[blockLen];
  322. Pack.UInt32_To_BE((uint)L, S);
  323. Pack.UInt32_To_BE((uint)N, S[4..]);
  324. input.CopyTo(S[8..]);
  325. S[8 + L] = 0x80;
  326. // S already padded with zeros
  327. int keySize = mKeySizeInBits / 8;
  328. int tempSize = keySize + blockSize;
  329. Span<byte> temp = tempSize <= 128
  330. ? stackalloc byte[tempSize]
  331. : new byte[tempSize];
  332. Span<byte> bccOut = blockSize <= 64
  333. ? stackalloc byte[blockSize]
  334. : new byte[blockSize];
  335. Span<byte> IV = blockSize <= 64
  336. ? stackalloc byte[blockSize]
  337. : new byte[blockSize];
  338. var K1 = ExpandToKeyParameter(K_BITS.AsSpan(0, keySize));
  339. mEngine.Init(true, K1);
  340. for (int i = 0; i * blockSize < tempSize; ++i)
  341. {
  342. Pack.UInt32_To_BE((uint)i, IV);
  343. BCC(bccOut, IV, S);
  344. int bytesToCopy = System.Math.Min(blockSize, tempSize - i * blockSize);
  345. bccOut[..bytesToCopy].CopyTo(temp[(i * blockSize)..]);
  346. }
  347. var K2 = ExpandToKeyParameter(temp[..keySize]);
  348. mEngine.Init(true, K2);
  349. var X = temp[keySize..];
  350. byte[] result = new byte[N];
  351. for (int i = 0; i * blockSize < result.Length; ++i)
  352. {
  353. mEngine.ProcessBlock(X, X);
  354. int bytesToCopy = System.Math.Min(blockSize, result.Length - i * blockSize);
  355. X[..bytesToCopy].CopyTo(result.AsSpan(i * blockSize));
  356. }
  357. return result;
  358. }
  359. #endif
  360. /*
  361. * 1. chaining_value = 0^outlen
  362. * . Comment: Set the first chaining value to outlen zeros.
  363. * 2. n = len (data)/outlen.
  364. * 3. Starting with the leftmost bits of data, split the data into n blocks of outlen bits
  365. * each, forming block(1) to block(n).
  366. * 4. For i = 1 to n do
  367. * 4.1 input_block = chaining_value ^ block(i) .
  368. * 4.2 chaining_value = Block_Encrypt (Key, input_block).
  369. * 5. output_block = chaining_value.
  370. * 6. Return output_block.
  371. */
  372. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  373. private void BCC(Span<byte> bccOut, ReadOnlySpan<byte> iV, ReadOnlySpan<byte> data)
  374. {
  375. int blockSize = mEngine.GetBlockSize();
  376. Span<byte> chainingValue = blockSize <= 64
  377. ? stackalloc byte[blockSize]
  378. : new byte[blockSize];
  379. Span<byte> inputBlock = blockSize <= 64
  380. ? stackalloc byte[blockSize]
  381. : new byte[blockSize];
  382. mEngine.ProcessBlock(iV, chainingValue);
  383. int n = data.Length / blockSize;
  384. for (int i = 0; i < n; i++)
  385. {
  386. Xor(chainingValue, data[(i * blockSize)..], inputBlock);
  387. mEngine.ProcessBlock(inputBlock, chainingValue);
  388. }
  389. bccOut.CopyFrom(chainingValue);
  390. }
  391. #else
  392. private void BCC(byte[] bccOut, byte[] iV, byte[] data)
  393. {
  394. int outlen = mEngine.GetBlockSize();
  395. byte[] chainingValue = new byte[outlen]; // initial values = 0
  396. int n = data.Length / outlen;
  397. byte[] inputBlock = new byte[outlen];
  398. mEngine.ProcessBlock(iV, 0, chainingValue, 0);
  399. for (int i = 0; i < n; i++)
  400. {
  401. Xor(inputBlock, chainingValue, data, i*outlen);
  402. mEngine.ProcessBlock(inputBlock, 0, chainingValue, 0);
  403. }
  404. Array.Copy(chainingValue, 0, bccOut, 0, bccOut.Length);
  405. }
  406. #endif
  407. /**
  408. * Return the block size (in bits) of the DRBG.
  409. *
  410. * @return the number of bits produced on each internal round of the DRBG.
  411. */
  412. public int BlockSize
  413. {
  414. get { return mV.Length * 8; }
  415. }
  416. /**
  417. * Populate a passed in array with random data.
  418. *
  419. * @param output output array for generated bits.
  420. * @param additionalInput additional input to be added to the DRBG in this step.
  421. * @param predictionResistant true if a reseed should be forced, false otherwise.
  422. *
  423. * @return number of bits generated, -1 if a reseed required.
  424. */
  425. public int Generate(byte[] output, int outputOff, int outputLen, byte[] additionalInput,
  426. bool predictionResistant)
  427. {
  428. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  429. return additionalInput == null
  430. ? Generate(output.AsSpan(outputOff, outputLen), predictionResistant)
  431. : GenerateWithInput(output.AsSpan(outputOff, outputLen), additionalInput.AsSpan(), predictionResistant);
  432. #else
  433. if (mIsTdea)
  434. {
  435. if (mReseedCounter > TDEA_RESEED_MAX)
  436. return -1;
  437. if (outputLen > TDEA_MAX_BITS_REQUEST / 8)
  438. throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
  439. }
  440. else
  441. {
  442. if (mReseedCounter > AES_RESEED_MAX)
  443. return -1;
  444. if (outputLen > AES_MAX_BITS_REQUEST / 8)
  445. throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
  446. }
  447. if (predictionResistant)
  448. {
  449. CTR_DRBG_Reseed_algorithm(additionalInput);
  450. additionalInput = null;
  451. }
  452. if (additionalInput != null)
  453. {
  454. additionalInput = BlockCipherDF(additionalInput, mSeedLength / 8);
  455. CTR_DRBG_Update(additionalInput, mKey, mV);
  456. }
  457. else
  458. {
  459. additionalInput = new byte[mSeedLength];
  460. }
  461. byte[] tmp = new byte[mV.Length];
  462. mEngine.Init(true, ExpandToKeyParameter(mKey));
  463. for (int i = 0, limit = outputLen / tmp.Length; i <= limit; i++)
  464. {
  465. int bytesToCopy = System.Math.Min(tmp.Length, outputLen - i * tmp.Length);
  466. if (bytesToCopy != 0)
  467. {
  468. AddOneTo(mV);
  469. mEngine.ProcessBlock(mV, 0, tmp, 0);
  470. Array.Copy(tmp, 0, output, outputOff + i * tmp.Length, bytesToCopy);
  471. }
  472. }
  473. CTR_DRBG_Update(additionalInput, mKey, mV);
  474. mReseedCounter++;
  475. return outputLen * 8;
  476. #endif
  477. }
  478. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  479. public int Generate(Span<byte> output, bool predictionResistant)
  480. {
  481. int outputLen = output.Length;
  482. if (mIsTdea)
  483. {
  484. if (mReseedCounter > TDEA_RESEED_MAX)
  485. return -1;
  486. if (outputLen > TDEA_MAX_BITS_REQUEST / 8)
  487. throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
  488. }
  489. else
  490. {
  491. if (mReseedCounter > AES_RESEED_MAX)
  492. return -1;
  493. if (outputLen > AES_MAX_BITS_REQUEST / 8)
  494. throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
  495. }
  496. if (predictionResistant)
  497. {
  498. CTR_DRBG_Reseed_algorithm(ReadOnlySpan<byte>.Empty);
  499. }
  500. byte[] seed = new byte[mSeedLength / 8];
  501. return ImplGenerate(seed, output);
  502. }
  503. public int GenerateWithInput(Span<byte> output, ReadOnlySpan<byte> additionalInput, bool predictionResistant)
  504. {
  505. int outputLen = output.Length;
  506. if (mIsTdea)
  507. {
  508. if (mReseedCounter > TDEA_RESEED_MAX)
  509. return -1;
  510. if (outputLen > TDEA_MAX_BITS_REQUEST / 8)
  511. throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
  512. }
  513. else
  514. {
  515. if (mReseedCounter > AES_RESEED_MAX)
  516. return -1;
  517. if (outputLen > AES_MAX_BITS_REQUEST / 8)
  518. throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
  519. }
  520. int seedLength = mSeedLength / 8;
  521. byte[] seed;
  522. if (predictionResistant)
  523. {
  524. CTR_DRBG_Reseed_algorithm(additionalInput);
  525. seed = new byte[seedLength];
  526. }
  527. else
  528. {
  529. seed = BlockCipherDF(additionalInput, seedLength);
  530. CTR_DRBG_Update(seed, mKey, mV);
  531. }
  532. return ImplGenerate(seed, output);
  533. }
  534. private int ImplGenerate(ReadOnlySpan<byte> seed, Span<byte> output)
  535. {
  536. byte[] tmp = new byte[mV.Length];
  537. mEngine.Init(true, ExpandToKeyParameter(mKey));
  538. int outputLen = output.Length;
  539. for (int i = 0, limit = outputLen / tmp.Length; i <= limit; i++)
  540. {
  541. int bytesToCopy = System.Math.Min(tmp.Length, outputLen - i * tmp.Length);
  542. if (bytesToCopy != 0)
  543. {
  544. AddOneTo(mV);
  545. mEngine.ProcessBlock(mV, 0, tmp, 0);
  546. tmp[..bytesToCopy].CopyTo(output[(i * tmp.Length)..]);
  547. }
  548. }
  549. CTR_DRBG_Update(seed, mKey, mV);
  550. mReseedCounter++;
  551. return outputLen * 8;
  552. }
  553. #endif
  554. /**
  555. * Reseed the DRBG.
  556. *
  557. * @param additionalInput additional input to be added to the DRBG in this step.
  558. */
  559. public void Reseed(byte[] additionalInput)
  560. {
  561. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  562. Reseed(Spans.FromNullableReadOnly(additionalInput));
  563. #else
  564. CTR_DRBG_Reseed_algorithm(additionalInput);
  565. #endif
  566. }
  567. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  568. public void Reseed(ReadOnlySpan<byte> additionalInput)
  569. {
  570. CTR_DRBG_Reseed_algorithm(additionalInput);
  571. }
  572. #endif
  573. private bool IsTdea(IBlockCipher cipher)
  574. {
  575. return cipher.AlgorithmName.Equals("DESede") || cipher.AlgorithmName.Equals("TDEA");
  576. }
  577. private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
  578. {
  579. if (IsTdea(cipher) && keySizeInBits == 168)
  580. {
  581. return 112;
  582. }
  583. if (cipher.AlgorithmName.Equals("AES"))
  584. {
  585. return keySizeInBits;
  586. }
  587. return -1;
  588. }
  589. private KeyParameter ExpandToKeyParameter(byte[] key)
  590. {
  591. if (!mIsTdea)
  592. return new KeyParameter(key);
  593. // expand key to 192 bits.
  594. byte[] tmp = new byte[24];
  595. PadKey(key, 0, tmp, 0);
  596. PadKey(key, 7, tmp, 8);
  597. PadKey(key, 14, tmp, 16);
  598. return new KeyParameter(tmp);
  599. }
  600. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  601. private KeyParameter ExpandToKeyParameter(ReadOnlySpan<byte> key)
  602. {
  603. if (!mIsTdea)
  604. return new KeyParameter(key);
  605. // expand key to 192 bits.
  606. Span<byte> tmp = stackalloc byte[24];
  607. PadKey(key, tmp);
  608. PadKey(key[7..], tmp[8..]);
  609. PadKey(key[14..], tmp[16..]);
  610. return new KeyParameter(tmp);
  611. }
  612. #endif
  613. /**
  614. * Pad out a key for TDEA, setting odd parity for each byte.
  615. *
  616. * @param keyMaster
  617. * @param keyOff
  618. * @param tmp
  619. * @param tmpOff
  620. */
  621. private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
  622. {
  623. tmp[tmpOff + 0] = (byte)(keyMaster[keyOff + 0] & 0xfe);
  624. tmp[tmpOff + 1] = (byte)((keyMaster[keyOff + 0] << 7) | ((keyMaster[keyOff + 1] & 0xfc) >> 1));
  625. tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xf8) >> 2));
  626. tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xf0) >> 3));
  627. tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xe0) >> 4));
  628. tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xc0) >> 5));
  629. tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >> 6));
  630. tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
  631. DesParameters.SetOddParity(tmp, tmpOff, 8);
  632. }
  633. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  634. private void PadKey(ReadOnlySpan<byte> keyMaster, Span<byte> tmp)
  635. {
  636. tmp[0] = (byte)(keyMaster[0] & 0xFE);
  637. tmp[1] = (byte)((keyMaster[0] << 7) | ((keyMaster[1] & 0xfc) >> 1));
  638. tmp[2] = (byte)((keyMaster[1] << 6) | ((keyMaster[2] & 0xf8) >> 2));
  639. tmp[3] = (byte)((keyMaster[2] << 5) | ((keyMaster[3] & 0xf0) >> 3));
  640. tmp[4] = (byte)((keyMaster[3] << 4) | ((keyMaster[4] & 0xe0) >> 4));
  641. tmp[5] = (byte)((keyMaster[4] << 3) | ((keyMaster[5] & 0xc0) >> 5));
  642. tmp[6] = (byte)((keyMaster[5] << 2) | ((keyMaster[6] & 0x80) >> 6));
  643. tmp[7] = (byte)(keyMaster[6] << 1);
  644. DesParameters.SetOddParity(tmp[..8]);
  645. }
  646. #endif
  647. }
  648. }
  649. #pragma warning restore
  650. #endif