Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
680 views
in Technique[技术] by (71.8m points)

.net - Importing ECC-based certificate from the Windows Certificate Store into CngKey

How can I get the public/private keys from an ECC-based X509Certificate2's into CngKey's for use with ECDsaCng and ECDiffieHellmanCng?

I'm currently using RSA 2048 bit key pairs to sign/encrypt stuff. I'm doing this by pulling the certificates from the X509Store where they are securely stored with private keys marked as non-exportable. I would like to convert the current implementation to use ECDSA and ECDH so that I can use smaller key sizes for equivalent security.

I've successfully generated ECC certs using openssl:

  1. openssl ecparam -out private.pem -name prime256v1 -genkey
  2. openssl req -new -key private.pem -x509 -nodes -days 365 -out public.cer
  3. openssl pkcs12 -export -in public.cer -inkey private.pem -out export.pfx

I've successfully installed the above generated certs in to the cert store. I can retrieve them by thumbprint, but the crypto providers for the private and public keys throw "Algorithm not supported" exceptions. Instead, I understand I'm supposed to use ECDsaCng and ECDiffieHellmanCng to sign/encrypt. But these deal in CngKey's.

Bouncy Castle isn't an option because it requires the private keys to be exportable.

CLR Security will return me a CngKey pair via GetCngPrivateKey but it cannot be used with ECDsa because the key returned by CLRSecurity is an ECDH key. Furthermore CLR Security doesn't give me a way to get just the public key from an X509Certificate2 for signature verification (where I don't even have or need the private key of the signer).

Any ideas? I'm at my wits end... Any help would be much appreciated.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to create the CngKey from the public key of the certificate (certificate.PublicKey.EncodedKeyValue.RawData):

The CngKey contains 8 additional bytes, the first 4 bytes (so called magic) are used for the name of the curve used (For ECDsa: ECS1, ECS3 or ECS5, For ECDH: ECK1, ECK3, ECK5), the last 4 are the length of the key incl. padding (32, 48 or 66).

The first byte of the public key from the certificate is removed (as it is always 0x04 for ECDSA public key).

So for instance for ECDSA using P-256 curve and SHA-256 hash algorithm, you will get a public key of length 65 bytes. Discard the first byte, leaving 64 bytes, then prefix with 4 bytes for curve and 4 bytes for key length i.e.:

var keyData = certificate.PublicKey.EncodedKeyValue.RawData.Skip(1).ToArray();
var keySize = BitConverter.GetBytes(keyData.Length/2);
var magic = Encoding.ASCII.GetBytes("ECS1").Concat()

var eccPublicBlobValue = magic.Concat(keySize).Concat(keyData).ToArray();

Now you have the public key (72 bytes) to create the CngKey from:

var cngKey = CngKey.Import(eccPublicBlobValue, CngKeyBlobFormat.EccPublicBlob);

var ecdsaCng = new ECDsaCng(cngKey);

And you can verify the signature:

return ecdsaCng.VerifyData(encodedBytes, signature);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...