123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng
- {
- internal class X931Rng
- {
- private const long BLOCK64_RESEED_MAX = 1L << (16 - 1);
- private const long BLOCK128_RESEED_MAX = 1L << (24 - 1);
- private const int BLOCK64_MAX_BITS_REQUEST = 1 << (13 - 1);
- private const int BLOCK128_MAX_BITS_REQUEST = 1 << (19 - 1);
- private readonly IBlockCipher mEngine;
- private readonly IEntropySource mEntropySource;
- private readonly byte[] mDT;
- private readonly byte[] mI;
- private readonly byte[] mR;
- private byte[] mV;
- private long mReseedCounter = 1;
- /**
- *
- * @param engine
- * @param entropySource
- */
- internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource)
- {
- this.mEngine = engine;
- this.mEntropySource = entropySource;
- this.mDT = new byte[engine.GetBlockSize()];
- Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length);
- this.mI = new byte[engine.GetBlockSize()];
- this.mR = new byte[engine.GetBlockSize()];
- }
- /**
- * Populate a passed in array with random data.
- *
- * @param output output array for generated bits.
- * @param predictionResistant true if a reseed should be forced, false otherwise.
- *
- * @return number of bits generated, -1 if a reseed required.
- */
- internal int Generate(byte[] output, bool predictionResistant)
- {
- if (mR.Length == 8) // 64 bit block size
- {
- if (mReseedCounter > BLOCK64_RESEED_MAX)
- return -1;
- if (IsTooLarge(output, BLOCK64_MAX_BITS_REQUEST / 8))
- throw new ArgumentException("Number of bits per request limited to " + BLOCK64_MAX_BITS_REQUEST, "output");
- }
- else
- {
- if (mReseedCounter > BLOCK128_RESEED_MAX)
- return -1;
- if (IsTooLarge(output, BLOCK128_MAX_BITS_REQUEST / 8))
- throw new ArgumentException("Number of bits per request limited to " + BLOCK128_MAX_BITS_REQUEST, "output");
- }
- if (predictionResistant || mV == null)
- {
- mV = mEntropySource.GetEntropy();
- if (mV.Length != mEngine.GetBlockSize())
- throw new InvalidOperationException("Insufficient entropy returned");
- }
- int m = output.Length / mR.Length;
- for (int i = 0; i < m; i++)
- {
- mEngine.ProcessBlock(mDT, 0, mI, 0);
- Process(mR, mI, mV);
- Process(mV, mR, mI);
- Array.Copy(mR, 0, output, i * mR.Length, mR.Length);
- Increment(mDT);
- }
- int bytesToCopy = (output.Length - m * mR.Length);
- if (bytesToCopy > 0)
- {
- mEngine.ProcessBlock(mDT, 0, mI, 0);
- Process(mR, mI, mV);
- Process(mV, mR, mI);
- Array.Copy(mR, 0, output, m * mR.Length, bytesToCopy);
- Increment(mDT);
- }
- mReseedCounter++;
- return output.Length;
- }
- /**
- * Reseed the RNG.
- */
- internal void Reseed()
- {
- mV = mEntropySource.GetEntropy();
- if (mV.Length != mEngine.GetBlockSize())
- throw new InvalidOperationException("Insufficient entropy returned");
- mReseedCounter = 1;
- }
- internal IEntropySource EntropySource
- {
- get { return mEntropySource; }
- }
- private void Process(byte[] res, byte[] a, byte[] b)
- {
- for (int i = 0; i != res.Length; i++)
- {
- res[i] = (byte)(a[i] ^ b[i]);
- }
- mEngine.ProcessBlock(res, 0, res, 0);
- }
- private void Increment(byte[] val)
- {
- for (int i = val.Length - 1; i >= 0; i--)
- {
- if (++val[i] != 0)
- break;
- }
- }
- private static bool IsTooLarge(byte[] bytes, int maxBytes)
- {
- return bytes != null && bytes.Length > maxBytes;
- }
- }
- }
- #pragma warning restore
- #endif
|