ConcatenationKdfGenerator
Generator for Concatenation Key Derivation Function defined in NIST SP 800-56A, Sect 5.8.1
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Agreement.Kdf
{
public sealed class ConcatenationKdfGenerator : IDerivationFunction
{
private readonly IDigest m_digest;
private readonly int m_hLen;
private byte[] m_buffer;
public IDigest Digest => m_digest;
public ConcatenationKdfGenerator(IDigest digest)
{
m_digest = digest;
m_hLen = digest.GetDigestSize();
}
public void Init(IDerivationParameters param)
{
KdfParameters obj = param as KdfParameters;
if (obj == null)
throw new ArgumentException("KDF parameters required for ConcatenationKdfGenerator");
byte[] sharedSecret = obj.GetSharedSecret();
byte[] iV = obj.GetIV();
m_buffer = new byte[4 + sharedSecret.Length + ((iV != null) ? iV.Length : 0) + m_hLen];
sharedSecret.CopyTo(m_buffer, 4);
iV?.CopyTo(m_buffer, 4 + sharedSecret.Length);
}
public int GenerateBytes(byte[] output, int outOff, int length)
{
Check.OutputLength(output, outOff, length, "output buffer too short");
return GenerateBytes(output.AsSpan(outOff, length));
}
public int GenerateBytes(Span<byte> output)
{
int num = m_buffer.Length - m_hLen;
uint num2 = 1;
m_digest.Reset();
int i = 0;
int length = output.Length;
for (int num3 = length - m_hLen; i <= num3; i += m_hLen) {
Pack.UInt32_To_BE(num2++, m_buffer.AsSpan());
m_digest.BlockUpdate(m_buffer.AsSpan(0, num));
IDigest digest = m_digest;
int num5 = i;
digest.DoFinal(output.Slice(num5, output.Length - num5));
}
if (i < length) {
Pack.UInt32_To_BE(num2, m_buffer.AsSpan());
m_digest.BlockUpdate(m_buffer.AsSpan(0, num));
m_digest.DoFinal(m_buffer.AsSpan(num));
Span<byte> span = m_buffer.AsSpan(num, length - i);
int num5 = i;
span.CopyTo(output.Slice(num5, output.Length - num5));
}
return length;
}
}
}