<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />

X931Rng

class X931Rng
using System; namespace Org.BouncyCastle.Crypto.Prng { internal class X931Rng { private const long BLOCK64_RESEED_MAX = 32768; private const long BLOCK128_RESEED_MAX = 8388608; private const int BLOCK64_MAX_BITS_REQUEST = 4096; private const int BLOCK128_MAX_BITS_REQUEST = 262144; 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; internal IEntropySource EntropySource => mEntropySource; internal X931Rng(IBlockCipher engine, byte[] dateTimeVector, IEntropySource entropySource) { mEngine = engine; mEntropySource = entropySource; mDT = new byte[engine.GetBlockSize()]; Array.Copy(dateTimeVector, 0, mDT, 0, mDT.Length); mI = new byte[engine.GetBlockSize()]; mR = new byte[engine.GetBlockSize()]; } internal int Generate(byte[] output, int outputOff, int outputLen, bool predictionResistant) { int num; if (mR.Length == 8) { if (mReseedCounter > 32768) return -1; if (outputLen > 512) { num = 4096; throw new ArgumentException("Number of bits per request limited to " + num.ToString(), "output"); } } else { if (mReseedCounter > 8388608) return -1; if (outputLen > 32768) { num = 262144; throw new ArgumentException("Number of bits per request limited to " + num.ToString(), "output"); } } if (predictionResistant || mV == null) { mV = mEntropySource.GetEntropy(); if (mV.Length != mEngine.GetBlockSize()) throw new InvalidOperationException("Insufficient entropy returned"); } int num2 = outputLen / mR.Length; for (int i = 0; i < num2; i++) { mEngine.ProcessBlock(mDT, 0, mI, 0); Process(mR, mI, mV); Process(mV, mR, mI); Array.Copy(mR, 0, output, outputOff + i * mR.Length, mR.Length); Increment(mDT); } int num3 = outputLen - num2 * mR.Length; if (num3 > 0) { mEngine.ProcessBlock(mDT, 0, mI, 0); Process(mR, mI, mV); Process(mV, mR, mI); Array.Copy(mR, 0, output, outputOff + num2 * mR.Length, num3); Increment(mDT); } mReseedCounter++; return outputLen * 8; } internal void Reseed() { mV = mEntropySource.GetEntropy(); if (mV.Length != mEngine.GetBlockSize()) throw new InvalidOperationException("Insufficient entropy returned"); mReseedCounter = 1; } 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) { int num = val.Length - 1; while (num >= 0 && ++val[num] == 0) { num--; } } } }