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

HashSP800Drbg

public sealed class HashSP800Drbg : ISP80090Drbg
using Org.BouncyCastle.Crypto.Utilities; using Org.BouncyCastle.Utilities; using System; using System.Collections.Generic; namespace Org.BouncyCastle.Crypto.Prng.Drbg { public sealed 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<string, int> 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 = 140737488355328; MAX_BITS_REQUEST = 262144; SeedLens = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase); 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 = SeedLens[digest.AlgorithmName]; byte[] entropy = GetEntropy(); byte[] seedMaterial = Arrays.ConcatenateAll(entropy, nonce, personalizationString); mV = new byte[(mSeedLength + 7) / 8]; DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength, mV); byte[] array = new byte[mV.Length + 1]; Array.Copy(mV, 0, array, 1, mV.Length); mC = new byte[(mSeedLength + 7) / 8]; DrbgUtilities.HashDF(mDigest, array, mSeedLength, mC); mReseedCounter = 1; } 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) { 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, outputLen); byte[] array2 = new byte[mV.Length + 1]; Array.Copy(mV, 0, array2, 1, mV.Length); array2[0] = 3; AddTo(shorter: Hash(array2), longer: mV); AddTo(mV, mC); byte[] array3 = new byte[4]; Pack.UInt32_To_BE((uint)mReseedCounter, array3); AddTo(mV, array3); mReseedCounter++; Array.Copy(sourceArray, 0, output, outputOff, outputLen); 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 = 0; int num3 = shorter.Length; while (--num3 >= 0) { num2 = (uint)((int)num2 + (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); DrbgUtilities.HashDF(mDigest, seedMaterial, mSeedLength, mV); byte[] array = new byte[mV.Length + 1]; array[0] = 0; Array.Copy(mV, 0, array, 1, mV.Length); DrbgUtilities.HashDF(mDigest, array, mSeedLength, mC); mReseedCounter = 1; } private void DoHash(byte[] input, byte[] output) { mDigest.BlockUpdate(input, 0, input.Length); mDigest.DoFinal(output, 0); } private byte[] Hash(byte[] input) { byte[] array = new byte[mDigest.GetDigestSize()]; DoHash(input, array); return array; } private byte[] Hashgen(byte[] input, int length) { int digestSize = mDigest.GetDigestSize(); int num = length / digestSize; byte[] array = (byte[])input.Clone(); byte[] array2 = new byte[length]; byte[] array3 = new byte[digestSize]; for (int i = 0; i <= num; i++) { DoHash(array, array3); int length2 = System.Math.Min(digestSize, length - i * digestSize); Array.Copy(array3, 0, array2, i * digestSize, length2); AddTo(array, ONE); } return array2; } } }