init commit

This commit is contained in:
2025-10-09 09:57:24 +09:00
commit 4d551bd74f
6636 changed files with 1218703 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Prng;
public class BasicEntropySourceProvider : IEntropySourceProvider
{
private class BasicEntropySource : IEntropySource
{
private readonly SecureRandom mSecureRandom;
private readonly bool mPredictionResistant;
private readonly int mEntropySize;
bool IEntropySource.IsPredictionResistant => mPredictionResistant;
int IEntropySource.EntropySize => mEntropySize;
internal BasicEntropySource(SecureRandom secureRandom, bool predictionResistant, int entropySize)
{
mSecureRandom = secureRandom;
mPredictionResistant = predictionResistant;
mEntropySize = entropySize;
}
byte[] IEntropySource.GetEntropy()
{
return SecureRandom.GetNextBytes(mSecureRandom, (mEntropySize + 7) / 8);
}
}
private readonly SecureRandom mSecureRandom;
private readonly bool mPredictionResistant;
public BasicEntropySourceProvider(SecureRandom secureRandom, bool isPredictionResistant)
{
mSecureRandom = secureRandom;
mPredictionResistant = isPredictionResistant;
}
public IEntropySource Get(int bitsRequired)
{
return new BasicEntropySource(mSecureRandom, mPredictionResistant, bitsRequired);
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Security.Cryptography;
namespace Org.BouncyCastle.Crypto.Prng;
public class CryptoApiEntropySourceProvider : IEntropySourceProvider
{
private class CryptoApiEntropySource : IEntropySource
{
private readonly RandomNumberGenerator mRng;
private readonly bool mPredictionResistant;
private readonly int mEntropySize;
bool IEntropySource.IsPredictionResistant => mPredictionResistant;
int IEntropySource.EntropySize => mEntropySize;
internal CryptoApiEntropySource(RandomNumberGenerator rng, bool predictionResistant, int entropySize)
{
mRng = rng;
mPredictionResistant = predictionResistant;
mEntropySize = entropySize;
}
byte[] IEntropySource.GetEntropy()
{
byte[] array = new byte[(mEntropySize + 7) / 8];
mRng.GetBytes(array);
return array;
}
}
private readonly RandomNumberGenerator mRng;
private readonly bool mPredictionResistant;
public CryptoApiEntropySourceProvider()
: this(RandomNumberGenerator.Create(), isPredictionResistant: true)
{
}
public CryptoApiEntropySourceProvider(RandomNumberGenerator rng, bool isPredictionResistant)
{
if (rng == null)
{
throw new ArgumentNullException("rng");
}
mRng = rng;
mPredictionResistant = isPredictionResistant;
}
public IEntropySource Get(int bitsRequired)
{
return new CryptoApiEntropySource(mRng, mPredictionResistant, bitsRequired);
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Security.Cryptography;
namespace Org.BouncyCastle.Crypto.Prng;
public class CryptoApiRandomGenerator : IRandomGenerator
{
private readonly RandomNumberGenerator rndProv;
public CryptoApiRandomGenerator()
: this(RandomNumberGenerator.Create())
{
}
public CryptoApiRandomGenerator(RandomNumberGenerator rng)
{
rndProv = rng;
}
public virtual void AddSeedMaterial(byte[] seed)
{
}
public virtual void AddSeedMaterial(long seed)
{
}
public virtual void NextBytes(byte[] bytes)
{
rndProv.GetBytes(bytes);
}
public virtual void NextBytes(byte[] bytes, int start, int len)
{
if (start < 0)
{
throw new ArgumentException("Start offset cannot be negative", "start");
}
if (bytes.Length < start + len)
{
throw new ArgumentException("Byte array too small for requested offset and length");
}
if (bytes.Length == len && start == 0)
{
NextBytes(bytes);
return;
}
byte[] array = new byte[len];
NextBytes(array);
Array.Copy(array, 0, bytes, start, len);
}
}

View File

@@ -0,0 +1,107 @@
using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Prng;
public class DigestRandomGenerator : IRandomGenerator
{
private const long CYCLE_COUNT = 10L;
private long stateCounter;
private long seedCounter;
private IDigest digest;
private byte[] state;
private byte[] seed;
public DigestRandomGenerator(IDigest digest)
{
this.digest = digest;
seed = new byte[digest.GetDigestSize()];
seedCounter = 1L;
state = new byte[digest.GetDigestSize()];
stateCounter = 1L;
}
public void AddSeedMaterial(byte[] inSeed)
{
lock (this)
{
DigestUpdate(inSeed);
DigestUpdate(seed);
DigestDoFinal(seed);
}
}
public void AddSeedMaterial(long rSeed)
{
lock (this)
{
DigestAddCounter(rSeed);
DigestUpdate(seed);
DigestDoFinal(seed);
}
}
public void NextBytes(byte[] bytes)
{
NextBytes(bytes, 0, bytes.Length);
}
public void NextBytes(byte[] bytes, int start, int len)
{
lock (this)
{
int num = 0;
GenerateState();
int num2 = start + len;
for (int i = start; i < num2; i++)
{
if (num == state.Length)
{
GenerateState();
num = 0;
}
bytes[i] = state[num++];
}
}
}
private void CycleSeed()
{
DigestUpdate(seed);
DigestAddCounter(seedCounter++);
DigestDoFinal(seed);
}
private void GenerateState()
{
DigestAddCounter(stateCounter++);
DigestUpdate(state);
DigestUpdate(seed);
DigestDoFinal(state);
if (stateCounter % 10 == 0)
{
CycleSeed();
}
}
private void DigestAddCounter(long seedVal)
{
byte[] array = new byte[8];
Pack.UInt64_To_LE((ulong)seedVal, array);
digest.BlockUpdate(array, 0, array.Length);
}
private void DigestUpdate(byte[] inSeed)
{
digest.BlockUpdate(inSeed, 0, inSeed.Length);
}
private void DigestDoFinal(byte[] result)
{
digest.DoFinal(result, 0);
}
}

View File

@@ -0,0 +1,303 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.Utilities.Encoders;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public class CtrSP800Drbg : ISP80090Drbg
{
private static readonly long TDEA_RESEED_MAX = 2147483648L;
private static readonly long AES_RESEED_MAX = 140737488355328L;
private static readonly int TDEA_MAX_BITS_REQUEST = 4096;
private static readonly int AES_MAX_BITS_REQUEST = 262144;
private readonly IEntropySource mEntropySource;
private readonly IBlockCipher mEngine;
private readonly int mKeySizeInBits;
private readonly int mSeedLength;
private readonly int mSecurityStrength;
private byte[] mKey;
private byte[] mV;
private long mReseedCounter = 0L;
private bool mIsTdea = false;
private static readonly byte[] K_BITS = Hex.Decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
public int BlockSize => mV.Length * 8;
public CtrSP800Drbg(IBlockCipher engine, int keySizeInBits, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
if (securityStrength > 256)
{
throw new ArgumentException("Requested security strength is not supported by the derivation function");
}
if (GetMaxSecurityStrength(engine, keySizeInBits) < securityStrength)
{
throw new ArgumentException("Requested security strength is not supported by block cipher and key size");
}
if (entropySource.EntropySize < securityStrength)
{
throw new ArgumentException("Not enough entropy for security strength required");
}
mEntropySource = entropySource;
mEngine = engine;
mKeySizeInBits = keySizeInBits;
mSecurityStrength = securityStrength;
mSeedLength = keySizeInBits + engine.GetBlockSize() * 8;
mIsTdea = IsTdea(engine);
byte[] entropy = GetEntropy();
CTR_DRBG_Instantiate_algorithm(entropy, nonce, personalizationString);
}
private void CTR_DRBG_Instantiate_algorithm(byte[] entropy, byte[] nonce, byte[] personalisationString)
{
byte[] inputString = Arrays.ConcatenateAll(entropy, nonce, personalisationString);
byte[] seed = Block_Cipher_df(inputString, mSeedLength);
int blockSize = mEngine.GetBlockSize();
mKey = new byte[(mKeySizeInBits + 7) / 8];
mV = new byte[blockSize];
CTR_DRBG_Update(seed, mKey, mV);
mReseedCounter = 1L;
}
private void CTR_DRBG_Update(byte[] seed, byte[] key, byte[] v)
{
byte[] array = new byte[seed.Length];
byte[] array2 = new byte[mEngine.GetBlockSize()];
int i = 0;
int blockSize = mEngine.GetBlockSize();
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(key)));
for (; i * blockSize < seed.Length; i++)
{
AddOneTo(v);
mEngine.ProcessBlock(v, 0, array2, 0);
int length = ((array.Length - i * blockSize > blockSize) ? blockSize : (array.Length - i * blockSize));
Array.Copy(array2, 0, array, i * blockSize, length);
}
XOR(array, seed, array, 0);
Array.Copy(array, 0, key, 0, key.Length);
Array.Copy(array, key.Length, v, 0, v.Length);
}
private void CTR_DRBG_Reseed_algorithm(byte[] additionalInput)
{
byte[] inputString = Arrays.Concatenate(GetEntropy(), additionalInput);
inputString = Block_Cipher_df(inputString, mSeedLength);
CTR_DRBG_Update(inputString, mKey, mV);
mReseedCounter = 1L;
}
private void XOR(byte[] output, byte[] a, byte[] b, int bOff)
{
for (int i = 0; i < output.Length; i++)
{
output[i] = (byte)(a[i] ^ b[bOff + i]);
}
}
private void AddOneTo(byte[] longer)
{
uint num = 1u;
int num2 = longer.Length;
while (--num2 >= 0)
{
num += longer[num2];
longer[num2] = (byte)num;
num >>= 8;
}
}
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
{
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
}
return entropy;
}
private byte[] Block_Cipher_df(byte[] inputString, int bitLength)
{
int blockSize = mEngine.GetBlockSize();
int num = inputString.Length;
int value = bitLength / 8;
int num2 = 8 + num + 1;
int num3 = (num2 + blockSize - 1) / blockSize * blockSize;
byte[] array = new byte[num3];
copyIntToByteArray(array, num, 0);
copyIntToByteArray(array, value, 4);
Array.Copy(inputString, 0, array, 8, num);
array[8 + num] = 128;
byte[] array2 = new byte[mKeySizeInBits / 8 + blockSize];
byte[] array3 = new byte[blockSize];
byte[] array4 = new byte[blockSize];
int i = 0;
byte[] array5 = new byte[mKeySizeInBits / 8];
Array.Copy(K_BITS, 0, array5, 0, array5.Length);
for (; i * blockSize * 8 < mKeySizeInBits + blockSize * 8; i++)
{
copyIntToByteArray(array4, i, 0);
BCC(array3, array5, array4, array);
int length = ((array2.Length - i * blockSize > blockSize) ? blockSize : (array2.Length - i * blockSize));
Array.Copy(array3, 0, array2, i * blockSize, length);
}
byte[] array6 = new byte[blockSize];
Array.Copy(array2, 0, array5, 0, array5.Length);
Array.Copy(array2, array5.Length, array6, 0, array6.Length);
array2 = new byte[bitLength / 2];
i = 0;
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(array5)));
for (; i * blockSize < array2.Length; i++)
{
mEngine.ProcessBlock(array6, 0, array6, 0);
int length2 = ((array2.Length - i * blockSize > blockSize) ? blockSize : (array2.Length - i * blockSize));
Array.Copy(array6, 0, array2, i * blockSize, length2);
}
return array2;
}
private void BCC(byte[] bccOut, byte[] k, byte[] iV, byte[] data)
{
int blockSize = mEngine.GetBlockSize();
byte[] array = new byte[blockSize];
int num = data.Length / blockSize;
byte[] array2 = new byte[blockSize];
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(k)));
mEngine.ProcessBlock(iV, 0, array, 0);
for (int i = 0; i < num; i++)
{
XOR(array2, array, data, i * blockSize);
mEngine.ProcessBlock(array2, 0, array, 0);
}
Array.Copy(array, 0, bccOut, 0, bccOut.Length);
}
private void copyIntToByteArray(byte[] buf, int value, int offSet)
{
buf[offSet] = (byte)(value >> 24);
buf[offSet + 1] = (byte)(value >> 16);
buf[offSet + 2] = (byte)(value >> 8);
buf[offSet + 3] = (byte)value;
}
public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
if (mIsTdea)
{
if (mReseedCounter > TDEA_RESEED_MAX)
{
return -1;
}
if (DrbgUtilities.IsTooLarge(output, TDEA_MAX_BITS_REQUEST / 8))
{
throw new ArgumentException("Number of bits per request limited to " + TDEA_MAX_BITS_REQUEST, "output");
}
}
else
{
if (mReseedCounter > AES_RESEED_MAX)
{
return -1;
}
if (DrbgUtilities.IsTooLarge(output, AES_MAX_BITS_REQUEST / 8))
{
throw new ArgumentException("Number of bits per request limited to " + AES_MAX_BITS_REQUEST, "output");
}
}
if (predictionResistant)
{
CTR_DRBG_Reseed_algorithm(additionalInput);
additionalInput = null;
}
if (additionalInput != null)
{
additionalInput = Block_Cipher_df(additionalInput, mSeedLength);
CTR_DRBG_Update(additionalInput, mKey, mV);
}
else
{
additionalInput = new byte[mSeedLength];
}
byte[] array = new byte[mV.Length];
mEngine.Init(forEncryption: true, new KeyParameter(ExpandKey(mKey)));
for (int i = 0; i <= output.Length / array.Length; i++)
{
int num = ((output.Length - i * array.Length > array.Length) ? array.Length : (output.Length - i * mV.Length));
if (num != 0)
{
AddOneTo(mV);
mEngine.ProcessBlock(mV, 0, array, 0);
Array.Copy(array, 0, output, i * array.Length, num);
}
}
CTR_DRBG_Update(additionalInput, mKey, mV);
mReseedCounter++;
return output.Length * 8;
}
public void Reseed(byte[] additionalInput)
{
CTR_DRBG_Reseed_algorithm(additionalInput);
}
private bool IsTdea(IBlockCipher cipher)
{
if (!cipher.AlgorithmName.Equals("DESede"))
{
return cipher.AlgorithmName.Equals("TDEA");
}
return true;
}
private int GetMaxSecurityStrength(IBlockCipher cipher, int keySizeInBits)
{
if (IsTdea(cipher) && keySizeInBits == 168)
{
return 112;
}
if (cipher.AlgorithmName.Equals("AES"))
{
return keySizeInBits;
}
return -1;
}
private byte[] ExpandKey(byte[] key)
{
if (mIsTdea)
{
byte[] array = new byte[24];
PadKey(key, 0, array, 0);
PadKey(key, 7, array, 8);
PadKey(key, 14, array, 16);
return array;
}
return key;
}
private void PadKey(byte[] keyMaster, int keyOff, byte[] tmp, int tmpOff)
{
tmp[tmpOff] = (byte)(keyMaster[keyOff] & 0xFE);
tmp[tmpOff + 1] = (byte)((keyMaster[keyOff] << 7) | ((keyMaster[keyOff + 1] & 0xFC) >> 1));
tmp[tmpOff + 2] = (byte)((keyMaster[keyOff + 1] << 6) | ((keyMaster[keyOff + 2] & 0xF8) >> 2));
tmp[tmpOff + 3] = (byte)((keyMaster[keyOff + 2] << 5) | ((keyMaster[keyOff + 3] & 0xF0) >> 3));
tmp[tmpOff + 4] = (byte)((keyMaster[keyOff + 3] << 4) | ((keyMaster[keyOff + 4] & 0xE0) >> 4));
tmp[tmpOff + 5] = (byte)((keyMaster[keyOff + 4] << 3) | ((keyMaster[keyOff + 5] & 0xC0) >> 5));
tmp[tmpOff + 6] = (byte)((keyMaster[keyOff + 5] << 2) | ((keyMaster[keyOff + 6] & 0x80) >> 6));
tmp[tmpOff + 7] = (byte)(keyMaster[keyOff + 6] << 1);
DesParameters.SetOddParity(tmp, tmpOff, 8);
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
internal class DrbgUtilities
{
private static readonly IDictionary maxSecurityStrengths;
static DrbgUtilities()
{
maxSecurityStrengths = Platform.CreateHashtable();
maxSecurityStrengths.Add("SHA-1", 128);
maxSecurityStrengths.Add("SHA-224", 192);
maxSecurityStrengths.Add("SHA-256", 256);
maxSecurityStrengths.Add("SHA-384", 256);
maxSecurityStrengths.Add("SHA-512", 256);
maxSecurityStrengths.Add("SHA-512/224", 192);
maxSecurityStrengths.Add("SHA-512/256", 256);
}
internal static int GetMaxSecurityStrength(IDigest d)
{
return (int)maxSecurityStrengths[d.AlgorithmName];
}
internal static int GetMaxSecurityStrength(IMac m)
{
string algorithmName = m.AlgorithmName;
return (int)maxSecurityStrengths[algorithmName.Substring(0, algorithmName.IndexOf("/"))];
}
internal static byte[] HashDF(IDigest digest, byte[] seedMaterial, int seedLength)
{
byte[] array = new byte[(seedLength + 7) / 8];
int num = array.Length / digest.GetDigestSize();
int num2 = 1;
byte[] array2 = new byte[digest.GetDigestSize()];
for (int i = 0; i <= num; i++)
{
digest.Update((byte)num2);
digest.Update((byte)(seedLength >> 24));
digest.Update((byte)(seedLength >> 16));
digest.Update((byte)(seedLength >> 8));
digest.Update((byte)seedLength);
digest.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
digest.DoFinal(array2, 0);
int length = ((array.Length - i * array2.Length > array2.Length) ? array2.Length : (array.Length - i * array2.Length));
Array.Copy(array2, 0, array, i * array2.Length, length);
num2++;
}
if (seedLength % 8 != 0)
{
int num3 = 8 - seedLength % 8;
uint num4 = 0u;
for (int j = 0; j != array.Length; j++)
{
uint num5 = array[j];
array[j] = (byte)((num5 >> num3) | (num4 << 8 - num3));
num4 = num5;
}
}
return array;
}
internal static bool IsTooLarge(byte[] bytes, int maxBytes)
{
if (bytes != null)
{
return bytes.Length > maxBytes;
}
return false;
}
}

View File

@@ -0,0 +1,131 @@
using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public class HMacSP800Drbg : ISP80090Drbg
{
private static readonly long RESEED_MAX = 140737488355328L;
private static readonly int MAX_BITS_REQUEST = 262144;
private readonly byte[] mK;
private readonly byte[] mV;
private readonly IEntropySource mEntropySource;
private readonly IMac mHMac;
private readonly int mSecurityStrength;
private long mReseedCounter;
public int BlockSize => mV.Length * 8;
public HMacSP800Drbg(IMac hMac, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(hMac))
{
throw new ArgumentException("Requested security strength is not supported by the derivation function");
}
if (entropySource.EntropySize < securityStrength)
{
throw new ArgumentException("Not enough entropy for security strength required");
}
mHMac = hMac;
mSecurityStrength = securityStrength;
mEntropySource = entropySource;
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
mK = new byte[hMac.GetMacSize()];
mV = new byte[mK.Length];
Arrays.Fill(mV, 1);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1L;
}
private void hmac_DRBG_Update(byte[] seedMaterial)
{
hmac_DRBG_Update_Func(seedMaterial, 0);
if (seedMaterial != null)
{
hmac_DRBG_Update_Func(seedMaterial, 1);
}
}
private void hmac_DRBG_Update_Func(byte[] seedMaterial, byte vValue)
{
mHMac.Init(new KeyParameter(mK));
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.Update(vValue);
if (seedMaterial != null)
{
mHMac.BlockUpdate(seedMaterial, 0, seedMaterial.Length);
}
mHMac.DoFinal(mK, 0);
mHMac.Init(new KeyParameter(mK));
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
}
public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
int num = output.Length * 8;
if (num > MAX_BITS_REQUEST)
{
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
}
if (mReseedCounter > RESEED_MAX)
{
return -1;
}
if (predictionResistant)
{
Reseed(additionalInput);
additionalInput = null;
}
if (additionalInput != null)
{
hmac_DRBG_Update(additionalInput);
}
byte[] array = new byte[output.Length];
int num2 = output.Length / mV.Length;
mHMac.Init(new KeyParameter(mK));
for (int i = 0; i < num2; i++)
{
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
Array.Copy(mV, 0, array, i * mV.Length, mV.Length);
}
if (num2 * mV.Length < array.Length)
{
mHMac.BlockUpdate(mV, 0, mV.Length);
mHMac.DoFinal(mV, 0);
Array.Copy(mV, 0, array, num2 * mV.Length, array.Length - num2 * mV.Length);
}
hmac_DRBG_Update(additionalInput);
mReseedCounter++;
Array.Copy(array, 0, output, 0, output.Length);
return num;
}
public void Reseed(byte[] additionalInput)
{
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.Concatenate(entropy, additionalInput);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1L;
}
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
{
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
}
return entropy;
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Collections;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public class HashSP800Drbg : ISP80090Drbg
{
private static readonly byte[] ONE;
private static readonly long RESEED_MAX;
private static readonly int MAX_BITS_REQUEST;
private static readonly IDictionary seedlens;
private readonly IDigest mDigest;
private readonly IEntropySource mEntropySource;
private readonly int mSecurityStrength;
private readonly int mSeedLength;
private byte[] mV;
private byte[] mC;
private long mReseedCounter;
public int BlockSize => mDigest.GetDigestSize() * 8;
static HashSP800Drbg()
{
ONE = new byte[1] { 1 };
RESEED_MAX = 140737488355328L;
MAX_BITS_REQUEST = 262144;
seedlens = Platform.CreateHashtable();
seedlens.Add("SHA-1", 440);
seedlens.Add("SHA-224", 440);
seedlens.Add("SHA-256", 440);
seedlens.Add("SHA-512/256", 440);
seedlens.Add("SHA-512/224", 440);
seedlens.Add("SHA-384", 888);
seedlens.Add("SHA-512", 888);
}
public HashSP800Drbg(IDigest digest, int securityStrength, IEntropySource entropySource, byte[] personalizationString, byte[] nonce)
{
if (securityStrength > DrbgUtilities.GetMaxSecurityStrength(digest))
{
throw new ArgumentException("Requested security strength is not supported by the derivation function");
}
if (entropySource.EntropySize < securityStrength)
{
throw new ArgumentException("Not enough entropy for security strength required");
}
mDigest = digest;
mEntropySource = entropySource;
mSecurityStrength = securityStrength;
mSeedLength = (int)seedlens[digest.AlgorithmName];
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString);
byte[] array = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
mV = array;
byte[] array2 = new byte[mV.Length + 1];
Array.Copy(mV, 0, array2, 1, mV.Length);
mC = DrbgUtilities.HashDF(mDigest, array2, mSeedLength);
mReseedCounter = 1L;
}
public int Generate(byte[] output, byte[] additionalInput, bool predictionResistant)
{
int num = output.Length * 8;
if (num > MAX_BITS_REQUEST)
{
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST, "output");
}
if (mReseedCounter > RESEED_MAX)
{
return -1;
}
if (predictionResistant)
{
Reseed(additionalInput);
additionalInput = null;
}
if (additionalInput != null)
{
byte[] array = new byte[1 + mV.Length + additionalInput.Length];
array[0] = 2;
Array.Copy(mV, 0, array, 1, mV.Length);
Array.Copy(additionalInput, 0, array, 1 + mV.Length, additionalInput.Length);
byte[] shorter = Hash(array);
AddTo(mV, shorter);
}
byte[] sourceArray = hashgen(mV, num);
byte[] array2 = new byte[mV.Length + 1];
Array.Copy(mV, 0, array2, 1, mV.Length);
array2[0] = 3;
byte[] shorter2 = Hash(array2);
AddTo(mV, shorter2);
AddTo(mV, mC);
AddTo(shorter: new byte[4]
{
(byte)(mReseedCounter >> 24),
(byte)(mReseedCounter >> 16),
(byte)(mReseedCounter >> 8),
(byte)mReseedCounter
}, longer: mV);
mReseedCounter++;
Array.Copy(sourceArray, 0, output, 0, output.Length);
return num;
}
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
{
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
}
return entropy;
}
private void AddTo(byte[] longer, byte[] shorter)
{
int num = longer.Length - shorter.Length;
uint num2 = 0u;
int num3 = shorter.Length;
while (--num3 >= 0)
{
num2 += (uint)(longer[num + num3] + shorter[num3]);
longer[num + num3] = (byte)num2;
num2 >>= 8;
}
num3 = num;
while (--num3 >= 0)
{
num2 += longer[num3];
longer[num3] = (byte)num2;
num2 >>= 8;
}
}
public void Reseed(byte[] additionalInput)
{
byte[] entropy = GetEntropy();
byte[] seedMaterial = Arrays.ConcatenateAll(ONE, mV, entropy, additionalInput);
byte[] array = DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength);
mV = array;
byte[] array2 = new byte[mV.Length + 1];
array2[0] = 0;
Array.Copy(mV, 0, array2, 1, mV.Length);
mC = DrbgUtilities.HashDF(mDigest, array2, mSeedLength);
mReseedCounter = 1L;
}
private byte[] Hash(byte[] input)
{
byte[] array = new byte[mDigest.GetDigestSize()];
DoHash(input, array);
return array;
}
private void DoHash(byte[] input, byte[] output)
{
mDigest.BlockUpdate(input, 0, input.Length);
mDigest.DoFinal(output, 0);
}
private byte[] hashgen(byte[] input, int lengthInBits)
{
int digestSize = mDigest.GetDigestSize();
int num = lengthInBits / 8 / digestSize;
byte[] array = new byte[input.Length];
Array.Copy(input, 0, array, 0, input.Length);
byte[] array2 = new byte[lengthInBits / 8];
byte[] array3 = new byte[mDigest.GetDigestSize()];
for (int i = 0; i <= num; i++)
{
DoHash(array, array3);
int length = ((array2.Length - i * array3.Length > array3.Length) ? array3.Length : (array2.Length - i * array3.Length));
Array.Copy(array3, 0, array2, i * array3.Length, length);
AddTo(array, ONE);
}
return array2;
}
}

