Search code examples
c#cryptographyx509certificate2

Loading an ECC private key in .NET


I have an ECC private and a certificate file which includes the public key. I can get them in either PEM or DER formats.

I can read the certificate into an X509Certificate with this code:

var certbytes = File.ReadAllBytes("certificate.pem");
var cert = new X509Certificate2(certbytes);

But I'm unable to load the private key. I've tried this code:

var keyContent = File.ReadAllBytes("certificate_private_key.pem");
var key = CngKey.Import(keyContent, CngKeyBlobFormat.EccPrivateBlob);

It throws Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'An error occurred during encode or decode operation'.

I've also tried other values of the CngKeyBlobFormat parameter. The Import method fails with those as well.

openssl can read the file, and it outputs the following information about it:

openssl ec -in certificate_private_key.pem -text
read EC key
Private-Key: (256 bit)
priv:
    44:<cut>:68
pub:
    04:<cut>:13
ASN1 OID: prime256v1
NIST CURVE: P-256
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHcC <cut here>
-----END EC PRIVATE KEY-----

Is there built-in API in .NET or .NET Core which can do this? Or are there 3rd party libraries that can do it, and how?


Solution

  • .NET Core 3.0 (currently in preview) has ECDsa.ImportECPrivateKey, AsymmetricAlgorithm.ImportPkcs8PrivateKey, and AsymmetricAlgorithm.ImportEncryptedPkcs8PrivateKey, (and RSA has RSAPublicKey and RSAPrivateKey) and for the current file (BEGIN EC PRIVATE KEY) you'd want the first one.

    • The good news of those methods is: they exist.
    • The bad news is: They're part of the next version, not the current one.
    • Good: The next version should be the current version soonishly.
    • Bad: They only understand BER/DER data, not PEM.

    The last point means that you currently would have to find the base64 content between the -----BEGIN EC PRIVATE KEY-----\n and \n-----END EC PRIVATE KEY----- and de-base64-it, then pass that into the methods.


    The only private key formats that I know that are supported by CNG import are PKCS8, encrypted PKCS8, and CNG private formats. To use CngKey.Import you'd first need to convert the keyfile to PKCS#8 then specify that the format is Pkcs8PrivateBlob, as suggested in the comments.