X931Rng.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng
  5. {
  6. internal class X931Rng
  7. {
  8. private const long BLOCK64_RESEED_MAX = 1L << (16 - 1);
  9. private const long BLOCK128_RESEED_MAX = 1L << (24 - 1);
  10. private const int BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
  11. private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
  12. private readonly IBlockCipher mEngine;
  13. private readonly IEntropySource mEntropySource;
  14. private readonly byte[] mDT;
  15. private readonly byte[] mI;
  16. private readonly byte[] mR;
  17. private byte[] mV;
  18. private long mReseedCounter = 1;
  19. /**
  20. *
  21. * @param engine
  22. * @param entropySource
  23. */
  24. internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
  25. {
  26. this.mEngine = engine;
  27. this.mEntropySource = entropySource;
  28. this.mDT = new byte[engine.GetBlockSize()];
  29. Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
  30. this.mI = new byte[engine.GetBlockSize()];
  31. this.mR = new byte[engine.GetBlockSize()];
  32. }
  33. /**
  34. * Populate a passed in array with random data.
  35. *
  36. * @param output output array for generated bits.
  37. * @param predictionResistant true if a reseed should be forced, false otherwise.
  38. *
  39. * @return number of bits generated, -1 if a reseed required.
  40. */
  41. internal int Generate(byte[] output, bool predictionResistant)
  42. {
  43. if (mR.Length == 8) // 64 bit block size
  44. {
  45. if (mReseedCounter > BLOCK64_RESEED_MAX)
  46. return -1;
  47. if (IsTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
  48. throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
  49. }
  50. else
  51. {
  52. if (mReseedCounter > BLOCK128_RESEED_MAX)
  53. return -1;
  54. if (IsTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
  55. throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
  56. }
  57. if (predictionResistant || mV == null)
  58. {
  59. mV = mEntropySource.GetEntropy();
  60. if (mV.Length != mEngine.GetBlockSize())
  61. throw new InvalidOperationException("Insufficient entropy returned");
  62. }
  63. int m = output.Length / mR.Length;
  64. for (int i = 0; i < m; i++)
  65. {
  66. mEngine.ProcessBlock(mDT, 0, mI, 0);
  67. Process(mR, mI, mV);
  68. Process(mV, mR, mI);
  69. Array.Copy(mR, 0, output, i * mR.Length, mR.Length);
  70. Increment(mDT);
  71. }
  72. int bytesToCopy = (output.Length - m * mR.Length);
  73. if (bytesToCopy > 0)
  74. {
  75. mEngine.ProcessBlock(mDT, 0, mI, 0);
  76. Process(mR, mI, mV);
  77. Process(mV, mR, mI);
  78. Array.Copy(mR, 0, output, m * mR.Length, bytesToCopy);
  79. Increment(mDT);
  80. }
  81. mReseedCounter++;
  82. return output.Length;
  83. }
  84. /**
  85. * Reseed the RNG.
  86. */
  87. internal void Reseed()
  88. {
  89. mV = mEntropySource.GetEntropy();
  90. if (mV.Length != mEngine.GetBlockSize())
  91. throw new InvalidOperationException("Insufficient entropy returned");
  92. mReseedCounter = 1;
  93. }
  94. internal IEntropySource EntropySource
  95. {
  96. get { return mEntropySource; }
  97. }
  98. private void Process(byte[] res, byte[] a, byte[] b)
  99. {
  100. for (int i = 0; i != res.Length; i++)
  101. {
  102. res[i] = (byte)(a[i] ^ b[i]);
  103. }
  104. mEngine.ProcessBlock(res, 0, res, 0);
  105. }
  106. private void Increment(byte[] val)
  107. {
  108. for (int i = val.Length - 1; i >= 0; i--)
  109. {
  110. if (++val[i] != 0)
  111. break;
  112. }
  113. }
  114. private static bool IsTooLarge(byte[] bytes, int maxBytes)
  115. {
  116. return bytes != null && bytes.Length > maxBytes;
  117. }
  118. }
  119. }
  120. #pragma warning restore
  121. #endif