View File

@@ -0,0 +1,10 @@
namespace Org.BouncyCastle.Crypto.Prng.Drbg;
public interface ISP80090Drbg
{
int BlockSize { get; }
int Generate(byte[] output, byte[] additionalInput, bool predictionResistant);
void Reseed(byte[] additionalInput);
}

View File

@@ -0,0 +1,19 @@
using System;
namespace Org.BouncyCastle.Crypto.Prng;
public abstract class EntropyUtilities
{
public static byte[] GenerateSeed(IEntropySource entropySource, int numBytes)
{
byte[] array = new byte[numBytes];
int num;
for (int i = 0; i < numBytes; i += num)
{
byte[] entropy = entropySource.GetEntropy();
num = System.Math.Min(array.Length, numBytes - i);
Array.Copy(entropy, 0, array, i, num);
}
return array;
}
}

View File

@@ -0,0 +1,8 @@
using Org.BouncyCastle.Crypto.Prng.Drbg;
namespace Org.BouncyCastle.Crypto.Prng;
internal interface IDrbgProvider
{
ISP80090Drbg Get(IEntropySource entropySource);
}

View File

@@ -0,0 +1,12 @@
namespace Org.BouncyCastle.Crypto.Prng;
public interface IRandomGenerator
{
void AddSeedMaterial(byte[] seed);
void AddSeedMaterial(long seed);
void NextBytes(byte[] bytes);
void NextBytes(byte[] bytes, int start, int len);
}

