Import an ECDSA public key from CngKey to BouncyCastle

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Import an ECDSA public key from CngKey to BouncyCastle

sesteve
This post was updated on 12:31, 07.Oct.2016.
Hi all,

I am trying to generate an x509 certificate from a pair of keys generated with CngKey.
I create the keys with:

            var parameters = new CngKeyCreationParameters
            {
                Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
                ExportPolicy = CngExportPolicies.AllowPlaintextExport,
                KeyCreationOptions = CngKeyCreationOptions.OverwriteExistingKey,
                KeyUsage = CngKeyUsages.AllUsages,
                UIPolicy = new CngUIPolicy(CngUIProtectionLevels.None)
            };
            var key = CngKey.Create(CngAlgorithm.ECDsaP384, container, parameters);
            byte[] ecPriKey = key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob);
            byte[] ecPubKey = key.Export(CngKeyBlobFormat.EccPublicBlob);

I get a BouncyCastle private key with:
            AsymmetricKeyParameter akPrivate = PrivateKeyFactory.CreateKey(ecPriKey);
And I have no trouble in it, so that I can see the proper curve's parameters from the key.

However, when I try to get the public key with:
                        string publicKeyBase64 = Convert.ToBase64String(ecPubKey);
                        byte[] ecPubKey2 = Base64.Decode(publicKeyBase64);
                        byte[] ecPublicKey = new byte[ecPubKey.Length -7];
                        ecPublicKey[0] = 0x04;
                        Array.Copy(ecPubKey, 8, ecPublicKey, 7, ecPublicKey.Length);
                        AsymmetricKeyParameter akPublic = PublicKeyFactory.CreateKey(ecPublicKey - 1);
I read I have to erase the 8 first digits from CngKey and add the uncompressed const value 0x04.
When I execute "PublicKeyFactory.CreateKey(ecPublicKey)" I get the exception:

- ex {"extra data found after object"} System.Exception {System.IO.IOException}
+ Data {System.Collections.ListDictionaryInternal} System.Collections.IDictionary {System.Collections.ListDictionaryInternal}
                HResult 0x80131620 int
                HelpLink null string
+ InnerException null System.Exception
                Message "extra data found after object" string
                Source "BouncyCastle.Crypto" string
                StackTrace "   at Org.BouncyCastle.Asn1.Asn1Object.FromByteArray(Byte[] data)\r\n   at Org.BouncyCastle.Security.PublicKeyFactory.CreateKey(Byte[] keyInfoData)\r\n   at Plpm.Csp.Security.KeyTool.SecurityKeyTool.OpGenEc(String[] args) in C:\\Projects\\TLS-ECC\\SecurityKeyTool\\SecurityKeyTool\\SecurityKeyTool.cs:line 651\r\n   at Plpm.Csp.Security.KeyTool.SecurityKeyTool.Main(String[] args) in C:\\Projects\\TLS-ECC\\SecurityKeyTool\\SecurityKeyTool\\SecurityKeyTool.cs:line 138" string
+ TargetSite {Org.BouncyCastle.Asn1.Asn1Object FromByteArray(Byte[])} System.Reflection.MethodBase {System.Reflection.RuntimeMethodInfo}
+ Static members
+ Non-Public members

Anyway, I get the same if I do this directly with the key as
  AsymmetricKeyParameter akPublic = PublicKeyFactory.CreateKey(ecPubKey);

Can you, please, give me some ideas about why is this error with public key.

Thank you so much.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Import an ECDSA public key from CngKey to BouncyCastle

Pitonyak, Andrew D
I do not entirely understand your uses, but when I needed / wanted to exchange ECDsaP521 with some Microsoft libraries, I manually changed the encodings. I posted how I did this here:

http://stackoverflow.com/questions/34618755/verify-bouncycastle-ecdsa-signature-with-net-libraries-ecdsacng/34770707#34770707

More specifically, I converted from the Bouncy Castle ASN.1/DER format to IEEE P-1393 format as follows:

public static byte[] ConvertDerToP1393(byte[] data)
{
    byte[] b = new byte[132];
    int totalLength = data[1];
    int n = 0;
    int offset = 4;
    int thisLength = data[offset++];
    if (data[offset] == 0)  {
        // Negative number!
        ++offset;
        --thisLength;
    }
    for (int i= thisLength; i < 66; ++i) {
        b[n++] = 0;
    }
    if (thisLength > 66) {
        System.Console.WriteLine("BAD, first number is too big! " + thisLength);
    } else {
        for (int i = 0; i < thisLength; ++i) {
            b[n++] = data[offset++];
        }
    }
    ++offset;
    thisLength = data[offset++];

    for (int i = thisLength; i < 66; ++i){
        b[n++] = 0;
    }
    if (thisLength > 66) {
        System.Console.WriteLine("BAD, second number is too big! " + thisLength);
    } else {
        for (int i = 0; i < thisLength; ++i) {
            b[n++] = data[offset++];
        }
    }
    return b;
}

