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

KdfFeedbackBytesGenerator

using Org.BouncyCastle.Crypto.Macs; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using System; namespace Org.BouncyCastle.Crypto.Generators { public sealed class KdfFeedbackBytesGenerator : IMacDerivationFunction, IDerivationFunction { private readonly IMac prf; private readonly int h; private byte[] fixedInputData; private int maxSizeExcl; private byte[] ios; private byte[] iv; private bool useCounter; private int generatedBytes; private byte[] k; public IMac Mac => prf; public IDigest Digest => (prf as HMac)?.GetUnderlyingDigest(); public KdfFeedbackBytesGenerator(IMac prf) { this.prf = prf; h = prf.GetMacSize(); k = new byte[h]; } public void Init(IDerivationParameters parameters) { KdfFeedbackParameters kdfFeedbackParameters = parameters as KdfFeedbackParameters; if (kdfFeedbackParameters == null) throw new ArgumentException("Wrong type of arguments given"); prf.Init(new KeyParameter(kdfFeedbackParameters.Ki)); fixedInputData = kdfFeedbackParameters.FixedInputData; int r = kdfFeedbackParameters.R; ios = new byte[r / 8]; if (kdfFeedbackParameters.UseCounter) { BigInteger bigInteger = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h)); maxSizeExcl = ((bigInteger.BitLength > 31) ? 2147483647 : bigInteger.IntValueExact); } else maxSizeExcl = 2147483647; iv = kdfFeedbackParameters.Iv; useCounter = kdfFeedbackParameters.UseCounter; generatedBytes = 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 >= maxSizeExcl - length) throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl.ToString() + " bytes"); int num = generatedBytes % h; Span<byte> span; if (num != 0) { int num2 = System.Math.Min(h - num, output.Length); span = k.AsSpan(num, num2); span.CopyTo(output); generatedBytes += num2; int num3 = num2; output = output.Slice(num3, output.Length - num3); } while (!output.IsEmpty) { GenerateNext(); int num4 = System.Math.Min(h, output.Length); span = k.AsSpan(0, num4); span.CopyTo(output); generatedBytes += num4; int num3 = num4; output = output.Slice(num3, output.Length - num3); } return length; } private void GenerateNext() { if (generatedBytes == 0) prf.BlockUpdate(iv, 0, iv.Length); else prf.BlockUpdate(k, 0, k.Length); if (useCounter) { int num = generatedBytes / h + 1; switch (ios.Length) { case 4: ios[0] = (byte)(num >> 24); goto case 3; case 3: ios[ios.Length - 3] = (byte)(num >> 16); goto case 2; case 2: ios[ios.Length - 2] = (byte)(num >> 8); break; case 1: break; default: throw new InvalidOperationException("Unsupported size of counter i"); } ios[ios.Length - 1] = (byte)num; prf.BlockUpdate(ios, 0, ios.Length); } prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length); prf.DoFinal(k, 0); } } }