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

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; } } }