Export EC private key from BouncyCastle and import

2019-05-25 05:03发布

问题:

I have created key pairs for elliptic curve DSA signatures using BouncyCastle and managed to import the public key into ECDsaCng using an XMLString accoding to RFC4050. Now I want to also move the private key and have not managed to find a solution. The closest I have got is using CngKey.Import.

CngKey.Import supports PKCS#8 format so if you can get your keys into valid pkcs8 then it should work. Unfortunately the following code does not quite work.

var privatekey = (ECPrivateKeyParameters) keyPair.Private;

var pkinfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privatekey);

byte[] pkcs8Blob = pkinfo.GetDerEncoded(); 

var importedKey = CngKey.Import(pkcs8Blob, CngKeyBlobFormat.Pkcs8PrivateBlob);

This throws an exception:

System.Security.Cryptography.CryptographicException: ASN1 bad tag value met.

GetDerEncoded should return a valid Pkcs8 blob as far as I can tell.

How can I use the private key created with BouncyCastle in a ECDsaCng object?

回答1:

After much hair-pulling, reading RFCs and studying the byte arrays generated by BouncyCastle and CngKey.Export I have found the answer.

The issue lies in how BouncyCastle encodes the EC key to DER/Pkcs8 format. The two RFCs which are relevant to this particular issue are RFC5915 (which is not a standard but instead a consensus document) and RFC5480. They state that curve parameters must be specified using named curves referenced in RFC5480. The BouncyCastle implementation of PKCS8/DER exporting will export the entire curve specification (implicit curve) which is not compliant with these two specs when you create the AsymmetricCipherKeyPair using the wrong generator parameters. You must use the ECKeyGenerationParameters which specify a named curve.

The following must be used (as far as I can tell) when creating interoperable keys in BouncyCastle:

string namedCurve = "prime256v1";
ECKeyPairGenerator pGen = new ECKeyPairGenerator();
ECKeyGenerationParameters genParam = new ECKeyGenerationParameters(
  X962NamedCurves.GetOid(namedCurve)   
  new SecureRandom());
pGen.Init(genParam);

AsymmetricCipherKeyPair keyPair = pGen.GenerateKeyPair();

The CngKey can be created by importing the key using the Der encoded bytes:

var bcKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
var pkcs8Blob = bcKeyInfo.GetDerEncoded();
var importedKey = CngKey.Import(pkcs8Blob, CngKeyBlobFormat.Pkcs8PrivateBlob);