View File

@@ -0,0 +1,71 @@
using System;
namespace Org.BouncyCastle.Crypto.Prng;
public class ReversedWindowGenerator : IRandomGenerator
{
private readonly IRandomGenerator generator;
private byte[] window;
private int windowCount;
public ReversedWindowGenerator(IRandomGenerator generator, int windowSize)
{
if (generator == null)
{
throw new ArgumentNullException("generator");
}
if (windowSize < 2)
{
throw new ArgumentException("Window size must be at least 2", "windowSize");
}
this.generator = generator;
window = new byte[windowSize];
}
public virtual void AddSeedMaterial(byte[] seed)
{
lock (this)
{
windowCount = 0;
generator.AddSeedMaterial(seed);
}
}
public virtual void AddSeedMaterial(long seed)
{
lock (this)
{
windowCount = 0;
generator.AddSeedMaterial(seed);
}
}
public virtual void NextBytes(byte[] bytes)
{
doNextBytes(bytes, 0, bytes.Length);
}
public virtual void NextBytes(byte[] bytes, int start, int len)
{
doNextBytes(bytes, start, len);
}
private void doNextBytes(byte[] bytes, int start, int len)
{
lock (this)
{
int num = 0;
while (num < len)
{
if (windowCount < 1)
{
generator.NextBytes(window, 0, window.Length);
windowCount = window.Length;
}
bytes[start + num++] = window[--windowCount];
}
}
}
}

