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(Span<byte> output, bool predictionResistant)
{
int length = output.Length;
int num;
if (mR.Length == 8) {
if (mReseedCounter > 32768)
return -1;
if (length > 512) {
num = 4096;
throw new ArgumentException("Number of bits per request limited to " + num.ToString(), "output");
}
} else {
if (mReseedCounter > 8388608)
return -1;
if (length > 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 = length / mR.Length;
for (int i = 0; i < num2; i++) {
mEngine.ProcessBlock(mDT, mI);
Process(mR, mI, mV);
Process(mV, mR, mI);
byte[] source = mR;
num = i * mR.Length;
source.CopyTo(output.Slice(num, output.Length - num));
Increment(mDT);
}
int num3 = length - num2 * mR.Length;
if (num3 > 0) {
mEngine.ProcessBlock(mDT, mI);
Process(mR, mI, mV);
Process(mV, mR, mI);
Span<byte> span = mR.AsSpan(0, num3);
num = num2 * mR.Length;
span.CopyTo(output.Slice(num, output.Length - num));
Increment(mDT);
}
mReseedCounter++;
return length * 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--;
}
}
}
}