The link shows my initial test code.

-----Original Message-----
From: sesteve [mailto:[hidden email]]
Sent: Tuesday, October 18, 2016 5:21 AM
To: [hidden email]
Subject: [dev-crypto] Import an ECDSA public key from CngKey to BouncyCastle

This post was updated on 12:31, 07.Oct.2016.
Hi all,

I am trying to generate an x509 certificate from a pair of keys generated with CngKey.
I create the keys with:

            var parameters = new CngKeyCreationParameters
            {
                Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
                ExportPolicy = CngExportPolicies.AllowPlaintextExport,
                KeyCreationOptions =
CngKeyCreationOptions.OverwriteExistingKey,
                KeyUsage = CngKeyUsages.AllUsages,
                UIPolicy = new CngUIPolicy(CngUIProtectionLevels.None)
            };
            var key = CngKey.Create(CngAlgorithm.ECDsaP384, container, parameters);
            byte[] ecPriKey = key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob);
            byte[] ecPubKey = key.Export(CngKeyBlobFormat.EccPublicBlob);

I get a BouncyCastle private key with:
            AsymmetricKeyParameter akPrivate = PrivateKeyFactory.CreateKey(ecPriKey);
And I have no trouble in it, so that I can see the proper curve's parameters from the key.

However, when I try to get the public key with:
                        string publicKeyBase64 = Convert.ToBase64String(ecPubKey);
                        byte[] ecPubKey2 = Base64.Decode(publicKeyBase64);
                        byte[] ecPublicKey = new byte[ecPubKey.Length -7];
                        ecPublicKey[0] = 0x04;
                        Array.Copy(ecPubKey, 8, ecPublicKey, 7, ecPublicKey.Length);
                        AsymmetricKeyParameter akPublic = PublicKeyFactory.CreateKey(ecPublicKey - 1); I read I have to erase the 8 first digits from CngKey and add the uncompressed const value 0x04.
When I execute "PublicKeyFactory.CreateKey(ecPublicKey)" I get the
exception:

- ex {"extra data found after object"} System.Exception
{System.IO.IOException}
+ Data {System.Collections.ListDictionaryInternal}
System.Collections.IDictionary {System.Collections.ListDictionaryInternal}
                HResult 0x80131620 int
                HelpLink null string
+ InnerException null System.Exception
                Message "extra data found after object" string
                Source "BouncyCastle.Crypto" string
                StackTrace "   at
Org.BouncyCastle.Asn1.Asn1Object.FromByteArray(Byte[] data)\r\n   at
Org.BouncyCastle.Security.PublicKeyFactory.CreateKey(Byte[] keyInfoData)\r\n at Plpm.Csp.Security.KeyTool.SecurityKeyTool.OpGenEc(String[] args) in C:\\Projects\\TLS-ECC\\SecurityKeyTool\\SecurityKeyTool\\SecurityKeyTool.cs:line
651\r\n   at Plpm.Csp.Security.KeyTool.SecurityKeyTool.Main(String[] args)
in
C:\\Projects\\TLS-ECC\\SecurityKeyTool\\SecurityKeyTool\\SecurityKeyTool.cs:line
138" string
+ TargetSite {Org.BouncyCastle.Asn1.Asn1Object FromByteArray(Byte[])}
System.Reflection.MethodBase {System.Reflection.RuntimeMethodInfo}
+ Static members
+ Non-Public members

Anyway, I get the same if I do this directly with the key as
  AsymmetricKeyParameter akPublic = PublicKeyFactory.CreateKey(ecPubKey);

Can you, please, give me some ideas about why is this error with public key.

Thank you so much.



--
View this message in context: http://bouncy-castle.1462172.n4.nabble.com/Import-an-ECDSA-public-key-from-CngKey-to-BouncyCastle-tp4658365.html
Sent from the Bouncy Castle - Dev mailing list archive at Nabble.com.


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Import an ECDSA public key from CngKey to BouncyCastle

sesteve
Thank you for your reply, but it is not the same case.

In yours, you are using a BouncyCastle key in MS, so you convert it.