View File

@@ -0,0 +1,89 @@
using System;
using Org.BouncyCastle.Crypto.Prng.Drbg;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Prng;
public class SP800SecureRandom : SecureRandom
{
private readonly IDrbgProvider mDrbgProvider;
private readonly bool mPredictionResistant;
private readonly SecureRandom mRandomSource;
private readonly IEntropySource mEntropySource;
private ISP80090Drbg mDrbg;
internal SP800SecureRandom(SecureRandom randomSource, IEntropySource entropySource, IDrbgProvider drbgProvider, bool predictionResistant)
: base((IRandomGenerator)null)
{
mRandomSource = randomSource;
mEntropySource = entropySource;
mDrbgProvider = drbgProvider;
mPredictionResistant = predictionResistant;
}
public override void SetSeed(byte[] seed)
{
lock (this)
{
if (mRandomSource != null)
{
mRandomSource.SetSeed(seed);
}
}
}
public override void SetSeed(long seed)
{
lock (this)
{
if (mRandomSource != null)
{
mRandomSource.SetSeed(seed);
}
}
}
public override void NextBytes(byte[] bytes)
{
lock (this)
{
if (mDrbg == null)
{
mDrbg = mDrbgProvider.Get(mEntropySource);
}
if (mDrbg.Generate(bytes, null, mPredictionResistant) < 0)
{
mDrbg.Reseed(null);
mDrbg.Generate(bytes, null, mPredictionResistant);
}
}
}
public override void NextBytes(byte[] buf, int off, int len)
{
byte[] array = new byte[len];
NextBytes(array);
Array.Copy(array, 0, buf, off, len);
}
public override byte[] GenerateSeed(int numBytes)
{
return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
}
public virtual void Reseed(byte[] additionalInput)
{
lock (this)
{
if (mDrbg == null)
{
mDrbg = mDrbgProvider.Get(mEntropySource);
}
mDrbg.Reseed(additionalInput);
}
}
}

