HMacSP800Drbg.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  6. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng.Drbg
  7. {
  8. /**
  9. * A SP800-90A HMAC DRBG.
  10. */
  11. public class HMacSP800Drbg
  12. : ISP80090Drbg
  13. {
  14. private readonly static long RESEED_MAX = 1L << (48 - 1);
  15. private readonly static int MAX_BITS_REQUEST = 1 << (19 - 1);
  16. private readonly byte[] mK;
  17. private readonly byte[] mV;
  18. private readonly IEntropySource mEntropySource;
  19. private readonly IMac mHMac;
  20. private readonly int mSecurityStrength;
  21. private long mReseedCounter;
  22. /**
  23. * Construct a SP800-90A Hash DRBG.
  24. * <p>
  25. * Minimum entropy requirement is the security strength requested.
  26. * </p>
  27. * @param hMac Hash MAC to base the DRBG on.
  28. * @param securityStrength security strength required (in bits)
  29. * @param entropySource source of entropy to use for seeding/reseeding.
  30. * @param personalizationString personalization string to distinguish this DRBG (may be null).
  31. * @param nonce nonce to further distinguish this DRBG (may be null).
  32. */
  33. public HMacSP800Drbg(IMac hMac, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
  34. {
  35. if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(hMac))
  36. throw new ArgumentException("Requested security strength is not supported by the derivation function");
  37. if (entropySource.EntropySize < securityStrength)
  38. throw new ArgumentException("Not enough entropy for security strength required");
  39. mHMac = hMac;
  40. mSecurityStrength = securityStrength;
  41. mEntropySource = entropySource;
  42. byte[] entropy = GetEntropy();
  43. byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
  44. mK = new byte[hMac.GetMacSize()];
  45. mV = new byte[mK.Length];
  46. Arrays.Fill(mV, (byte)1);
  47. hmac_DRBG_Update(seedMaterial);
  48. mReseedCounter = 1;
  49. }
  50. private void hmac_DRBG_Update(byte[] seedMaterial)
  51. {
  52. hmac_DRBG_Update_Func(seedMaterial, (byte)0x00);
  53. if (seedMaterial != null)
  54. {
  55. hmac_DRBG_Update_Func(seedMaterial, (byte)0x01);
  56. }
  57. }
  58. private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue)
  59. {
  60. mHMac.Init(new KeyParameter(mK));
  61. mHMac.BlockUpdate(mV, 0, mV.Length);
  62. mHMac.Update(vValue);
  63. if (seedMaterial != null)
  64. {
  65. mHMac.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
  66. }
  67. mHMac.DoFinal(mK, 0);
  68. mHMac.Init(new KeyParameter(mK));
  69. mHMac.BlockUpdate(mV, 0, mV.Length);
  70. mHMac.DoFinal(mV, 0);
  71. }
  72. /**
  73. * Return the block size (in bits) of the DRBG.
  74. *
  75. * @return the number of bits produced on each round of the DRBG.
  76. */
  77. public int BlockSize
  78. {
  79. get { return mV.Length * 8; }
  80. }
  81. /**
  82. * Populate a passed in array with random data.
  83. *
  84. * @param output output array for generated bits.
  85. * @param additionalInput additional input to be added to the DRBG in this step.
  86. * @param predictionResistant true if a reseed should be forced, false otherwise.
  87. *
  88. * @return number of bits generated, -1 if a reseed required.
  89. */
  90. public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
  91. {
  92. int numberOfBits = output.Length * 8;
  93. if (numberOfBits > MAX_BITS_REQUEST)
  94. throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
  95. if (mReseedCounter > RESEED_MAX)
  96. {
  97. return -1;
  98. }
  99. if (predictionResistant)
  100. {
  101. Reseed(additionalInput);
  102. additionalInput = null;
  103. }
  104. // 2.
  105. if (additionalInput != null)
  106. {
  107. hmac_DRBG_Update(additionalInput);
  108. }
  109. // 3.
  110. byte[] rv = new byte[output.Length];
  111. int m = output.Length / mV.Length;
  112. mHMac.Init(new KeyParameter(mK));
  113. for (int i = 0; i < m; i++)
  114. {
  115. mHMac.BlockUpdate(mV, 0, mV.Length);
  116. mHMac.DoFinal(mV, 0);
  117. Array.Copy(mV, 0, rv, i * mV.Length, mV.Length);
  118. }
  119. if (m * mV.Length < rv.Length)
  120. {
  121. mHMac.BlockUpdate(mV, 0, mV.Length);
  122. mHMac.DoFinal(mV, 0);
  123. Array.Copy(mV, 0, rv, m * mV.Length, rv.Length - (m * mV.Length));
  124. }
  125. hmac_DRBG_Update(additionalInput);
  126. mReseedCounter++;
  127. Array.Copy(rv, 0, output, 0, output.Length);
  128. return numberOfBits;
  129. }
  130. /**
  131. * Reseed the DRBG.
  132. *
  133. * @param additionalInput additional input to be added to the DRBG in this step.
  134. */
  135. public void Reseed(byte[] additionalInput)
  136. {
  137. byte[] entropy = GetEntropy();
  138. byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
  139. hmac_DRBG_Update(seedMaterial);
  140. mReseedCounter = 1;
  141. }
  142. private byte[] GetEntropy()
  143. {
  144. byte[] entropy = mEntropySource.GetEntropy();
  145. if (entropy.Length < (mSecurityStrength + 7) / 8)
  146. throw new InvalidOperationException("Insufficient entropy provided by entropy source");
  147. return entropy;
  148. }
  149. }
  150. }
  151. #pragma warning restore
  152. #endif