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

HMacSP800Drbg

public sealed class HMacSP800Drbg : ISP80090Drbg
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[] array = Arrays.ConcatenateAll(entropy, nonce, personalizationString); mK = new byte[hMac.GetMacSize()]; mV = new byte[mK.Length]; Arrays.Fill(mV, 1); hmac_DRBG_Update(array); mReseedCounter = 1; } private void hmac_DRBG_Update() { hmac_DRBG_Update_Func(ReadOnlySpan<byte>.Empty, 0); } private void hmac_DRBG_Update(ReadOnlySpan<byte> seedMaterial) { hmac_DRBG_Update_Func(seedMaterial, 0); hmac_DRBG_Update_Func(seedMaterial, 1); } private void hmac_DRBG_Update_Func(ReadOnlySpan<byte> seedMaterial, byte vValue) { mHMac.Init(new KeyParameter(mK)); mHMac.BlockUpdate(mV); mHMac.Update(vValue); if (!seedMaterial.IsEmpty) mHMac.BlockUpdate(seedMaterial); mHMac.DoFinal(mK); mHMac.Init(new KeyParameter(mK)); mHMac.BlockUpdate(mV); mHMac.DoFinal(mV); } public int Generate(byte[] output, int outputOff, int outputLen, byte[] additionalInput, bool predictionResistant) { Span<byte> output2 = output.AsSpan(outputOff, outputLen); if (additionalInput != null) return GenerateWithInput(output2, additionalInput.AsSpan(), predictionResistant); return Generate(output2, predictionResistant); } public int Generate(Span<byte> output, 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.ToString(), "output"); if (mReseedCounter > RESEED_MAX) return -1; if (predictionResistant) Reseed(ReadOnlySpan<byte>.Empty); ImplGenerate(output); hmac_DRBG_Update(); mReseedCounter++; return num; } public int GenerateWithInput(Span<byte> output, ReadOnlySpan<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.ToString(), "output"); if (mReseedCounter > RESEED_MAX) return -1; if (predictionResistant) Reseed(additionalInput); else hmac_DRBG_Update(additionalInput); ImplGenerate(output); if (predictionResistant) hmac_DRBG_Update(); else hmac_DRBG_Update(additionalInput); mReseedCounter++; return num; } private void ImplGenerate(Span<byte> output) { int length = output.Length; int num = length / mV.Length; mHMac.Init(new KeyParameter(mK)); for (int i = 0; i < num; i++) { mHMac.BlockUpdate(mV); mHMac.DoFinal(mV); byte[] source = mV; int num2 = i * mV.Length; source.CopyTo(output.Slice(num2, output.Length - num2)); } int num3 = length - num * mV.Length; if (num3 > 0) { mHMac.BlockUpdate(mV); mHMac.DoFinal(mV); Span<byte> span = mV.AsSpan(0, num3); int num2 = num * mV.Length; span.CopyTo(output.Slice(num2, output.Length - num2)); } } public void Reseed(byte[] additionalInput) { Reseed(Spans.FromNullableReadOnly(additionalInput)); } public unsafe void Reseed(ReadOnlySpan<byte> additionalInput) { int entropyLength = GetEntropyLength(); int num = entropyLength + additionalInput.Length; Span<byte> span; int num2; if (num <= 256) { num2 = num; span = new Span<byte>(stackalloc byte[(int)(uint)num2], num2); } else span = new byte[num]; Span<byte> span2 = span; GetEntropy(span2); num2 = entropyLength; additionalInput.CopyTo(span2.Slice(num2, span2.Length - num2)); hmac_DRBG_Update(span2); 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; } private int GetEntropy(Span<byte> output) { int entropy = mEntropySource.GetEntropy(output); if (entropy < (mSecurityStrength + 7) / 8) throw new InvalidOperationException("Insufficient entropy provided by entropy source"); return entropy; } private int GetEntropyLength() { return (mEntropySource.EntropySize + 7) / 8; } } }