From f8ada894d0a9760cc9c3333e33a6de33124bb495 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Fri, 30 Sep 2022 13:40:07 +0700 Subject: Derivation function work - Add span-based variant of IDerivationFunction.GenerateBytes - IMacDerivation.GetMac() => Mac property - Refactor implementations --- crypto/src/crypto/IDerivationFunction.cs | 11 +- crypto/src/crypto/IMacDerivationFunction.cs | 7 +- .../agreement/kdf/ConcatenationKdfGenerator.cs | 130 +++++++++-------- crypto/src/crypto/agreement/kdf/DHKekGenerator.cs | 118 +++++++++++---- .../src/crypto/agreement/kdf/ECDHKekGenerator.cs | 36 +++-- .../src/crypto/generators/BaseKdfBytesGenerator.cs | 110 ++++++++++---- crypto/src/crypto/generators/HKdfBytesGenerator.cs | 78 ++++++---- .../crypto/generators/KDFCounterBytesGenerator.cs | 134 +++++++++-------- .../KDFDoublePipelineIterationBytesGenerator.cs | 135 +++++++++-------- .../crypto/generators/KDFFeedbackBytesGenerator.cs | 130 +++++++++-------- crypto/src/crypto/generators/Kdf1BytesGenerator.cs | 9 +- crypto/src/crypto/generators/Kdf2BytesGenerator.cs | 7 +- crypto/src/crypto/generators/Mgf1BytesGenerator.cs | 159 ++++++++++----------- crypto/src/crypto/parameters/KdfParameters.cs | 20 ++- crypto/src/crypto/parameters/MgfParameters.cs | 35 +++-- 15 files changed, 656 insertions(+), 463 deletions(-) diff --git a/crypto/src/crypto/IDerivationFunction.cs b/crypto/src/crypto/IDerivationFunction.cs index 7f289f790..9c0228ab0 100644 --- a/crypto/src/crypto/IDerivationFunction.cs +++ b/crypto/src/crypto/IDerivationFunction.cs @@ -12,13 +12,12 @@ namespace Org.BouncyCastle.Crypto /** * return the message digest used as the basis for the function */ - IDigest Digest - { - get; - } + IDigest Digest { get; } int GenerateBytes(byte[] output, int outOff, int length); - //throws DataLengthException, ArgumentException; - } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + int GenerateBytes(Span output); +#endif + } } diff --git a/crypto/src/crypto/IMacDerivationFunction.cs b/crypto/src/crypto/IMacDerivationFunction.cs index 7297cd854..354524e5a 100644 --- a/crypto/src/crypto/IMacDerivationFunction.cs +++ b/crypto/src/crypto/IMacDerivationFunction.cs @@ -1,7 +1,8 @@ namespace Org.BouncyCastle.Crypto { - public interface IMacDerivationFunction:IDerivationFunction + public interface IMacDerivationFunction + : IDerivationFunction { - IMac GetMac(); + IMac Mac { get; } } -} \ No newline at end of file +} diff --git a/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs b/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs index d88f4dfdb..207c795da 100644 --- a/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs +++ b/crypto/src/crypto/agreement/kdf/ConcatenationKdfGenerator.cs @@ -5,96 +5,110 @@ using Org.BouncyCastle.Crypto.Utilities; namespace Org.BouncyCastle.Crypto.Agreement.Kdf { - /** - * Generator for Concatenation Key Derivation Function defined in NIST SP 800-56A, Sect 5.8.1 - */ - public class ConcatenationKdfGenerator + /// Generator for Concatenation Key Derivation Function defined in NIST SP 800-56A, Sect 5.8.1 + public sealed class ConcatenationKdfGenerator : IDerivationFunction { - private readonly IDigest mDigest; + private readonly IDigest m_digest; + private readonly int m_hLen; - private byte[] mShared; - private byte[] mOtherInfo; - private int mHLen; + private byte[] m_buffer; - /** - * @param digest the digest to be used as the source of generated bytes - */ + /// the digest to be used as the source of generated bytes public ConcatenationKdfGenerator(IDigest digest) { - this.mDigest = digest; - this.mHLen = digest.GetDigestSize(); + m_digest = digest; + m_hLen = digest.GetDigestSize(); } - public virtual void Init(IDerivationParameters param) + public void Init(IDerivationParameters param) { - if (!(param is KdfParameters)) + if (!(param is KdfParameters kdfParameters)) throw new ArgumentException("KDF parameters required for ConcatenationKdfGenerator"); - KdfParameters p = (KdfParameters)param; + byte[] sharedSecret = kdfParameters.GetSharedSecret(); + byte[] otherInfo = kdfParameters.GetIV(); - mShared = p.GetSharedSecret(); - mOtherInfo = p.GetIV(); + m_buffer = new byte[4 + sharedSecret.Length + otherInfo.Length + m_hLen]; + sharedSecret.CopyTo(m_buffer, 4); + otherInfo.CopyTo(m_buffer, 4 + sharedSecret.Length); } - /** - * return the underlying digest. - */ - public virtual IDigest Digest - { - get { return mDigest; } - } + /// the underlying digest. + public IDigest Digest => m_digest; - /** - * fill len bytes of the output buffer with bytes generated from - * the derivation function. - * - * @throws DataLengthException if the out buffer is too small. - */ - public virtual int GenerateBytes(byte[] outBytes, int outOff, int len) + /// Fill len bytes of the output buffer with bytes generated from the derivation function. + /// + public int GenerateBytes(byte[] output, int outOff, int length) { - if ((outBytes.Length - len) < outOff) - throw new DataLengthException("output buffer too small"); + Check.OutputLength(output, outOff, length, "output buffer too small"); - byte[] hashBuf = new byte[mHLen]; - byte[] C = new byte[4]; +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(output.AsSpan(outOff, length)); +#else + int hashPos = m_buffer.Length - m_hLen; uint counter = 1; - int outputLen = 0; - mDigest.Reset(); + m_digest.Reset(); + + int end = outOff + length; + int limit = end - m_hLen; - if (len > mHLen) + while (outOff <= limit) { - do - { - Pack.UInt32_To_BE(counter, C); + Pack.UInt32_To_BE(counter++, m_buffer, 0); - mDigest.BlockUpdate(C, 0, C.Length); - mDigest.BlockUpdate(mShared, 0, mShared.Length); - mDigest.BlockUpdate(mOtherInfo, 0, mOtherInfo.Length); + m_digest.BlockUpdate(m_buffer, 0, hashPos); + m_digest.DoFinal(output, outOff); - mDigest.DoFinal(hashBuf, 0); + outOff += m_hLen; + } - Array.Copy(hashBuf, 0, outBytes, outOff + outputLen, mHLen); - outputLen += mHLen; - } - while ((counter++) < (len / mHLen)); + if (outOff < end) + { + Pack.UInt32_To_BE(counter, m_buffer, 0); + + m_digest.BlockUpdate(m_buffer, 0, hashPos); + m_digest.DoFinal(m_buffer, hashPos); + + Array.Copy(m_buffer, hashPos, output, outOff, end - outOff); } - if (outputLen < len) + return length; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) + { + int hashPos = m_buffer.Length - m_hLen; + uint counter = 1; + + m_digest.Reset(); + + int pos = 0, length = output.Length, limit = length - m_hLen; + + while (pos <= limit) { - Pack.UInt32_To_BE(counter, C); + Pack.UInt32_To_BE(counter++, m_buffer.AsSpan()); + + m_digest.BlockUpdate(m_buffer.AsSpan(0, hashPos)); + m_digest.DoFinal(output[pos..]); - mDigest.BlockUpdate(C, 0, C.Length); - mDigest.BlockUpdate(mShared, 0, mShared.Length); - mDigest.BlockUpdate(mOtherInfo, 0, mOtherInfo.Length); + pos += m_hLen; + } - mDigest.DoFinal(hashBuf, 0); + if (pos < length) + { + Pack.UInt32_To_BE(counter, m_buffer.AsSpan()); - Array.Copy(hashBuf, 0, outBytes, outOff + outputLen, len - outputLen); + m_digest.BlockUpdate(m_buffer.AsSpan(0, hashPos)); + m_digest.DoFinal(m_buffer.AsSpan(hashPos)); + m_buffer.AsSpan(hashPos, length - pos).CopyTo(output[pos..]); } - return len; + return length; } +#endif } } diff --git a/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs b/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs index 259e21e69..7d75c2224 100644 --- a/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs +++ b/crypto/src/crypto/agreement/kdf/DHKekGenerator.cs @@ -1,17 +1,19 @@ using System; using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.IO; using Org.BouncyCastle.Crypto.Utilities; +using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Agreement.Kdf { /** * RFC 2631 Diffie-hellman KEK derivation function. */ - public class DHKekGenerator + public sealed class DHKekGenerator : IDerivationFunction { - private readonly IDigest digest; + private readonly IDigest m_digest; private DerObjectIdentifier algorithm; private int keySize; @@ -20,10 +22,10 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf public DHKekGenerator(IDigest digest) { - this.digest = digest; + m_digest = digest; } - public virtual void Init(IDerivationParameters param) + public void Init(IDerivationParameters param) { DHKdfParameters parameters = (DHKdfParameters)param; @@ -33,20 +35,79 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf this.partyAInfo = parameters.GetExtraInfo(); // TODO Clone? } - public virtual IDigest Digest - { - get { return digest; } - } + public IDigest Digest => m_digest; - public virtual int GenerateBytes(byte[] outBytes, int outOff, int len) + public int GenerateBytes(byte[] outBytes, int outOff, int length) { - if ((outBytes.Length - len) < outOff) + Check.OutputLength(outBytes, outOff, length, "output buffer too small"); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(outBytes.AsSpan(outOff, length)); +#else + long oBytes = length; + int digestSize = m_digest.GetDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + throw new ArgumentException("Output length too large"); + + int cThreshold = (int)((oBytes + digestSize - 1) / digestSize); + + byte[] dig = new byte[digestSize]; + + uint counter = 1; + + for (int i = 0; i < cThreshold; i++) { - throw new DataLengthException("output buffer too small"); + // KeySpecificInfo + DerSequence keyInfo = new DerSequence(algorithm, new DerOctetString(Pack.UInt32_To_BE(counter))); + + // OtherInfo + Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo); + + if (partyAInfo != null) + { + v1.Add(new DerTaggedObject(true, 0, new DerOctetString(partyAInfo))); + } + + v1.Add(new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize)))); + + byte[] other = new DerSequence(v1).GetDerEncoded(); + + m_digest.BlockUpdate(z, 0, z.Length); + m_digest.BlockUpdate(other, 0, other.Length); + m_digest.DoFinal(dig, 0); + + if (length > digestSize) + { + Array.Copy(dig, 0, outBytes, outOff, digestSize); + outOff += digestSize; + length -= digestSize; + } + else + { + Array.Copy(dig, 0, outBytes, outOff, length); + } + + counter++; } - long oBytes = len; - int outLen = digest.GetDigestSize(); + m_digest.Reset(); + + return (int)oBytes; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) + { + long oBytes = output.Length; + int digestSize = m_digest.GetDigestSize(); // // this is at odds with the standard implementation, the @@ -55,24 +116,18 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf // array with a long index at the moment... // if (oBytes > ((2L << 32) - 1)) - { throw new ArgumentException("Output length too large"); - } - int cThreshold = (int)((oBytes + outLen - 1) / outLen); + int cThreshold = (int)((oBytes + digestSize - 1) / digestSize); - byte[] dig = new byte[digest.GetDigestSize()]; + Span dig = stackalloc byte[digestSize]; uint counter = 1; for (int i = 0; i < cThreshold; i++) { - digest.BlockUpdate(z, 0, z.Length); - // KeySpecificInfo - DerSequence keyInfo = new DerSequence( - algorithm, - new DerOctetString(Pack.UInt32_To_BE(counter))); + DerSequence keyInfo = new DerSequence(algorithm, new DerOctetString(Pack.UInt32_To_BE(counter))); // OtherInfo Asn1EncodableVector v1 = new Asn1EncodableVector(keyInfo); @@ -86,27 +141,28 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf byte[] other = new DerSequence(v1).GetDerEncoded(); - digest.BlockUpdate(other, 0, other.Length); - - digest.DoFinal(dig, 0); + m_digest.BlockUpdate(z); + m_digest.BlockUpdate(other); + m_digest.DoFinal(dig); - if (len > outLen) + int remaining = output.Length; + if (remaining > digestSize) { - Array.Copy(dig, 0, outBytes, outOff, outLen); - outOff += outLen; - len -= outLen; + dig.CopyTo(output); + output = output[digestSize..]; } else { - Array.Copy(dig, 0, outBytes, outOff, len); + dig[..remaining].CopyTo(output); } counter++; } - digest.Reset(); + m_digest.Reset(); return (int)oBytes; } +#endif } } diff --git a/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs b/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs index 74464574c..dbb7ad535 100644 --- a/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs +++ b/crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs @@ -11,10 +11,10 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf /** * X9.63 based key derivation function for ECDH CMS. */ - public class ECDHKekGenerator + public sealed class ECDHKekGenerator : IDerivationFunction { - private readonly IDerivationFunction kdf; + private readonly IDerivationFunction m_kdf; private DerObjectIdentifier algorithm; private int keySize; @@ -22,10 +22,10 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf public ECDHKekGenerator(IDigest digest) { - this.kdf = new Kdf2BytesGenerator(digest); + m_kdf = new Kdf2BytesGenerator(digest); } - public virtual void Init(IDerivationParameters param) + public void Init(IDerivationParameters param) { DHKdfParameters parameters = (DHKdfParameters)param; @@ -34,12 +34,29 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf this.z = parameters.GetZ(); // TODO Clone? } - public virtual IDigest Digest + public IDigest Digest => m_kdf.Digest; + + public int GenerateBytes(byte[] outBytes, int outOff, int length) { - get { return kdf.Digest; } + Check.OutputLength(outBytes, outOff, length, "output buffer too small"); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(outBytes.AsSpan(outOff, length)); +#else + // TODO Create an ASN.1 class for this (RFC3278) + // ECC-CMS-SharedInfo + DerSequence s = new DerSequence( + new AlgorithmIdentifier(algorithm, DerNull.Instance), + new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize)))); + + m_kdf.Init(new KdfParameters(z, s.GetDerEncoded())); + + return m_kdf.GenerateBytes(outBytes, outOff, length); +#endif } - public virtual int GenerateBytes(byte[] outBytes, int outOff, int len) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) { // TODO Create an ASN.1 class for this (RFC3278) // ECC-CMS-SharedInfo @@ -47,9 +64,10 @@ namespace Org.BouncyCastle.Crypto.Agreement.Kdf new AlgorithmIdentifier(algorithm, DerNull.Instance), new DerTaggedObject(true, 2, new DerOctetString(Pack.UInt32_To_BE((uint)keySize)))); - kdf.Init(new KdfParameters(z, s.GetDerEncoded())); + m_kdf.Init(new KdfParameters(z, s.GetDerEncoded())); - return kdf.GenerateBytes(outBytes, outOff, len); + return m_kdf.GenerateBytes(output); } +#endif } } diff --git a/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs b/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs index bca420711..c0c4be217 100644 --- a/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs +++ b/crypto/src/crypto/generators/BaseKdfBytesGenerator.cs @@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Generators *
* This implementation is based on ISO 18033/P1363a. */ - public class BaseKdfBytesGenerator + public abstract class BaseKdfBytesGenerator : IDerivationFunction { private int counterStart; @@ -25,26 +25,22 @@ namespace Org.BouncyCastle.Crypto.Generators * @param counterStart value of counter. * @param digest the digest to be used as the source of derived keys. */ - public BaseKdfBytesGenerator(int counterStart, IDigest digest) + protected BaseKdfBytesGenerator(int counterStart, IDigest digest) { this.counterStart = counterStart; this.digest = digest; } - public virtual void Init(IDerivationParameters parameters) + public void Init(IDerivationParameters parameters) { - if (parameters is KdfParameters) + if (parameters is KdfParameters kdfParameters) { - KdfParameters p = (KdfParameters)parameters; - - shared = p.GetSharedSecret(); - iv = p.GetIV(); + shared = kdfParameters.GetSharedSecret(); + iv = kdfParameters.GetIV(); } - else if (parameters is Iso18033KdfParameters) + else if (parameters is Iso18033KdfParameters iso18033KdfParameters) { - Iso18033KdfParameters p = (Iso18033KdfParameters)parameters; - - shared = p.GetSeed(); + shared = iso18033KdfParameters.GetSeed(); iv = null; } else @@ -56,10 +52,7 @@ namespace Org.BouncyCastle.Crypto.Generators /** * return the underlying digest. */ - public virtual IDigest Digest - { - get { return digest; } - } + public IDigest Digest => digest; /** * fill len bytes of the output buffer with bytes generated from @@ -68,13 +61,15 @@ namespace Org.BouncyCastle.Crypto.Generators * @throws ArgumentException if the size of the request will cause an overflow. * @throws DataLengthException if the out buffer is too small. */ - public virtual int GenerateBytes(byte[] output, int outOff, int length) + public int GenerateBytes(byte[] output, int outOff, int length) { - if ((output.Length - length) < outOff) - throw new DataLengthException("output buffer too small"); + Check.OutputLength(output, outOff, length, "output buffer too small"); +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(output.AsSpan(outOff, length)); +#else long oBytes = length; - int outLen = digest.GetDigestSize(); + int digestSize = digest.GetDigestSize(); // // this is at odds with the standard implementation, the @@ -85,9 +80,9 @@ namespace Org.BouncyCastle.Crypto.Generators if (oBytes > ((2L << 32) - 1)) throw new ArgumentException("Output length too large"); - int cThreshold = (int)((oBytes + outLen - 1) / outLen); + int cThreshold = (int)((oBytes + digestSize - 1) / digestSize); - byte[] dig = new byte[digest.GetDigestSize()]; + byte[] dig = new byte[digestSize]; byte[] C = new byte[4]; Pack.UInt32_To_BE((uint)counterStart, C, 0); @@ -106,11 +101,11 @@ namespace Org.BouncyCastle.Crypto.Generators digest.DoFinal(dig, 0); - if (length > outLen) + if (length > digestSize) { - Array.Copy(dig, 0, output, outOff, outLen); - outOff += outLen; - length -= outLen; + Array.Copy(dig, 0, output, outOff, digestSize); + outOff += digestSize; + length -= digestSize; } else { @@ -126,7 +121,68 @@ namespace Org.BouncyCastle.Crypto.Generators digest.Reset(); + return (int)oBytes; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) + { + long oBytes = output.Length; + int digestSize = digest.GetDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + throw new ArgumentException("Output length too large"); + + int cThreshold = (int)((oBytes + digestSize - 1) / digestSize); + + Span dig = stackalloc byte[digestSize]; + + Span C = stackalloc byte[4]; + Pack.UInt32_To_BE((uint)counterStart, C); + + uint counterBase = (uint)(counterStart & ~0xFF); + + for (int i = 0; i < cThreshold; i++) + { + digest.BlockUpdate(shared); + digest.BlockUpdate(C); + + if (iv != null) + { + digest.BlockUpdate(iv); + } + + digest.DoFinal(dig); + + int remaining = output.Length; + if (remaining > digestSize) + { + dig.CopyTo(output); + output = output[digestSize..]; + } + else + { + dig[..remaining].CopyTo(output); + } + + if (++C[3] == 0) + { + counterBase += 0x100; + Pack.UInt32_To_BE(counterBase, C); + } + } + + digest.Reset(); + return (int)oBytes; } +#endif } -} \ No newline at end of file +} diff --git a/crypto/src/crypto/generators/HKdfBytesGenerator.cs b/crypto/src/crypto/generators/HKdfBytesGenerator.cs index 6f36a6faa..e5c122049 100644 --- a/crypto/src/crypto/generators/HKdfBytesGenerator.cs +++ b/crypto/src/crypto/generators/HKdfBytesGenerator.cs @@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Crypto.Generators * (output keying material) and is likely to have better security properties * than KDF's based on just a hash function. */ - public class HkdfBytesGenerator + public sealed class HkdfBytesGenerator : IDerivationFunction { private HMac hMacHash; @@ -35,12 +35,11 @@ namespace Org.BouncyCastle.Crypto.Generators this.hashLen = hash.GetDigestSize(); } - public virtual void Init(IDerivationParameters parameters) + public void Init(IDerivationParameters parameters) { - if (!(parameters is HkdfParameters)) + if (!(parameters is HkdfParameters hkdfParameters)) throw new ArgumentException("HKDF parameters required for HkdfBytesGenerator", "parameters"); - HkdfParameters hkdfParameters = (HkdfParameters)parameters; if (hkdfParameters.SkipExtract) { // use IKM directly as PRK @@ -108,45 +107,70 @@ namespace Org.BouncyCastle.Crypto.Generators hMacHash.DoFinal(currentT, 0); } - public virtual IDigest Digest - { - get { return hMacHash.GetUnderlyingDigest(); } - } + public IDigest Digest => hMacHash.GetUnderlyingDigest(); - public virtual int GenerateBytes(byte[] output, int outOff, int len) + public int GenerateBytes(byte[] output, int outOff, int length) { - if (generatedBytes + len > 255 * hashLen) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(output.AsSpan(outOff, length)); +#else + if (generatedBytes > 255 * hashLen - length) + throw new DataLengthException("HKDF may only be used for 255 * HashLen bytes of output"); + + int toGenerate = length; + int posInT = generatedBytes % hashLen; + if (posInT != 0) { - throw new DataLengthException( - "HKDF may only be used for 255 * HashLen bytes of output"); + // copy what is left in the currentT (1..hash + int toCopy = System.Math.Min(hashLen - posInT, toGenerate); + Array.Copy(currentT, posInT, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; } - if (generatedBytes % hashLen == 0) + while (toGenerate > 0) { ExpandNext(); + int toCopy = System.Math.Min(hashLen, toGenerate); + Array.Copy(currentT, 0, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; } - // copy what is left in the currentT (1..hash - int toGenerate = len; + return length; +#endif + } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span outputX) + { + int length = outputX.Length; + if (generatedBytes > 255 * hashLen - length) + throw new DataLengthException("HKDF may only be used for 255 * HashLen bytes of output"); + int posInT = generatedBytes % hashLen; - int leftInT = hashLen - generatedBytes % hashLen; - int toCopy = System.Math.Min(leftInT, toGenerate); - Array.Copy(currentT, posInT, output, outOff, toCopy); - generatedBytes += toCopy; - toGenerate -= toCopy; - outOff += toCopy; + if (posInT != 0) + { + // copy what is left in the currentT (1..hash + int toCopy = System.Math.Min(hashLen - posInT, outputX.Length); + currentT.AsSpan(posInT, toCopy).CopyTo(outputX); + generatedBytes += toCopy; + outputX = outputX[toCopy..]; + } - while (toGenerate > 0) + while (!outputX.IsEmpty) { ExpandNext(); - toCopy = System.Math.Min(hashLen, toGenerate); - Array.Copy(currentT, 0, output, outOff, toCopy); + int toCopy = System.Math.Min(hashLen, outputX.Length); + currentT.AsSpan(0, toCopy).CopyTo(outputX); generatedBytes += toCopy; - toGenerate -= toCopy; - outOff += toCopy; + outputX = outputX[toCopy..]; } - return len; + return length; } +#endif } } diff --git a/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs b/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs index 0d7647289..7fa50e2fa 100644 --- a/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs +++ b/crypto/src/crypto/generators/KDFCounterBytesGenerator.cs @@ -3,17 +3,12 @@ using Org.BouncyCastle.Crypto.Macs; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; -using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Generators { - public class KdfCounterBytesGenerator : IMacDerivationFunction + public sealed class KdfCounterBytesGenerator + : IMacDerivationFunction { - - private static readonly BigInteger IntegerMax = BigInteger.ValueOf(0x7fffffff); - private static readonly BigInteger Two = BigInteger.Two; - - private readonly IMac prf; private readonly int h; @@ -37,13 +32,8 @@ namespace Org.BouncyCastle.Crypto.Generators public void Init(IDerivationParameters param) { - KdfCounterParameters kdfParams = param as KdfCounterParameters; - if (kdfParams == null) - { + if (!(param is KdfCounterParameters kdfParams)) throw new ArgumentException("Wrong type of arguments given"); - } - - // --- init mac based PRF --- @@ -57,54 +47,45 @@ namespace Org.BouncyCastle.Crypto.Generators int r = kdfParams.R; this.ios = new byte[r / 8]; - BigInteger maxSize = Two.Pow(r).Multiply(BigInteger.ValueOf(h)); - this.maxSizeExcl = maxSize.CompareTo(IntegerMax) == 1 ? - int.MaxValue : maxSize.IntValue; + BigInteger maxSize = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h)); + this.maxSizeExcl = maxSize.BitLength > 31 ? int.MaxValue : maxSize.IntValueExact; // --- set operational state --- generatedBytes = 0; } - - public IMac GetMac() - { - return prf; - } + public IMac Mac => prf; public IDigest Digest { - get { return prf is HMac ? ((HMac)prf).GetUnderlyingDigest() : null; } + get { return (prf as HMac)?.GetUnderlyingDigest(); } } public int GenerateBytes(byte[] output, int outOff, int length) { - int generatedBytesAfter = generatedBytes + length; - if (generatedBytesAfter < 0 || generatedBytesAfter >= maxSizeExcl) - { - throw new DataLengthException( - "Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); - } - - if (generatedBytes % h == 0) - { - generateNext(); - } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(output.AsSpan(outOff, length)); +#else + if (generatedBytes >= maxSizeExcl - length) + throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); - // copy what is left in the currentT (1..hash int toGenerate = length; int posInK = generatedBytes % h; - int leftInK = h - generatedBytes % h; - int toCopy = System.Math.Min(leftInK, toGenerate); - Array.Copy(k, posInK, output, outOff, toCopy); - generatedBytes += toCopy; - toGenerate -= toCopy; - outOff += toCopy; + if (posInK != 0) + { + // copy what is left in the currentT (1..hash + int toCopy = System.Math.Min(h - posInK, toGenerate); + Array.Copy(k, posInK, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + } while (toGenerate > 0) { - generateNext(); - toCopy = System.Math.Min(h, toGenerate); + GenerateNext(); + int toCopy = System.Math.Min(h, toGenerate); Array.Copy(k, 0, output, outOff, toCopy); generatedBytes += toCopy; toGenerate -= toCopy; @@ -112,38 +93,65 @@ namespace Org.BouncyCastle.Crypto.Generators } return length; - +#endif } - private void generateNext() +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) { + int length = output.Length; + if (generatedBytes >= maxSizeExcl - length) + throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); + + int posInK = generatedBytes % h; + if (posInK != 0) + { + // copy what is left in the currentT (1..hash + int toCopy = System.Math.Min(h - posInK, output.Length); + k.AsSpan(posInK, toCopy).CopyTo(output); + generatedBytes += toCopy; + output = output[toCopy..]; + } + while (!output.IsEmpty) + { + GenerateNext(); + int toCopy = System.Math.Min(h, output.Length); + k.AsSpan(0, toCopy).CopyTo(output); + generatedBytes += toCopy; + output = output[toCopy..]; + } + + return length; + } +#endif + + private void GenerateNext() + { int i = generatedBytes / h + 1; // encode i into counter buffer switch (ios.Length) { - case 4: - ios[0] = (byte)(i >> 24); - goto case 3; + case 4: + ios[0] = (byte)(i >> 24); // fall through - case 3: - ios[ios.Length - 3] = (byte)(i >> 16); - // fall through - goto case 2; - case 2: - ios[ios.Length - 2] = (byte)(i >> 8); - // fall through - goto case 1; - case 1: - ios[ios.Length - 1] = (byte)i; - break; - default: - throw new InvalidOperationException("Unsupported size of counter i"); + goto case 3; + case 3: + ios[ios.Length - 3] = (byte)(i >> 16); + // fall through + goto case 2; + case 2: + ios[ios.Length - 2] = (byte)(i >> 8); + // fall through + goto case 1; + case 1: + ios[ios.Length - 1] = (byte)i; + break; + default: + throw new InvalidOperationException("Unsupported size of counter i"); } - - // special case for K(0): K(0) is empty, so no update prf.BlockUpdate(fixedInputDataCtrPrefix, 0, fixedInputDataCtrPrefix.Length); prf.BlockUpdate(ios, 0, ios.Length); @@ -151,4 +159,4 @@ namespace Org.BouncyCastle.Crypto.Generators prf.DoFinal(k, 0); } } -} \ No newline at end of file +} diff --git a/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs b/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs index 63c0787f3..01feda6f4 100644 --- a/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs +++ b/crypto/src/crypto/generators/KDFDoublePipelineIterationBytesGenerator.cs @@ -6,11 +6,9 @@ using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Crypto.Generators { - public class KdfDoublePipelineIterationBytesGenerator : IMacDerivationFunction + public sealed class KdfDoublePipelineIterationBytesGenerator + : IMacDerivationFunction { - private static readonly BigInteger IntegerMax = BigInteger.ValueOf(0x7fffffff); - private static readonly BigInteger Two = BigInteger.Two; - // fields set by the constructor private readonly IMac prf; private readonly int h; @@ -28,7 +26,6 @@ namespace Org.BouncyCastle.Crypto.Generators private byte[] a; private byte[] k; - public KdfDoublePipelineIterationBytesGenerator(IMac prf) { this.prf = prf; @@ -37,16 +34,10 @@ namespace Org.BouncyCastle.Crypto.Generators this.k = new byte[h]; } - public void Init(IDerivationParameters parameters) { - KdfDoublePipelineIterationParameters dpiParams = parameters as KdfDoublePipelineIterationParameters; - if (dpiParams == null) - { + if (!(parameters is KdfDoublePipelineIterationParameters dpiParams)) throw new ArgumentException("Wrong type of arguments given"); - } - - // --- init mac based PRF --- @@ -62,13 +53,12 @@ namespace Org.BouncyCastle.Crypto.Generators if (dpiParams.UseCounter) { // this is more conservative than the spec - BigInteger maxSize = Two.Pow(r).Multiply(BigInteger.ValueOf(h)); - this.maxSizeExcl = maxSize.CompareTo(IntegerMax) == 1 ? - int.MaxValue : maxSize.IntValue; + BigInteger maxSize = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h)); + this.maxSizeExcl = maxSize.BitLength > 31 ? int.MaxValue : maxSize.IntValueExact; } else { - this.maxSizeExcl = IntegerMax.IntValue; + this.maxSizeExcl = int.MaxValue; } this.useCounter = dpiParams.UseCounter; @@ -78,12 +68,8 @@ namespace Org.BouncyCastle.Crypto.Generators generatedBytes = 0; } - - - - private void generateNext() + private void GenerateNext() { - if (generatedBytes == 0) { // --- step 4 --- @@ -107,23 +93,23 @@ namespace Org.BouncyCastle.Crypto.Generators // encode i into counter buffer switch (ios.Length) { - case 4: - ios[0] = (byte)(i >> 24); - // fall through - goto case 3; - case 3: - ios[ios.Length - 3] = (byte)(i >> 16); - // fall through - goto case 2; - case 2: - ios[ios.Length - 2] = (byte)(i >> 8); - // fall through - goto case 1; - case 1: - ios[ios.Length - 1] = (byte)i; - break; - default: - throw new InvalidOperationException("Unsupported size of counter i"); + case 4: + ios[0] = (byte)(i >> 24); + // fall through + goto case 3; + case 3: + ios[ios.Length - 3] = (byte)(i >> 16); + // fall through + goto case 2; + case 2: + ios[ios.Length - 2] = (byte)(i >> 8); + // fall through + goto case 1; + case 1: + ios[ios.Length - 1] = (byte)i; + break; + default: + throw new InvalidOperationException("Unsupported size of counter i"); } prf.BlockUpdate(ios, 0, ios.Length); } @@ -134,37 +120,33 @@ namespace Org.BouncyCastle.Crypto.Generators public IDigest Digest { - get { return prf is HMac ? ((HMac)prf).GetUnderlyingDigest() : null; } + get { return (prf as HMac)?.GetUnderlyingDigest(); } } public int GenerateBytes(byte[] output, int outOff, int length) { - int generatedBytesAfter = generatedBytes + length; - if (generatedBytesAfter < 0 || generatedBytesAfter >= maxSizeExcl) - { - throw new DataLengthException( - "Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); - } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(output.AsSpan(outOff, length)); +#else + if (generatedBytes >= maxSizeExcl - length) + throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); - if (generatedBytes % h == 0) - { - generateNext(); - } - - // copy what is left in the currentT (1..hash int toGenerate = length; int posInK = generatedBytes % h; - int leftInK = h - generatedBytes % h; - int toCopy = System.Math.Min(leftInK, toGenerate); - Array.Copy(k, posInK, output, outOff, toCopy); - generatedBytes += toCopy; - toGenerate -= toCopy; - outOff += toCopy; + if (posInK != 0) + { + // copy what is left in the currentT (1..hash + int toCopy = System.Math.Min(h - posInK, toGenerate); + Array.Copy(k, posInK, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + } while (toGenerate > 0) { - generateNext(); - toCopy = System.Math.Min(h, toGenerate); + GenerateNext(); + int toCopy = System.Math.Min(h, toGenerate); Array.Copy(k, 0, output, outOff, toCopy); generatedBytes += toCopy; toGenerate -= toCopy; @@ -172,11 +154,40 @@ namespace Org.BouncyCastle.Crypto.Generators } return length; +#endif } - public IMac GetMac() +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) { - return prf; + int length = output.Length; + if (generatedBytes >= maxSizeExcl - length) + throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); + + int posInK = generatedBytes % h; + if (posInK != 0) + { + // copy what is left in the currentT (1..hash + GenerateNext(); + int toCopy = System.Math.Min(h - posInK, output.Length); + k.AsSpan(posInK, toCopy).CopyTo(output); + generatedBytes += toCopy; + output = output[toCopy..]; + } + + while (!output.IsEmpty) + { + GenerateNext(); + int toCopy = System.Math.Min(h, output.Length); + k.AsSpan(0, toCopy).CopyTo(output); + generatedBytes += toCopy; + output = output[toCopy..]; + } + + return length; } +#endif + + public IMac Mac => prf; } -} \ No newline at end of file +} diff --git a/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs b/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs index 11a5552fe..58a035ef6 100644 --- a/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs +++ b/crypto/src/crypto/generators/KDFFeedbackBytesGenerator.cs @@ -6,11 +6,9 @@ using Org.BouncyCastle.Math; namespace Org.BouncyCastle.Crypto.Generators { - public class KdfFeedbackBytesGenerator : IMacDerivationFunction + public sealed class KdfFeedbackBytesGenerator + : IMacDerivationFunction { - private static readonly BigInteger IntegerMax = BigInteger.ValueOf(0x7fffffff); - private static readonly BigInteger Two = BigInteger.Two; - // please refer to the standard for the meaning of the variable names // all field lengths are in bytes, not in bits as specified by the standard @@ -38,15 +36,10 @@ namespace Org.BouncyCastle.Crypto.Generators this.k = new byte[h]; } - public void Init(IDerivationParameters parameters) { - KdfFeedbackParameters feedbackParams = parameters as KdfFeedbackParameters; - if (feedbackParams == null) - { + if (!(parameters is KdfFeedbackParameters feedbackParams)) throw new ArgumentException("Wrong type of arguments given"); - } - // --- init mac based PRF --- @@ -62,9 +55,8 @@ namespace Org.BouncyCastle.Crypto.Generators if (feedbackParams.UseCounter) { // this is more conservative than the spec - BigInteger maxSize = Two.Pow(r).Multiply(BigInteger.ValueOf(h)); - this.maxSizeExcl = maxSize.CompareTo(IntegerMax) == 1 ? - int.MaxValue : maxSize.IntValue; + BigInteger maxSize = BigInteger.One.ShiftLeft(r).Multiply(BigInteger.ValueOf(h)); + this.maxSizeExcl = maxSize.BitLength > 31 ? int.MaxValue : maxSize.IntValueExact; } else { @@ -81,40 +73,33 @@ namespace Org.BouncyCastle.Crypto.Generators public IDigest Digest { - get { return prf is HMac ? ((HMac)prf).GetUnderlyingDigest() : null; } + get { return (prf as HMac)?.GetUnderlyingDigest(); } } public int GenerateBytes(byte[] output, int outOff, int length) { - int generatedBytesAfter = generatedBytes + length; - if (generatedBytesAfter < 0 || generatedBytesAfter >= maxSizeExcl) - { - throw new DataLengthException( - "Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); - } - - if (generatedBytes % h == 0) - { - generateNext(); - } +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(output.AsSpan(outOff, length)); +#else + if (generatedBytes >= maxSizeExcl - length) + throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); - // copy what is left in the currentT (1..hash int toGenerate = length; int posInK = generatedBytes % h; - int leftInK = h - generatedBytes % h; - - - int toCopy = System.Math.Min(leftInK, toGenerate); - Array.Copy(k, posInK, output, outOff, toCopy); - - generatedBytes += toCopy; - toGenerate -= toCopy; - outOff += toCopy; + if (posInK != 0) + { + // copy what is left in the currentT (1..hash + int toCopy = System.Math.Min(h - posInK, toGenerate); + Array.Copy(k, posInK, output, outOff, toCopy); + generatedBytes += toCopy; + toGenerate -= toCopy; + outOff += toCopy; + } while (toGenerate > 0) { - generateNext(); - toCopy = System.Math.Min(h, toGenerate); + GenerateNext(); + int toCopy = System.Math.Min(h, toGenerate); Array.Copy(k, 0, output, outOff, toCopy); generatedBytes += toCopy; toGenerate -= toCopy; @@ -122,11 +107,41 @@ namespace Org.BouncyCastle.Crypto.Generators } return length; +#endif } - private void generateNext() +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) { + int length = output.Length; + if (generatedBytes >= maxSizeExcl - length) + throw new DataLengthException("Current KDFCTR may only be used for " + maxSizeExcl + " bytes"); + int posInK = generatedBytes % h; + if (posInK != 0) + { + // copy what is left in the currentT (1..hash + int toCopy = System.Math.Min(h - posInK, output.Length); + k.AsSpan(posInK, toCopy).CopyTo(output); + generatedBytes += toCopy; + output = output[toCopy..]; + } + + while (!output.IsEmpty) + { + GenerateNext(); + int toCopy = System.Math.Min(h, output.Length); + k.AsSpan(0, toCopy).CopyTo(output); + generatedBytes += toCopy; + output = output[toCopy..]; + } + + return length; + } +#endif + + private void GenerateNext() + { // TODO enable IV if (generatedBytes == 0) { @@ -144,23 +159,23 @@ namespace Org.BouncyCastle.Crypto.Generators // encode i into counter buffer switch (ios.Length) { - case 4: - ios[0] = (byte)(i >> 24); - goto case 3; + case 4: + ios[0] = (byte)(i >> 24); // fall through - case 3: - ios[ios.Length - 3] = (byte)(i >> 16); - // fall through - goto case 2; - case 2: - ios[ios.Length - 2] = (byte)(i >> 8); - // fall through - goto case 1; - case 1: - ios[ios.Length - 1] = (byte)i; - break; - default: - throw new InvalidOperationException("Unsupported size of counter i"); + goto case 3; + case 3: + ios[ios.Length - 3] = (byte)(i >> 16); + // fall through + goto case 2; + case 2: + ios[ios.Length - 2] = (byte)(i >> 8); + // fall through + goto case 1; + case 1: + ios[ios.Length - 1] = (byte)i; + break; + default: + throw new InvalidOperationException("Unsupported size of counter i"); } prf.BlockUpdate(ios, 0, ios.Length); } @@ -169,9 +184,6 @@ namespace Org.BouncyCastle.Crypto.Generators prf.DoFinal(k, 0); } - public IMac GetMac() - { - return prf; - } + public IMac Mac => prf; } -} \ No newline at end of file +} diff --git a/crypto/src/crypto/generators/Kdf1BytesGenerator.cs b/crypto/src/crypto/generators/Kdf1BytesGenerator.cs index 0ddf6c166..a43fa06d1 100644 --- a/crypto/src/crypto/generators/Kdf1BytesGenerator.cs +++ b/crypto/src/crypto/generators/Kdf1BytesGenerator.cs @@ -1,16 +1,11 @@ -using System; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; - namespace Org.BouncyCastle.Crypto.Generators { /** - * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033 + * KFD1 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033 *
* This implementation is based on IEEE P1363/ISO 18033. */ - public class Kdf1BytesGenerator + public sealed class Kdf1BytesGenerator : BaseKdfBytesGenerator { /** diff --git a/crypto/src/crypto/generators/Kdf2BytesGenerator.cs b/crypto/src/crypto/generators/Kdf2BytesGenerator.cs index 8a6821980..2dc1d4301 100644 --- a/crypto/src/crypto/generators/Kdf2BytesGenerator.cs +++ b/crypto/src/crypto/generators/Kdf2BytesGenerator.cs @@ -1,8 +1,3 @@ -using System; - -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Parameters; - namespace Org.BouncyCastle.Crypto.Generators { /** @@ -10,7 +5,7 @@ namespace Org.BouncyCastle.Crypto.Generators *
* This implementation is based on IEEE P1363/ISO 18033. */ - public class Kdf2BytesGenerator + public sealed class Kdf2BytesGenerator : BaseKdfBytesGenerator { /** diff --git a/crypto/src/crypto/generators/Mgf1BytesGenerator.cs b/crypto/src/crypto/generators/Mgf1BytesGenerator.cs index 23a3aca25..7b4bb3c0b 100644 --- a/crypto/src/crypto/generators/Mgf1BytesGenerator.cs +++ b/crypto/src/crypto/generators/Mgf1BytesGenerator.cs @@ -1,117 +1,112 @@ using System; -//using Org.BouncyCastle.Math; -//using Org.BouncyCastle.Security; -using Org.BouncyCastle.Crypto; + using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Utilities; namespace Org.BouncyCastle.Crypto.Generators { - /** - * Generator for MGF1 as defined in Pkcs 1v2 - */ - public class Mgf1BytesGenerator : IDerivationFunction + /// Generator for MGF1 as defined in Pkcs 1v2 + public sealed class Mgf1BytesGenerator + : IDerivationFunction { - private IDigest digest; - private byte[] seed; - private int hLen; - - /** - * @param digest the digest to be used as the source of Generated bytes - */ - public Mgf1BytesGenerator( - IDigest digest) + private readonly IDigest m_digest; + private readonly int m_hLen; + + private byte[] m_buffer; + + /// the digest to be used as the source of generated bytes + public Mgf1BytesGenerator(IDigest digest) { - this.digest = digest; - this.hLen = digest.GetDigestSize(); + m_digest = digest; + m_hLen = digest.GetDigestSize(); } - public void Init( - IDerivationParameters parameters) + public void Init(IDerivationParameters parameters) { - if (!(typeof(MgfParameters).IsInstanceOfType(parameters))) - { + if (!(parameters is MgfParameters mgfParameters)) throw new ArgumentException("MGF parameters required for MGF1Generator"); - } - - MgfParameters p = (MgfParameters)parameters; - seed = p.GetSeed(); + m_buffer = new byte[mgfParameters.SeedLength + 4 + m_hLen]; + mgfParameters.GetSeed(m_buffer, 0); } - /** - * return the underlying digest. - */ - public IDigest Digest + /// the underlying digest. + public IDigest Digest => m_digest; + + /// Fill len bytes of the output buffer with bytes generated from the derivation function. + /// + public int GenerateBytes(byte[] output, int outOff, int length) { - get + Check.OutputLength(output, outOff, length, "output buffer too small"); + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + return GenerateBytes(output.AsSpan(outOff, length)); +#else + int hashPos = m_buffer.Length - m_hLen; + int counterPos = hashPos - 4; + uint counter = 0; + + m_digest.Reset(); + + int end = outOff + length; + int limit = end - m_hLen; + + while (outOff <= limit) { - return digest; + Pack.UInt32_To_BE(counter++, m_buffer, counterPos); + + m_digest.BlockUpdate(m_buffer, 0, hashPos); + m_digest.DoFinal(output, outOff); + + outOff += m_hLen; } - } - /** - * int to octet string. - */ - private void ItoOSP( - int i, - byte[] sp) - { - sp[0] = (byte)((uint) i >> 24); - sp[1] = (byte)((uint) i >> 16); - sp[2] = (byte)((uint) i >> 8); - sp[3] = (byte)((uint) i >> 0); + if (outOff < end) + { + Pack.UInt32_To_BE(counter, m_buffer, counterPos); + + m_digest.BlockUpdate(m_buffer, 0, hashPos); + m_digest.DoFinal(m_buffer, hashPos); + + Array.Copy(m_buffer, hashPos, output, outOff, end - outOff); + } + + return length; +#endif } - /** - * fill len bytes of the output buffer with bytes Generated from - * the derivation function. - * - * @throws DataLengthException if the out buffer is too small. - */ - public int GenerateBytes( - byte[] output, - int outOff, - int length) +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public int GenerateBytes(Span output) { - if ((output.Length - length) < outOff) - { - throw new DataLengthException("output buffer too small"); - } + int hashPos = m_buffer.Length - m_hLen; + int counterPos = hashPos - 4; + uint counter = 0; - byte[] hashBuf = new byte[hLen]; - byte[] C = new byte[4]; - int counter = 0; + m_digest.Reset(); - digest.Reset(); + int pos = 0, length = output.Length, limit = length - m_hLen; - if (length > hLen) - { - do - { - ItoOSP(counter, C); + while (pos <= limit) + { + Pack.UInt32_To_BE(counter++, m_buffer.AsSpan(counterPos)); - digest.BlockUpdate(seed, 0, seed.Length); - digest.BlockUpdate(C, 0, C.Length); - digest.DoFinal(hashBuf, 0); + m_digest.BlockUpdate(m_buffer.AsSpan(0, hashPos)); + m_digest.DoFinal(output[pos..]); - Array.Copy(hashBuf, 0, output, outOff + counter * hLen, hLen); - } - while (++counter < (length / hLen)); - } + pos += m_hLen; + } - if ((counter * hLen) < length) + if (pos < length) { - ItoOSP(counter, C); - - digest.BlockUpdate(seed, 0, seed.Length); - digest.BlockUpdate(C, 0, C.Length); - digest.DoFinal(hashBuf, 0); + Pack.UInt32_To_BE(counter, m_buffer.AsSpan(counterPos)); - Array.Copy(hashBuf, 0, output, outOff + counter * hLen, length - (counter * hLen)); + m_digest.BlockUpdate(m_buffer.AsSpan(0, hashPos)); + m_digest.DoFinal(m_buffer.AsSpan(hashPos)); + m_buffer.AsSpan(hashPos, length - pos).CopyTo(output[pos..]); } return length; } +#endif } - } diff --git a/crypto/src/crypto/parameters/KdfParameters.cs b/crypto/src/crypto/parameters/KdfParameters.cs index bc5c905d0..78cf81855 100644 --- a/crypto/src/crypto/parameters/KdfParameters.cs +++ b/crypto/src/crypto/parameters/KdfParameters.cs @@ -6,28 +6,26 @@ namespace Org.BouncyCastle.Crypto.Parameters /** * parameters for Key derivation functions for IEEE P1363a */ - public class KdfParameters : IDerivationParameters + public class KdfParameters + : IDerivationParameters { - byte[] iv; - byte[] shared; + private readonly byte[] m_iv; + private readonly byte[] m_shared; - public KdfParameters( - byte[] shared, - byte[] iv) + public KdfParameters(byte[] shared, byte[] iv) { - this.shared = shared; - this.iv = iv; + m_shared = shared; + m_iv = iv; } public byte[] GetSharedSecret() { - return shared; + return m_shared; } public byte[] GetIV() { - return iv; + return m_iv; } } - } diff --git a/crypto/src/crypto/parameters/MgfParameters.cs b/crypto/src/crypto/parameters/MgfParameters.cs index 11983b877..7915567e2 100644 --- a/crypto/src/crypto/parameters/MgfParameters.cs +++ b/crypto/src/crypto/parameters/MgfParameters.cs @@ -1,31 +1,42 @@ using System; +using Org.BouncyCastle.Utilities; + namespace Org.BouncyCastle.Crypto.Parameters { /// Parameters for mask derivation functions. - public class MgfParameters + public sealed class MgfParameters : IDerivationParameters { - private readonly byte[] seed; + private readonly byte[] m_seed; - public MgfParameters( - byte[] seed) + public MgfParameters(byte[] seed) : this(seed, 0, seed.Length) { } - public MgfParameters( - byte[] seed, - int off, - int len) + public MgfParameters(byte[] seed, int off, int len) + { + m_seed = Arrays.CopyOfRange(seed, off, len); + } + + public byte[] GetSeed() { - this.seed = new byte[len]; - Array.Copy(seed, off, this.seed, 0, len); + return (byte[])m_seed.Clone(); } - public byte[] GetSeed() + public void GetSeed(byte[] buffer, int offset) { - return (byte[]) seed.Clone(); + m_seed.CopyTo(buffer, offset); } + +#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER + public void GetSeed(Span output) + { + m_seed.CopyTo(output); + } +#endif + + public int SeedLength => m_seed.Length; } } -- cgit 1.4.1