View File

@@ -0,0 +1,142 @@
using Org.BouncyCastle.Crypto.Prng.Drbg;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Prng;
public class SP800SecureRandomBuilder
{
private class HashDrbgProvider : IDrbgProvider
{
private readonly IDigest mDigest;
private readonly byte[] mNonce;
private readonly byte[] mPersonalizationString;
private readonly int mSecurityStrength;
public HashDrbgProvider(IDigest digest, byte[] nonce, byte[] personalizationString, int securityStrength)
{
mDigest = digest;
mNonce = nonce;
mPersonalizationString = personalizationString;
mSecurityStrength = securityStrength;
}
public ISP80090Drbg Get(IEntropySource entropySource)
{
return new HashSP800Drbg(mDigest, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
}
}
private class HMacDrbgProvider : IDrbgProvider
{
private readonly IMac mHMac;
private readonly byte[] mNonce;
private readonly byte[] mPersonalizationString;
private readonly int mSecurityStrength;
public HMacDrbgProvider(IMac hMac, byte[] nonce, byte[] personalizationString, int securityStrength)
{
mHMac = hMac;
mNonce = nonce;
mPersonalizationString = personalizationString;
mSecurityStrength = securityStrength;
}
public ISP80090Drbg Get(IEntropySource entropySource)
{
return new HMacSP800Drbg(mHMac, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
}
}
private class CtrDrbgProvider : IDrbgProvider
{
private readonly IBlockCipher mBlockCipher;
private readonly int mKeySizeInBits;
private readonly byte[] mNonce;
private readonly byte[] mPersonalizationString;
private readonly int mSecurityStrength;
public CtrDrbgProvider(IBlockCipher blockCipher, int keySizeInBits, byte[] nonce, byte[] personalizationString, int securityStrength)
{
mBlockCipher = blockCipher;
mKeySizeInBits = keySizeInBits;
mNonce = nonce;
mPersonalizationString = personalizationString;
mSecurityStrength = securityStrength;
}
public ISP80090Drbg Get(IEntropySource entropySource)
{
return new CtrSP800Drbg(mBlockCipher, mKeySizeInBits, mSecurityStrength, entropySource, mPersonalizationString, mNonce);
}
}
private readonly SecureRandom mRandom;
private readonly IEntropySourceProvider mEntropySourceProvider;
private byte[] mPersonalizationString = null;
private int mSecurityStrength = 256;
private int mEntropyBitsRequired = 256;
public SP800SecureRandomBuilder()
: this(new SecureRandom(), predictionResistant: false)
{
}
public SP800SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
{
mRandom = entropySource;
mEntropySourceProvider = new BasicEntropySourceProvider(entropySource, predictionResistant);
}
public SP800SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
{
mRandom = null;
mEntropySourceProvider = entropySourceProvider;
}
public SP800SecureRandomBuilder SetPersonalizationString(byte[] personalizationString)
{
mPersonalizationString = personalizationString;
return this;
}
public SP800SecureRandomBuilder SetSecurityStrength(int securityStrength)
{
mSecurityStrength = securityStrength;
return this;
}
public SP800SecureRandomBuilder SetEntropyBitsRequired(int entropyBitsRequired)
{
mEntropyBitsRequired = entropyBitsRequired;
return this;
}
public SP800SecureRandom BuildHash(IDigest digest, byte[] nonce, bool predictionResistant)
{
return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired), new HashDrbgProvider(digest, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
}
public SP800SecureRandom BuildCtr(IBlockCipher cipher, int keySizeInBits, byte[] nonce, bool predictionResistant)
{
return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired), new CtrDrbgProvider(cipher, keySizeInBits, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
}
public SP800SecureRandom BuildHMac(IMac hMac, byte[] nonce, bool predictionResistant)
{
return new SP800SecureRandom(mRandom, mEntropySourceProvider.Get(mEntropyBitsRequired), new HMacDrbgProvider(hMac, nonce, mPersonalizationString, mSecurityStrength), predictionResistant);
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Threading;
namespace Org.BouncyCastle.Crypto.Prng;
public class ThreadedSeedGenerator
{
private class SeedGenerator
{
private volatile int counter = 0;
private volatile bool stop = false;
private void Run(object ignored)
{
while (!stop)
{
counter++;
}
}
public byte[] GenerateSeed(int numBytes, bool fast)
{
ThreadPriority priority = Thread.CurrentThread.Priority;
try
{
Thread.CurrentThread.Priority = ThreadPriority.Normal;
return DoGenerateSeed(numBytes, fast);
}
finally
{
Thread.CurrentThread.Priority = priority;
}
}
private byte[] DoGenerateSeed(int numBytes, bool fast)
{
counter = 0;
stop = false;
byte[] array = new byte[numBytes];
int num = 0;
int num2 = (fast ? numBytes : (numBytes * 8));
ThreadPool.QueueUserWorkItem(Run);
for (int i = 0; i < num2; i++)
{
while (counter == num)
{
try
{
Thread.Sleep(1);
}
catch (Exception)
{
}
}
num = counter;
if (fast)
{
array[i] = (byte)num;
continue;
}
int num3 = i / 8;
array[num3] = (byte)((array[num3] << 1) | (num & 1));
}
stop = true;
return array;
}
}
public byte[] GenerateSeed(int numBytes, bool fast)
{
return new SeedGenerator().GenerateSeed(numBytes, fast);
}
}

View File

@@ -0,0 +1,79 @@
using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Prng;
public class VmpcRandomGenerator : IRandomGenerator
{
private byte n = 0;
private byte[] P = new byte[256]
{
187, 44, 98, 127, 181, 170, 212, 13, 129, 254,
178, 130, 203, 160, 161, 8, 24, 113, 86, 232,
73, 2, 16, 196, 222, 53, 165, 236, 128, 18,
184, 105, 218, 47, 117, 204, 162, 9, 54, 3,
97, 45, 253, 224, 221, 5, 67, 144, 173, 200,
225, 175, 87, 155, 76, 216, 81, 174, 80, 133,
60, 10, 228, 243, 156, 38, 35, 83, 201, 131,
151, 70, 177, 153, 100, 49, 119, 213, 29, 214,
120, 189, 94, 176, 138, 34, 56, 248, 104, 43,
42, 197, 211, 247, 188, 111, 223, 4, 229, 149,
62, 37, 134, 166, 11, 143, 241, 36, 14, 215,
64, 179, 207, 126, 6, 21, 154, 77, 28, 163,
219, 50, 146, 88, 17, 39, 244, 89, 208, 78,
106, 23, 91, 172, 255, 7, 192, 101, 121, 252,
199, 205, 118, 66, 93, 231, 58, 52, 122, 48,
40, 15, 115, 1, 249, 209, 210, 25, 233, 145,
185, 90, 237, 65, 109, 180, 195, 158, 191, 99,
250, 31, 51, 96, 71, 137, 240, 150, 26, 95,
147, 61, 55, 75, 217, 168, 193, 27, 246, 57,
139, 183, 12, 32, 206, 136, 110, 182, 116, 142,
141, 22, 41, 242, 135, 245, 235, 112, 227, 251,
85, 159, 198, 68, 74, 69, 125, 226, 107, 92,
108, 102, 169, 140, 238, 132, 19, 167, 30, 157,
220, 103, 72, 186, 46, 230, 164, 171, 124, 148,
0, 33, 239, 234, 190, 202, 114, 79, 82, 152,
63, 194, 20, 123, 59, 84
};
private byte s = 190;
public virtual void AddSeedMaterial(byte[] seed)
{
for (int i = 0; i < seed.Length; i++)
{
s = P[(s + P[n & 0xFF] + seed[i]) & 0xFF];
byte b = P[n & 0xFF];
P[n & 0xFF] = P[s & 0xFF];
P[s & 0xFF] = b;
n = (byte)((n + 1) & 0xFF);
}
}
public virtual void AddSeedMaterial(long seed)
{
AddSeedMaterial(Pack.UInt64_To_BE((ulong)seed));
}
public virtual void NextBytes(byte[] bytes)
{
NextBytes(bytes, 0, bytes.Length);
}
public virtual void NextBytes(byte[] bytes, int start, int len)
{
lock (P)
{
int num = start + len;
for (int i = start; i != num; i++)
{
s = P[(s + P[n & 0xFF]) & 0xFF];
bytes[i] = P[(P[P[s & 0xFF] & 0xFF] + 1) & 0xFF];
byte b = P[n & 0xFF];
P[n & 0xFF] = P[s & 0xFF];
P[s & 0xFF] = b;
n = (byte)((n + 1) & 0xFF);
}
}
}
}

View File

@@ -0,0 +1,137 @@
using System;
namespace Org.BouncyCastle.Crypto.Prng;
internal class X931Rng
{
private const long BLOCK64_RESEED_MAX = 32768L;
private const long BLOCK128_RESEED_MAX = 8388608L;
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 = 1L;
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, bool predictionResistant)
{
if (mR.Length == 8)
{
if (mReseedCounter > 32768)
{
return -1;
}
if (IsTooLarge(output, 512))
{
throw new ArgumentException("Number of bits per request limited to " + 4096, "output");
}
}
else
{
if (mReseedCounter > 8388608)
{
return -1;
}
if (IsTooLarge(output, 32768))
{
throw new ArgumentException("Number of bits per request limited to " + 262144, "output");
}
}
if (predictionResistant || mV == null)
{
mV = mEntropySource.GetEntropy();
if (mV.Length != mEngine.GetBlockSize())
{
throw new InvalidOperationException("Insufficient entropy returned");
}
}
int num = output.Length / mR.Length;
for (int i = 0; i < num; 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 num2 = output.Length - num * mR.Length;
if (num2 > 0)
{
mEngine.ProcessBlock(mDT, 0, mI, 0);
Process(mR, mI, mV);
Process(mV, mR, mI);
Array.Copy(mR, 0, output, num * mR.Length, num2);
Increment(mDT);
}
mReseedCounter++;
return output.Length;
}
internal void Reseed()
{
mV = mEntropySource.GetEntropy();
if (mV.Length != mEngine.GetBlockSize())
{
throw new InvalidOperationException("Insufficient entropy returned");
}
mReseedCounter = 1L;
}
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 num = val.Length - 1; num >= 0; num--)
{
byte[] array2;
byte[] array = (array2 = val);
int num2 = num;
nint num3 = num2;
if ((array[num2] = (byte)(array2[num3] + 1)) != 0)
{
break;
}
}
}
private static bool IsTooLarge(byte[] bytes, int maxBytes)
{
if (bytes != null)
{
return bytes.Length > maxBytes;
}
return false;
}
}

View File

@@ -0,0 +1,67 @@
using System;
using Org.BouncyCastle.Security;
namespace Org.BouncyCastle.Crypto.Prng;
public class X931SecureRandom : SecureRandom
{
private readonly bool mPredictionResistant;
private readonly SecureRandom mRandomSource;
private readonly X931Rng mDrbg;
internal X931SecureRandom(SecureRandom randomSource, X931Rng drbg, bool predictionResistant)
: base((IRandomGenerator)null)
{
mRandomSource = randomSource;
mDrbg = drbg;
mPredictionResistant = predictionResistant;
}
public override void SetSeed(byte[] seed)
{
lock (this)
{
if (mRandomSource != null)
{
mRandomSource.SetSeed(seed);
}
}
}
public override void SetSeed(long seed)
{
lock (this)
{
if (mRandomSource != null)
{
mRandomSource.SetSeed(seed);
}
}
}
public override void NextBytes(byte[] bytes)
{
lock (this)
{
if (mDrbg.Generate(bytes, mPredictionResistant) < 0)
{
mDrbg.Reseed();
mDrbg.Generate(bytes, mPredictionResistant);
}
}
}
public override void NextBytes(byte[] buf, int off, int len)
{
byte[] array = new byte[len];
NextBytes(array);
Array.Copy(array, 0, buf, off, len);
}
public override byte[] GenerateSeed(int numBytes)
{
return EntropyUtilities.GenerateSeed(mDrbg.EntropySource, numBytes);
}
}

View File

@@ -0,0 +1,49 @@
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Date;
namespace Org.BouncyCastle.Crypto.Prng;
public class X931SecureRandomBuilder
{
private readonly SecureRandom mRandom;
private IEntropySourceProvider mEntropySourceProvider;
private byte[] mDateTimeVector;
public X931SecureRandomBuilder()
: this(new SecureRandom(), predictionResistant: false)
{
}
public X931SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
{
mRandom = entropySource;
mEntropySourceProvider = new BasicEntropySourceProvider(mRandom, predictionResistant);
}
public X931SecureRandomBuilder(IEntropySourceProvider entropySourceProvider)
{
mRandom = null;
mEntropySourceProvider = entropySourceProvider;
}
public X931SecureRandomBuilder SetDateTimeVector(byte[] dateTimeVector)
{
mDateTimeVector = dateTimeVector;
return this;
}
public X931SecureRandom Build(IBlockCipher engine, KeyParameter key, bool predictionResistant)
{
if (mDateTimeVector == null)
{
mDateTimeVector = new byte[engine.GetBlockSize()];
Pack.UInt64_To_BE((ulong)DateTimeUtilities.CurrentUnixMs(), mDateTimeVector, 0);
}
engine.Init(forEncryption: true, key);
return new X931SecureRandom(mRandom, new X931Rng(engine, mDateTimeVector, mEntropySourceProvider.Get(engine.GetBlockSize() * 8)), predictionResistant);
}
}