KdfDoublePipelineIterationBytesGenerator
public sealed class KdfDoublePipelineIterationBytesGenerator : IMacDerivationFunction, IDerivationFunction
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)
{
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) {
GenerateNext();
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(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);
}
}
}