HMacSP800Drbg
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Prng.Drbg
{
public sealed class HMacSP800Drbg : ISP80090Drbg
{
private static readonly long RESEED_MAX = 140737488355328;
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 = 1;
}
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, int outputOff, int outputLen, byte[] additionalInput, bool predictionResistant)
{
int num = outputLen * 8;
if (num > MAX_BITS_REQUEST)
throw new ArgumentException("Number of bits per request limited to " + MAX_BITS_REQUEST.ToString(), "output");
if (mReseedCounter > RESEED_MAX)
return -1;
if (predictionResistant) {
Reseed(additionalInput);
additionalInput = null;
}
if (additionalInput != null)
hmac_DRBG_Update(additionalInput);
byte[] array = new byte[outputLen];
int num2 = outputLen / 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, outputOff, outputLen);
return num;
}
public void Reseed(byte[] additionalInput)
{
byte[] seedMaterial = Arrays.Concatenate(GetEntropy(), additionalInput);
hmac_DRBG_Update(seedMaterial);
mReseedCounter = 1;
}
private byte[] GetEntropy()
{
byte[] entropy = mEntropySource.GetEntropy();
if (entropy.Length < (mSecurityStrength + 7) / 8)
throw new InvalidOperationException("Insufficient entropy provided by entropy source");
return entropy;
}
}
}