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

KdfCounterBytesGenerator

using Org.BouncyCastle.Crypto.Macs; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using System; namespace Org.BouncyCastle.Crypto.Generators { public sealed class KdfCounterBytesGenerator : IMacDerivationFunction, IDerivationFunction { private readonly IMac prf; private readonly int h; private byte[] fixedInputDataCtrPrefix; private byte[] fixedInputData_afterCtr; private int maxSizeExcl; private byte[] ios; private int generatedBytes; private byte[] k; public IMac Mac => prf; public IDigest Digest => (prf as HMac)?.GetUnderlyingDigest(); public KdfCounterBytesGenerator(IMac prf) { this.prf = prf; h = prf.GetMacSize(); k = new byte[h]; } public void Init(IDerivationParameters param) { KdfCounterParameters kdfCounterParameters = param as KdfCounterParameters; if (kdfCounterParameters == null) throw new ArgumentException("Wrong type of arguments given"); prf.Init(new KeyParameter(kdfCounterParameters.Ki)); fixedInputDataCtrPrefix = kdfCounterParameters.FixedInputDataCounterPrefix; fixedInputData_afterCtr = kdfCounterParameters.FixedInputDataCounterSuffix; int r = kdfCounterParameters.R; ios = new byte[r / 8]; BigInteger bigInteger = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h)); maxSizeExcl = ((bigInteger.BitLength > 31) ? 2147483647 : bigInteger.IntValueExact); 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() { 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); goto case 1; case 1: ios[ios.Length - 1] = (byte)num; prf.BlockUpdate(fixedInputDataCtrPrefix, 0, fixedInputDataCtrPrefix.Length); prf.BlockUpdate(ios, 0, ios.Length); prf.BlockUpdate(fixedInputData_afterCtr, 0, fixedInputData_afterCtr.Length); prf.DoFinal(k, 0); break; default: throw new InvalidOperationException("Unsupported size of counter i"); } } } }