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

HkdfBytesGenerator

public sealed class HkdfBytesGenerator : IDerivationFunction
using Org.BouncyCastle.Crypto.Macs; using Org.BouncyCastle.Crypto.Parameters; using System; namespace Org.BouncyCastle.Crypto.Generators { public sealed class HkdfBytesGenerator : IDerivationFunction { private HMac hMacHash; private int hashLen; private byte[] info; private byte[] currentT; private int generatedBytes; public IDigest Digest => hMacHash.GetUnderlyingDigest(); public HkdfBytesGenerator(IDigest hash) { hMacHash = new HMac(hash); hashLen = hash.GetDigestSize(); } public void Init(IDerivationParameters parameters) { HkdfParameters hkdfParameters = parameters as HkdfParameters; if (hkdfParameters == null) throw new ArgumentException("HKDF parameters required for HkdfBytesGenerator", "parameters"); if (hkdfParameters.SkipExtract) hMacHash.Init(new KeyParameter(hkdfParameters.GetIkm())); else hMacHash.Init(Extract(hkdfParameters.GetSalt(), hkdfParameters.GetIkm())); info = hkdfParameters.GetInfo(); generatedBytes = 0; currentT = new byte[hashLen]; } private KeyParameter Extract(byte[] salt, byte[] ikm) { if (salt == null) hMacHash.Init(new KeyParameter(new byte[hashLen])); else hMacHash.Init(new KeyParameter(salt)); hMacHash.BlockUpdate(ikm, 0, ikm.Length); byte[] array = new byte[hashLen]; hMacHash.DoFinal(array, 0); return new KeyParameter(array); } private void ExpandNext() { int num = generatedBytes / hashLen + 1; if (num >= 256) throw new DataLengthException("HKDF cannot generate more than 255 blocks of HashLen size"); if (generatedBytes != 0) hMacHash.BlockUpdate(currentT, 0, hashLen); hMacHash.BlockUpdate(info, 0, info.Length); hMacHash.Update((byte)num); hMacHash.DoFinal(currentT, 0); } public int GenerateBytes(byte[] output, int outOff, int length) { return GenerateBytes(output.AsSpan(outOff, length)); } public int GenerateBytes(Span<byte> output) { int length = output.Length; if (generatedBytes > 255 * hashLen - length) throw new DataLengthException("HKDF may only be used for 255 * HashLen bytes of output"); int num = generatedBytes % hashLen; Span<byte> span; if (num != 0) { int num2 = System.Math.Min(hashLen - num, output.Length); span = currentT.AsSpan(num, num2); span.CopyTo(output); generatedBytes += num2; int num3 = num2; output = output.Slice(num3, output.Length - num3); } while (!output.IsEmpty) { ExpandNext(); int num4 = System.Math.Min(hashLen, output.Length); span = currentT.AsSpan(0, num4); span.CopyTo(output); generatedBytes += num4; int num3 = num4; output = output.Slice(num3, output.Length - num3); } return length; } } }