summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2014-07-21 20:05:27 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2014-07-21 20:05:27 +0700
commit0c51033abe10b6a2b0035ea6bab8c471be6f45dc (patch)
tree8e48802b9c29d98996cf49b92726ec81ab0edcb2
parentPort of PrivateKeyInfo changes from Java (diff)
downloadBouncyCastle.NET-ed25519-0c51033abe10b6a2b0035ea6bab8c471be6f45dc.tar.xz
BMA-105
Support for parsing Gost3410x2001 private keys encoded as DER Integer
Miscellaneous support methods ported from Java
-rw-r--r--crypto/src/asn1/sec/ECPrivateKeyStructure.cs226
-rw-r--r--crypto/src/security/PrivateKeyFactory.cs27
-rw-r--r--crypto/src/util/Arrays.cs16
3 files changed, 148 insertions, 121 deletions
diff --git a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
index 2e9c27fd2..8d805fa30 100644
--- a/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
+++ b/crypto/src/asn1/sec/ECPrivateKeyStructure.cs
@@ -6,113 +6,121 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Sec
 {
-	/**
-	 * the elliptic curve private key object from SEC 1
-	 */
-	public class ECPrivateKeyStructure
-		: Asn1Encodable
-	{
-		private readonly Asn1Sequence seq;
-
-		public ECPrivateKeyStructure(
-			Asn1Sequence seq)
-		{
-			if (seq == null)
-				throw new ArgumentNullException("seq");
-
-			this.seq = seq;
-		}
-
-		public ECPrivateKeyStructure(
-			BigInteger key)
-		{
-			if (key == null)
-				throw new ArgumentNullException("key");
-
-			this.seq = new DerSequence(
-				new DerInteger(1),
-				new DerOctetString(key.ToByteArrayUnsigned()));
-		}
-
-		public ECPrivateKeyStructure(
-			BigInteger		key,
-			Asn1Encodable	parameters)
-			: this(key, null, parameters)
-		{
-		}
-
-		public ECPrivateKeyStructure(
-			BigInteger		key,
-			DerBitString	publicKey,
-			Asn1Encodable	parameters)
-		{
-			if (key == null)
-				throw new ArgumentNullException("key");
-
-			Asn1EncodableVector v = new Asn1EncodableVector(
-				new DerInteger(1),
-				new DerOctetString(key.ToByteArrayUnsigned()));
-
-			if (parameters != null)
-			{
-				v.Add(new DerTaggedObject(true, 0, parameters));
-			}
-
-			if (publicKey != null)
-			{
-				v.Add(new DerTaggedObject(true, 1, publicKey));
-			}
-
-			this.seq = new DerSequence(v);
-		}
-
-		public BigInteger GetKey()
-		{
-			Asn1OctetString octs = (Asn1OctetString) seq[1];
-
-			return new BigInteger(1, octs.GetOctets());
-		}
-
-		public DerBitString GetPublicKey()
-		{
-			return (DerBitString) GetObjectInTag(1);
-		}
-
-		public Asn1Object GetParameters()
-		{
-			return GetObjectInTag(0);
-		}
-
-		private Asn1Object GetObjectInTag(
-			int tagNo)
-		{
-			foreach (Asn1Encodable ae in seq)
-			{
-				Asn1Object obj = ae.ToAsn1Object();
-
-				if (obj is Asn1TaggedObject)
-				{
-					Asn1TaggedObject tag = (Asn1TaggedObject) obj;
-					if (tag.TagNo == tagNo)
-					{
-						return tag.GetObject();
-					}
-				}
-			}
-
-			return null;
-		}
-
-		/**
-		 * ECPrivateKey ::= SEQUENCE {
-		 *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
-		 *     privateKey OCTET STRING,
-		 *     parameters [0] Parameters OPTIONAL,
-		 *     publicKey [1] BIT STRING OPTIONAL }
-		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			return seq;
-		}
-	}
+    /**
+     * the elliptic curve private key object from SEC 1
+     */
+    public class ECPrivateKeyStructure
+        : Asn1Encodable
+    {
+        private readonly Asn1Sequence seq;
+
+        public static ECPrivateKeyStructure GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is ECPrivateKeyStructure)
+                return (ECPrivateKeyStructure)obj;
+            return new ECPrivateKeyStructure(Asn1Sequence.GetInstance(obj));
+        }
+
+        public ECPrivateKeyStructure(
+            Asn1Sequence seq)
+        {
+            if (seq == null)
+                throw new ArgumentNullException("seq");
+
+            this.seq = seq;
+        }
+
+        public ECPrivateKeyStructure(
+            BigInteger key)
+        {
+            if (key == null)
+                throw new ArgumentNullException("key");
+
+            this.seq = new DerSequence(
+                new DerInteger(1),
+                new DerOctetString(key.ToByteArrayUnsigned()));
+        }
+
+        public ECPrivateKeyStructure(
+            BigInteger		key,
+            Asn1Encodable	parameters)
+            : this(key, null, parameters)
+        {
+        }
+
+        public ECPrivateKeyStructure(
+            BigInteger		key,
+            DerBitString	publicKey,
+            Asn1Encodable	parameters)
+        {
+            if (key == null)
+                throw new ArgumentNullException("key");
+
+            Asn1EncodableVector v = new Asn1EncodableVector(
+                new DerInteger(1),
+                new DerOctetString(key.ToByteArrayUnsigned()));
+
+            if (parameters != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, parameters));
+            }
+
+            if (publicKey != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, publicKey));
+            }
+
+            this.seq = new DerSequence(v);
+        }
+
+        public virtual BigInteger GetKey()
+        {
+            Asn1OctetString octs = (Asn1OctetString) seq[1];
+
+            return new BigInteger(1, octs.GetOctets());
+        }
+
+        public virtual DerBitString GetPublicKey()
+        {
+            return (DerBitString) GetObjectInTag(1);
+        }
+
+        public virtual Asn1Object GetParameters()
+        {
+            return GetObjectInTag(0);
+        }
+
+        private Asn1Object GetObjectInTag(int tagNo)
+        {
+            foreach (Asn1Encodable ae in seq)
+            {
+                Asn1Object obj = ae.ToAsn1Object();
+
+                if (obj is Asn1TaggedObject)
+                {
+                    Asn1TaggedObject tag = (Asn1TaggedObject) obj;
+                    if (tag.TagNo == tagNo)
+                    {
+                        return tag.GetObject();
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        /**
+         * ECPrivateKey ::= SEQUENCE {
+         *     version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+         *     privateKey OCTET STRING,
+         *     parameters [0] Parameters OPTIONAL,
+         *     publicKey [1] BIT STRING OPTIONAL }
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return seq;
+        }
+    }
 }
diff --git a/crypto/src/security/PrivateKeyFactory.cs b/crypto/src/security/PrivateKeyFactory.cs
index c346352f5..1cfa37afe 100644
--- a/crypto/src/security/PrivateKeyFactory.cs
+++ b/crypto/src/security/PrivateKeyFactory.cs
@@ -15,6 +15,7 @@ using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Security
 {
@@ -134,13 +135,23 @@ namespace Org.BouncyCastle.Security
                 Gost3410PublicKeyAlgParameters gostParams = new Gost3410PublicKeyAlgParameters(
                     Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
 
-                ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
-                    Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey()));
+                Asn1Object privKey = keyInfo.ParsePrivateKey();
+                ECPrivateKeyStructure ec;
+
+                if (privKey is DerInteger)
+                {
+                    // TODO Do we need to pass any parameters here?
+                    ec = new ECPrivateKeyStructure(((DerInteger)privKey).Value);
+                }
+                else
+                {
+                    ec = ECPrivateKeyStructure.GetInstance(privKey);
+                }
 
                 ECDomainParameters ecP = ECGost3410NamedCurves.GetByOid(gostParams.PublicKeyParamSet);
 
                 if (ecP == null)
-                    return null;
+                    throw new ArgumentException("Unrecognized curve OID for GostR3410x2001 private key");
 
                 return new ECPrivateKeyParameters("ECGOST3410", ec.GetKey(), gostParams.PublicKeyParamSet);
             }
@@ -150,15 +161,7 @@ namespace Org.BouncyCastle.Security
                     Asn1Sequence.GetInstance(algID.Parameters.ToAsn1Object()));
 
                 DerOctetString derX = (DerOctetString)keyInfo.ParsePrivateKey();
-                byte[] keyEnc = derX.GetOctets();
-                byte[] keyBytes = new byte[keyEnc.Length];
-
-                for (int i = 0; i != keyEnc.Length; i++)
-                {
-                    keyBytes[i] = keyEnc[keyEnc.Length - 1 - i]; // was little endian
-                }
-
-                BigInteger x = new BigInteger(1, keyBytes);
+                BigInteger x = new BigInteger(1, Arrays.Reverse(derX.GetOctets()));
 
                 return new Gost3410PrivateKeyParameters(x, gostParams.PublicKeyParamSet);
             }
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index a21dd00b1..37da3940f 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -396,5 +396,21 @@ namespace Org.BouncyCastle.Utilities
             Array.Copy(b, 0, rv, a.Length, b.Length);
             return rv;
         }
+
+        public static byte[] Reverse(byte[] a)
+        {
+            if (a == null)
+                return null;
+
+            int p1 = 0, p2 = a.Length;
+            byte[] result = new byte[p2];
+
+            while (--p2 >= 0)
+            {
+                result[p2] = a[p1++];
+            }
+
+            return result;
+        }
     }
 }