summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2022-11-06 21:18:24 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2022-11-06 21:18:24 +0700
commit2746e44d62b031d0981d2f6b1bc3c7d2a34d64ec (patch)
tree2c7bf5cebc66cd4ade8e30fa6a3a2c8221fcf839
parentCMS support for OtherRevocationInfoFormat (diff)
downloadBouncyCastle.NET-ed25519-2746e44d62b031d0981d2f6b1bc3c7d2a34d64ec.tar.xz
Add some dotnet ECDsa interop methods
-rw-r--r--crypto/src/security/DotNetUtilities.cs118
-rw-r--r--crypto/test/src/security/test/TestDotNetUtil.cs32
2 files changed, 117 insertions, 33 deletions
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
diff --git a/crypto/test/src/security/test/TestDotNetUtil.cs b/crypto/test/src/security/test/TestDotNetUtil.cs
index b83a94a36..5d0177ead 100644
--- a/crypto/test/src/security/test/TestDotNetUtil.cs
+++ b/crypto/test/src/security/test/TestDotNetUtil.cs
@@ -22,6 +22,36 @@ namespace Org.BouncyCastle.Security.Tests
 	[TestFixture]
     public class TestDotNetUtilities
 	{
+//#if NETCOREAPP1_0_OR_GREATER || NET47_OR_GREATER || NETSTANDARD1_6_OR_GREATER
+#if NET6_0_OR_GREATER
+        [Test]
+		public void TestECDsaInterop()
+		{
+			byte[] data = new byte[1024];
+
+            for (int i = 0; i < 10; ++i)
+			{
+                var ecDsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
+				byte[] sig1 = ecDsa.SignData(data, HashAlgorithmName.SHA256);
+
+                AsymmetricCipherKeyPair kp = DotNetUtilities.GetECDsaKeyPair(ecDsa);
+                Assert.IsNotNull(kp.Private);
+                Assert.IsNotNull(kp.Public);
+                ISigner signer = SignerUtilities.GetSigner("SHA256withPLAIN-ECDSA");
+
+                signer.Init(false, kp.Public);
+                signer.BlockUpdate(data, 0, data.Length);
+                Assert.IsTrue(signer.VerifySignature(sig1));
+
+				signer.Init(true, kp.Private);
+				signer.BlockUpdate(data, 0, data.Length);
+				byte[] sig2 = signer.GenerateSignature();
+
+                Assert.IsTrue(ecDsa.VerifyData(data, sig2, HashAlgorithmName.SHA256));
+            }
+        }
+#endif
+
 //#if NET5_0_OR_GREATER
 #if NET6_0_OR_GREATER
         [SupportedOSPlatform("windows")]
@@ -29,7 +59,7 @@ namespace Org.BouncyCastle.Security.Tests
         [Test]
 		public void TestRsaInterop()
 		{
-			for (int i = 0; i < 100; ++i)
+			for (int i = 0; i < 10; ++i)
 			{
 				RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(512);
 				RSAParameters rp = rsa.ExportParameters(true);