From 2746e44d62b031d0981d2f6b1bc3c7d2a34d64ec Mon Sep 17 00:00:00 2001 From: Peter Dettman Date: Sun, 6 Nov 2022 21:18:24 +0700 Subject: Add some dotnet ECDsa interop methods --- crypto/src/security/DotNetUtilities.cs | 118 ++++++++++++++++++++++++--------- 1 file changed, 86 insertions(+), 32 deletions(-) (limited to 'crypto/src/security') diff --git a/crypto/src/security/DotNetUtilities.cs b/crypto/src/security/DotNetUtilities.cs index 3a7c5f0cb..08853e45e 100644 --- a/crypto/src/security/DotNetUtilities.cs +++ b/crypto/src/security/DotNetUtilities.cs @@ -5,9 +5,12 @@ using System.Runtime.Versioning; using System.Security.Cryptography; using SystemX509 = System.Security.Cryptography.X509Certificates; +using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Pkcs; using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using Org.BouncyCastle.Utilities; @@ -50,23 +53,11 @@ namespace Org.BouncyCastle.Security public static AsymmetricCipherKeyPair GetDsaKeyPair(DSAParameters dp) { - DsaValidationParameters validationParameters = (dp.Seed != null) - ? new DsaValidationParameters(dp.Seed, dp.Counter) - : null; - - DsaParameters parameters = new DsaParameters( - new BigInteger(1, dp.P), - new BigInteger(1, dp.Q), - new BigInteger(1, dp.G), - validationParameters); - - DsaPublicKeyParameters pubKey = new DsaPublicKeyParameters( - new BigInteger(1, dp.Y), - parameters); + DsaPublicKeyParameters pubKey = GetDsaPublicKey(dp); DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters( new BigInteger(1, dp.X), - parameters); + pubKey.Parameters); return new AsymmetricCipherKeyPair(pubKey, privKey); } @@ -93,6 +84,62 @@ namespace Org.BouncyCastle.Security parameters); } +#if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER + public static AsymmetricCipherKeyPair GetECDsaKeyPair(ECDsa ecDsa) + { + return GetECKeyPair("ECDSA", ecDsa.ExportParameters(true)); + } + + public static ECPublicKeyParameters GetECDsaPublicKey(ECDsa ecDsa) + { + return GetECPublicKey("ECDSA", ecDsa.ExportParameters(false)); + } + + public static AsymmetricCipherKeyPair GetECKeyPair(string algorithm, ECParameters ec) + { + ECPublicKeyParameters pubKey = GetECPublicKey(algorithm, ec); + + ECPrivateKeyParameters privKey = new ECPrivateKeyParameters( + pubKey.AlgorithmName, + new BigInteger(1, ec.D), + pubKey.Parameters); + + return new AsymmetricCipherKeyPair(pubKey, privKey); + } + + public static ECPublicKeyParameters GetECPublicKey(string algorithm, ECParameters ec) + { + X9ECParameters x9 = GetX9ECParameters(ec.Curve); + if (x9 == null) + throw new NotSupportedException("Unrecognized curve"); + + return new ECPublicKeyParameters( + algorithm, + GetECPoint(x9.Curve, ec.Q), + new ECDomainParameters(x9)); + } + + private static Math.EC.ECPoint GetECPoint(Math.EC.ECCurve curve, ECPoint point) + { + return curve.CreatePoint(new BigInteger(1, point.X), new BigInteger(1, point.Y)); + } + + private static X9ECParameters GetX9ECParameters(ECCurve curve) + { + if (!curve.IsNamed) + throw new NotSupportedException("Only named curves are supported"); + + Oid oid = curve.Oid; + if (oid != null) + { + string oidValue = oid.Value; + if (oidValue != null) + return ECKeyPairGenerator.FindECCurveByOid(new DerObjectIdentifier(oidValue)); + } + return null; + } +#endif + public static AsymmetricCipherKeyPair GetRsaKeyPair(RSA rsa) { return GetRsaKeyPair(rsa.ExportParameters(true)); @@ -100,17 +147,11 @@ namespace Org.BouncyCastle.Security public static AsymmetricCipherKeyPair GetRsaKeyPair(RSAParameters rp) { - BigInteger modulus = new BigInteger(1, rp.Modulus); - BigInteger pubExp = new BigInteger(1, rp.Exponent); - - RsaKeyParameters pubKey = new RsaKeyParameters( - false, - modulus, - pubExp); + RsaKeyParameters pubKey = GetRsaPublicKey(rp); RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters( - modulus, - pubExp, + pubKey.Modulus, + pubKey.Exponent, new BigInteger(1, rp.D), new BigInteger(1, rp.P), new BigInteger(1, rp.Q), @@ -137,17 +178,18 @@ namespace Org.BouncyCastle.Security public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey) { - if (privateKey is DSA) - { - return GetDsaKeyPair((DSA)privateKey); - } + if (privateKey is DSA dsa) + return GetDsaKeyPair(dsa); - if (privateKey is RSA) - { - return GetRsaKeyPair((RSA)privateKey); - } +#if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER + if (privateKey is ECDsa ecDsa) + return GetECDsaKeyPair(ecDsa); +#endif - throw new ArgumentException("Unsupported algorithm specified", "privateKey"); + if (privateKey is RSA rsa) + return GetRsaKeyPair(rsa); + + throw new ArgumentException("Unsupported algorithm specified", nameof(privateKey)); } #if NET5_0_OR_GREATER @@ -244,6 +286,18 @@ namespace Org.BouncyCastle.Security return BigIntegers.AsUnsignedByteArray(size, n); } + // TODO Why do we use CspParameters instead of just RSA.Create in methods below? +// private static RSA CreateRSA(RSAParameters rp) +// { +//#if NETCOREAPP2_0_OR_GREATER || NET472_OR_GREATER || NETSTANDARD2_1_OR_GREATER +// return RSA.Create(rp); +//#else +// var rsa = RSA.Create(); +// rsa.ImportParameters(rp); +// return rsa; +//#endif +// } + #if NET5_0_OR_GREATER [SupportedOSPlatform("windows")] #endif -- cgit 1.4.1