My case is the opposite, from a CngKey I want to get the public and private keys so as to using them in BouncyCastle.
I can get the private key without troubles with:
                        byte[] ecPriKey = key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob);
                        AsymmetricKeyParameter akPrivate = PrivateKeyFactory.CreateKey(ecPriKey);

But it fails with public key:
                        byte[] ecPubKey = key.Export(CngKeyBlobFormat.EccPublicBlob);
                        AsymmetricKeyParameter akPublic = PublicKeyFactory.CreateKey(ecPubKey);
Throwing the exception {"extra data found after object"}

Thanks again
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Import an ECDSA public key from CngKey to BouncyCastle

Pitonyak, Andrew D
I would expect that you could look at the conversion code and use that to then take it in the other direction for use in Bouncy Castle.

-----Original Message-----
From: sesteve [mailto:[hidden email]]
Sent: Wednesday, October 19, 2016 4:35 AM
To: [hidden email]
Subject: [dev-crypto] RE: Import an ECDSA public key from CngKey to BouncyCastle

Thank you for your reply, but it is not the same case.

In yours, you are using a BouncyCastle key in MS, so you convert it.

My case is the opposite, from a CngKey I want to get the public and private keys so as to using them in BouncyCastle.
I can get the private key without troubles with:
                        byte[] ecPriKey = key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob);
                        AsymmetricKeyParameter akPrivate = PrivateKeyFactory.CreateKey(ecPriKey);

But it fails with public key:
                        byte[] ecPubKey = key.Export(CngKeyBlobFormat.EccPublicBlob);
                        AsymmetricKeyParameter akPublic = PublicKeyFactory.CreateKey(ecPubKey);
Throwing the exception {"extra data found after object"}

Thanks again



--
View this message in context: http://bouncy-castle.1462172.n4.nabble.com/Import-an-ECDSA-public-key-from-CngKey-to-BouncyCastle-tp4658365p4658370.html
Sent from the Bouncy Castle - Dev mailing list archive at Nabble.com.


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Import an ECDSA public key from CngKey to BouncyCastle

sesteve
It is possible I am wrong, but I think those are different cases.

You are talking about signatures and I am talking about public keys.
I don't see in the key the structure you are managing in your function.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Import an ECDSA public key from CngKey to BouncyCastle

Pitonyak, Andrew D
Could be true.....

-----Original Message-----
From: sesteve [mailto:[hidden email]]
Sent: Wednesday, October 19, 2016 11:03 AM
To: [hidden email]
Subject: [dev-crypto] RE: Import an ECDSA public key from CngKey to BouncyCastle

It is possible I am wrong, but I think those are different cases.

You are talking about signatures and I am talking about public keys.
I don't see in the key the structure you are managing in your function.



--
View this message in context: http://bouncy-castle.1462172.n4.nabble.com/Import-an-ECDSA-public-key-from-CngKey-to-BouncyCastle-tp4658365p4658372.html
Sent from the Bouncy Castle - Dev mailing list archive at Nabble.com.


Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

RE: Import an ECDSA public key from CngKey to BouncyCastle

sesteve
I think I got it. I found some BouncyCastle functions which solve it.

Secondly, I read my CngKey from the container and get the byte arrays with the key pair:


                container = "EccCertTest";
                key = CngKey.Open(container);
                byte[] ecPriKey = key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob);
                byte[] ecPubKey = key.Export(CngKeyBlobFormat.EccPublicBlob);


The public key has this sequence at the beginning:
                4543533330000000
with the KeyType and KeyLength, it has to be removed and create a new byte array with 0x04 at the beginning (uncompressed key format), and concat with the public key. Now that we have the new array, it can be deserialized and get ECPublicKeyParameters value:


                ECDomainParameters ecdp = TlsEccUtilities.GetParametersForNamedCurve(NamedCurve.secp384r1);
                byte[] ecPublicKey = new byte[ecPubKey.Length - 7];
                ecPublicKey[0] = 0x04;
                Array.Copy(ecPubKey, 8, ecPublicKey, 1, ecPublicKey.Length - 1);
                var basePoint = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(null, ecdp, ecPublicKey));
                SubjectPublicKeyInfo subinfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(basePoint);

                AsymmetricKeyParameter akPrivate = PrivateKeyFactory.CreateKey(ecPriKey);
                AsymmetricKeyParameter akPublic = PublicKeyFactory.CreateKey(subinfo);


Finally, I could get the private and public key parameter, and create the certificate with them.

I hope it is enough...

Thanks for your help and time!
Loading...