From 75cb55fedb8b90dc99996b88ccb55a35549be184 Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Wed, 14 Jun 2023 14:04:48 +0700 Subject: Add ECDHCWithKdfBasicAgreement - refactor other WithKdf agreeements - support "ECCDHWITHSHA1KDF" in AgreementUtilities --- .../src/crypto/agreement/BasicAgreementWithKdf.cs | 34 +++++++++++++++ crypto/src/crypto/agreement/ECDHBasicAgreement.cs | 5 ++- crypto/src/crypto/agreement/ECDHCBasicAgreement.cs | 4 +- .../crypto/agreement/ECDHCWithKdfBasicAgreement.cs | 30 +++++++++++++ .../crypto/agreement/ECDHWithKdfBasicAgreement.cs | 48 +++++---------------- crypto/src/crypto/agreement/ECMqvBasicAgreement.cs | 10 +++-- .../crypto/agreement/ECMqvWithKdfBasicAgreement.cs | 50 +++++----------------- crypto/src/security/AgreementUtilities.cs | 17 +++----- 8 files changed, 103 insertions(+), 95 deletions(-) create mode 100644 crypto/src/crypto/agreement/BasicAgreementWithKdf.cs create mode 100644 crypto/src/crypto/agreement/ECDHCWithKdfBasicAgreement.cs diff --git a/crypto/src/crypto/agreement/BasicAgreementWithKdf.cs b/crypto/src/crypto/agreement/BasicAgreementWithKdf.cs new file mode 100644 index 000000000..8f78bd393 --- /dev/null +++ b/crypto/src/crypto/agreement/BasicAgreementWithKdf.cs @@ -0,0 +1,34 @@ +using System.Security.Cryptography; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.Agreement.Kdf; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + internal static class BasicAgreementWithKdf + { + internal static BigInteger CalculateAgreementWithKdf(string algorithm, IDerivationFunction kdf, int fieldSize, + BigInteger result) + { + // Note that the ec.KeyAgreement class in JCE only uses kdf in one + // of the engineGenerateSecret methods. + + int keySize = GeneratorUtilities.GetDefaultKeySize(algorithm); + + DHKdfParameters dhKdfParams = new DHKdfParameters( + new DerObjectIdentifier(algorithm), + keySize, + BigIntegers.AsUnsignedByteArray(fieldSize, result)); + + kdf.Init(dhKdfParams); + + byte[] keyBytes = new byte[keySize / 8]; + kdf.GenerateBytes(keyBytes, 0, keyBytes.Length); + + return new BigInteger(1, keyBytes); + } + } +} diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs index 4555cdde4..700bb88e6 100644 --- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs @@ -21,9 +21,11 @@ namespace Org.BouncyCastle.Crypto.Agreement * DL/ECKAS-DH2. It assumes that the input keys are valid (see also * Section 7.2.2). */ + // TODO[api] sealed public class ECDHBasicAgreement : IBasicAgreement { + // TODO[api] private protected internal ECPrivateKeyParameters privKey; public virtual void Init(ICipherParameters parameters) @@ -44,8 +46,7 @@ namespace Org.BouncyCastle.Crypto.Agreement return (privKey.Parameters.Curve.FieldSize + 7) / 8; } - public virtual BigInteger CalculateAgreement( - ICipherParameters pubKey) + public virtual BigInteger CalculateAgreement(ICipherParameters pubKey) { ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; ECDomainParameters dp = privKey.Parameters; diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs index bb4c185df..a58974953 100644 --- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs @@ -26,6 +26,7 @@ namespace Org.BouncyCastle.Crypto.Agreement * (if you want that just use ECDHBasicAgreement and note they both implement * BasicAgreement!).

*/ + // TODO[api] sealed public class ECDHCBasicAgreement : IBasicAgreement { @@ -49,8 +50,7 @@ namespace Org.BouncyCastle.Crypto.Agreement return (privKey.Parameters.Curve.FieldSize + 7) / 8; } - public virtual BigInteger CalculateAgreement( - ICipherParameters pubKey) + public virtual BigInteger CalculateAgreement(ICipherParameters pubKey) { ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey; ECDomainParameters dp = privKey.Parameters; diff --git a/crypto/src/crypto/agreement/ECDHCWithKdfBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCWithKdfBasicAgreement.cs new file mode 100644 index 000000000..0f38c0fe6 --- /dev/null +++ b/crypto/src/crypto/agreement/ECDHCWithKdfBasicAgreement.cs @@ -0,0 +1,30 @@ +using System; + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Crypto.Agreement.Kdf; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Crypto.Agreement +{ + public sealed class ECDHCWithKdfBasicAgreement + : ECDHCBasicAgreement + { + private readonly string m_algorithm; + private readonly IDerivationFunction m_kdf; + + public ECDHCWithKdfBasicAgreement(string algorithm, IDerivationFunction kdf) + { + m_algorithm = algorithm ?? throw new ArgumentNullException(nameof(algorithm)); + m_kdf = kdf ?? throw new ArgumentNullException(nameof(kdf)); + } + + public override BigInteger CalculateAgreement(ICipherParameters pubKey) + { + BigInteger result = base.CalculateAgreement(pubKey); + + return BasicAgreementWithKdf.CalculateAgreementWithKdf(m_algorithm, m_kdf, GetFieldSize(), result); + } + } +} diff --git a/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs index a73e3f438..fb85da611 100644 --- a/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs @@ -1,59 +1,31 @@ using System; using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.Agreement.Kdf; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Agreement { - public class ECDHWithKdfBasicAgreement + // TODO[api] sealed + public class ECDHWithKdfBasicAgreement : ECDHBasicAgreement { - private readonly string algorithm; - private readonly IDerivationFunction kdf; + private readonly string m_algorithm; + private readonly IDerivationFunction m_kdf; - public ECDHWithKdfBasicAgreement( - string algorithm, - IDerivationFunction kdf) + public ECDHWithKdfBasicAgreement(string algorithm, IDerivationFunction kdf) { - if (algorithm == null) - throw new ArgumentNullException("algorithm"); - if (kdf == null) - throw new ArgumentNullException("kdf"); - - this.algorithm = algorithm; - this.kdf = kdf; + m_algorithm = algorithm ?? throw new ArgumentNullException(nameof(algorithm)); + m_kdf = kdf ?? throw new ArgumentNullException(nameof(kdf)); } - public override BigInteger CalculateAgreement( - ICipherParameters pubKey) + public override BigInteger CalculateAgreement(ICipherParameters pubKey) { - // Note that the ec.KeyAgreement class in JCE only uses kdf in one - // of the engineGenerateSecret methods. - BigInteger result = base.CalculateAgreement(pubKey); - int keySize = GeneratorUtilities.GetDefaultKeySize(algorithm); - - DHKdfParameters dhKdfParams = new DHKdfParameters( - new DerObjectIdentifier(algorithm), - keySize, - BigIntToBytes(result)); - - kdf.Init(dhKdfParams); - - byte[] keyBytes = new byte[keySize / 8]; - kdf.GenerateBytes(keyBytes, 0, keyBytes.Length); - - return new BigInteger(1, keyBytes); - } - - private byte[] BigIntToBytes(BigInteger r) - { - int byteLength = X9IntegerConverter.GetByteLength(privKey.Parameters.Curve); - return X9IntegerConverter.IntegerToBytes(r, byteLength); + return BasicAgreementWithKdf.CalculateAgreementWithKdf(m_algorithm, m_kdf, GetFieldSize(), result); } } } diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs index 984d66587..64f41dd78 100644 --- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs @@ -7,9 +7,11 @@ using Org.BouncyCastle.Math.EC; namespace Org.BouncyCastle.Crypto.Agreement { + // TODO[api] sealed public class ECMqvBasicAgreement : IBasicAgreement { + // TODO[api] private protected internal MqvPrivateParameters privParams; public virtual void Init(ICipherParameters parameters) @@ -19,7 +21,10 @@ namespace Org.BouncyCastle.Crypto.Agreement parameters = withRandom.Parameters; } - this.privParams = (MqvPrivateParameters)parameters; + if (!(parameters is MqvPrivateParameters mqvPrivateParameters)) + throw new ArgumentException("ECMqvBasicAgreement expects MqvPrivateParameters"); + + this.privParams = mqvPrivateParameters; } public virtual int GetFieldSize() @@ -27,8 +32,7 @@ namespace Org.BouncyCastle.Crypto.Agreement return (privParams.StaticPrivateKey.Parameters.Curve.FieldSize + 7) / 8; } - public virtual BigInteger CalculateAgreement( - ICipherParameters pubKey) + public virtual BigInteger CalculateAgreement(ICipherParameters pubKey) { MqvPublicParameters pubParams = (MqvPublicParameters)pubKey; diff --git a/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs index 248e04e27..6977a5057 100644 --- a/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs +++ b/crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs @@ -1,59 +1,31 @@ using System; using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.Agreement.Kdf; using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Crypto.Agreement { - public class ECMqvWithKdfBasicAgreement + // TODO[api] sealed + public class ECMqvWithKdfBasicAgreement : ECMqvBasicAgreement { - private readonly string algorithm; - private readonly IDerivationFunction kdf; + private readonly string m_algorithm; + private readonly IDerivationFunction m_kdf; - public ECMqvWithKdfBasicAgreement( - string algorithm, - IDerivationFunction kdf) + public ECMqvWithKdfBasicAgreement(string algorithm, IDerivationFunction kdf) { - if (algorithm == null) - throw new ArgumentNullException("algorithm"); - if (kdf == null) - throw new ArgumentNullException("kdf"); - - this.algorithm = algorithm; - this.kdf = kdf; + m_algorithm = algorithm ?? throw new ArgumentNullException(nameof(algorithm)); + m_kdf = kdf ?? throw new ArgumentNullException(nameof(kdf)); } - public override BigInteger CalculateAgreement( - ICipherParameters pubKey) + public override BigInteger CalculateAgreement(ICipherParameters pubKey) { - // Note that the ec.KeyAgreement class in JCE only uses kdf in one - // of the engineGenerateSecret methods. - - BigInteger result = base.CalculateAgreement(pubKey); - - int keySize = GeneratorUtilities.GetDefaultKeySize(algorithm); - - DHKdfParameters dhKdfParams = new DHKdfParameters( - new DerObjectIdentifier(algorithm), - keySize, - BigIntToBytes(result)); - - kdf.Init(dhKdfParams); + BigInteger result = base.CalculateAgreement(pubKey); - byte[] keyBytes = new byte[keySize / 8]; - kdf.GenerateBytes(keyBytes, 0, keyBytes.Length); - - return new BigInteger(1, keyBytes); - } - - private byte[] BigIntToBytes(BigInteger r) - { - int byteLength = X9IntegerConverter.GetByteLength(privParams.StaticPrivateKey.Parameters.Curve); - return X9IntegerConverter.IntegerToBytes(r, byteLength); + return BasicAgreementWithKdf.CalculateAgreementWithKdf(m_algorithm, m_kdf, GetFieldSize(), result); } } } diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs index 5fef5f877..041aeeed2 100644 --- a/crypto/src/security/AgreementUtilities.cs +++ b/crypto/src/security/AgreementUtilities.cs @@ -67,24 +67,19 @@ namespace Org.BouncyCastle.Security return GetBasicAgreementWithKdf(oid.Id, wrapAlgorithm); } - public static IBasicAgreement GetBasicAgreementWithKdf( - string agreeAlgorithm, - string wrapAlgorithm) + public static IBasicAgreement GetBasicAgreementWithKdf(string agreeAlgorithm, string wrapAlgorithm) { string mechanism = GetMechanism(agreeAlgorithm); // 'DHWITHSHA1KDF' retained for backward compatibility if (mechanism == "DHWITHSHA1KDF" || mechanism == "ECDHWITHSHA1KDF") - return new ECDHWithKdfBasicAgreement( - wrapAlgorithm, - new ECDHKekGenerator( - new Sha1Digest())); + return new ECDHWithKdfBasicAgreement(wrapAlgorithm, new ECDHKekGenerator(new Sha1Digest())); + + if (mechanism == "ECCDHWITHSHA1KDF") + return new ECDHCWithKdfBasicAgreement(wrapAlgorithm, new ECDHKekGenerator(new Sha1Digest())); if (mechanism == "ECMQVWITHSHA1KDF") - return new ECMqvWithKdfBasicAgreement( - wrapAlgorithm, - new ECDHKekGenerator( - new Sha1Digest())); + return new ECMqvWithKdfBasicAgreement(wrapAlgorithm, new ECDHKekGenerator(new Sha1Digest())); throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised."); } -- cgit 1.4.1