I have a ASN.1 encoded RSA private key in a pem file in this format:
-----BEGIN RSA PRIVATE KEY-----
base64 encoded pkcs8 key
-----END RSA PRIVATE KEY-----
Now, to import it into my RSACng
object I neeed to follow these steps:
Read the file and extract the encoded key
Convert base64
to bytes to get the byte[]
for pkcs8 key
Decode the byte[]
from ASN.1 (DER) to key information (modulus, exponent etc.)
Load these parameters into the RSACng
object
I have two following questions:
1. Why doesn't the CngKeyBlobFormat.Pkcs8PrivateBlob
allow you to automatically import the PKCS8 byte[]
key into the RSACng
object?
For instance, why couldn't it work in this way:
var keyData = GetBytesFromPEM(pemstring); // Get the bytes for key that is ASN.1 DER encoded
CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob);
CngKeyBlobFormat clearly specifies that it is a PKCS8 private blob.
2. What is the ASN.1 encoding format of the RSACng.Key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob)
?
I noticed that if I load the key into the RSACng
as I described above and I then export the same key using the above code, I get the BLOB which is encoded in a different ASN.1 format, and which INSIDE it contains the ASN.1 DER encoded key. Basically, to get information from this exported key I would need to DECODE it from this ASN.1 format again to get the original key parameters stored inside it which are AGAIN encoded in ASN.1 DER.
Why is it such a mess? And is the reason why you cannot import the ASN.1 DER encoded key into the RSACng
that CngKeyBlobFormat.Pkcs8PrivateBlob
has a different ASN.1 encoding format and it is not DER? Would the potential workaround then be to encode the original RSA private key to that another ASN.1 format, since this is exactly how the key is exported?
EDIT: apparently, RSACng.Key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob)
uses Object Identifiers (I'm not yet familiar with that), but it seems to still be in DER format
- Why doesn't the CngKeyBlobFormat.Pkcs8PrivateBlob allow you to automatically import the PKCS8 byte[] key into the RSACng object?
Because BEGIN RSA PRIVATE KEY
indicates a PKCS#1 RSAPrivateKey
, not a PKCS#8 PrivateKeyInfo
. A PKCS#8 non-encrypted private key would say BEGIN PRIVATE KEY
.
- What is the ASN.1 encoding format of the
RSACng.Key.Export(CngKeyBlobFormat.Pkcs8PrivateBlob)
?
PKCS#8 PrivateKeyInfo. https://www.rfc-editor.org/rfc/rfc5208#section-5.
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
privateKey PrivateKey,
attributes [0] IMPLICIT Attributes OPTIONAL }
Version ::= INTEGER
PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
PrivateKey ::= OCTET STRING
Attributes ::= SET OF Attribute
The value in PrivateKey
for an RSA key is the PKCS#1 RSAPrivateKey
value.
Why is it such a mess? ... Object Identifiers ...
The PKCS#8 PrivateKeyInfo format is a container for any kind of private key. The Object Identifier (OID) tells the reader what kind of thing the payload is. If the OID is rsaEncryption
(1.2.840.113549.1.1.1) then the payload is RSAPrivateKey
, if it's id-dsa
(1.2.840.10040.4.1) then the payload is an INTEGER representing the private key (and the context parameters are in privateKeyAlgorithm.Parameters
), if it's id-ecPublicKey
(1.2.840.10045.2.1) (yes "public", 'cuz names) then the payload is an ECPrivateKey
, et cetera.