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

KdfDoublePipelineIterationBytesGenerator

using Org.BouncyCastle.Crypto.Macs; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using System; namespace Org.BouncyCastle.Crypto.Generators { public sealed class KdfDoublePipelineIterationBytesGenerator : IMacDerivationFunction, IDerivationFunction { private readonly IMac prf; private readonly int h; private byte[] fixedInputData; private int maxSizeExcl; private byte[] ios; private bool useCounter; private int generatedBytes; private byte[] a; private byte[] k; public IMac Mac => prf; public IDigest Digest => (prf as HMac)?.GetUnderlyingDigest(); public KdfDoublePipelineIterationBytesGenerator(IMac prf) { this.prf = prf; h = prf.GetMacSize(); a = new byte[h]; k = new byte[h]; } public void Init(IDerivationParameters parameters) { KdfDoublePipelineIterationParameters kdfDoublePipelineIterationParameters = parameters as KdfDoublePipelineIterationParameters; if (kdfDoublePipelineIterationParameters == null) throw new ArgumentException("Wrong type of arguments given"); prf.Init(new KeyParameter(kdfDoublePipelineIterationParameters.Ki)); fixedInputData = kdfDoublePipelineIterationParameters.FixedInputData; int r = kdfDoublePipelineIterationParameters.R; ios = new byte[r / 8]; if (kdfDoublePipelineIterationParameters.UseCounter) { BigInteger bigInteger = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h)); maxSizeExcl = ((bigInteger.BitLength > 31) ? 2147483647 : bigInteger.IntValueExact); } else maxSizeExcl = 2147483647; useCounter = kdfDoublePipelineIterationParameters.UseCounter; generatedBytes = 0; } public int GenerateBytes(byte[] output, int outOff, int length) { if (generatedBytes >= maxSizeExcl - length) throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl.ToString() + " bytes"); int num = length; int num2 = generatedBytes % h; if (num2 != 0) { int num3 = System.Math.Min(h - num2, num); Array.Copy(k, num2, output, outOff, num3); generatedBytes += num3; num -= num3; outOff += num3; } while (num > 0) { GenerateNext(); int num4 = System.Math.Min(h, num); Array.Copy(k, 0, output, outOff, num4); generatedBytes += num4; num -= num4; outOff += num4; } return length; } private void GenerateNext() { if (generatedBytes == 0) { prf.BlockUpdate(fixedInputData, 0, fixedInputData.Length); prf.DoFinal(a, 0); } else { prf.BlockUpdate(a, 0, a.Length); prf.DoFinal(a, 0); } prf.BlockUpdate(a, 0, a.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); } } }