Home > Blockchain >  Does the X509Certificate2 GetRSAPrivateKey method also return public key data?
Does the X509Certificate2 GetRSAPrivateKey method also return public key data?

Time:09-15

I was doing some work involving asymmetric encryption (signing and decoding JSON Web Tokens) using certificates to provide the keys.

While doing some tests, I happened to notice that the JWT could be both encoded and decoded using the result of GetRSAPrivateKey() (called on the loaded certificate). This was surprising because the decoding/encoding algorithm is asymmetric.

This lead to the question was there an issue with the JWT library I was using or does GetRSAPrivateKey() include public key information in its response.

Example code:

var certificatePath = @"PATH TO CERTIFICATE";

var payload = new Dictionary<string, object>();
payload.Add("Nosey", "Parker");

var cert = new X509Certificate2(certificatePath, string.Empty, X509KeyStorageFlags.Exportable);

var token = Jose.JWT.Encode(payload, cert.GetRSAPrivateKey(), Jose.JwsAlgorithm.RS256);
var claims = Jose.JWT.Decode(token, cert.GetRSAPrivateKey(), Jose.JwsAlgorithm.RS256);

Note: the example code is for a .pfx file that contains both a public and private key.

CodePudding user response:

Using the below code to extract the private & public key data into byte arrays, you can see that GetRSAPrivateKey() does return public key data in addition to the private key despite this not being mentioned in the official documentation: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.rsacertificateextensions.getrsaprivatekey?view=net-6.0

var privateKeyBytes = cert.GetRSAPrivateKey()?.ExportRSAPrivateKey();
var publicKeyBytes = cert.GetRSAPrivateKey()?.ExportRSAPublicKey();

CodePudding user response:

The short answer is that in all cryptographic libraries (barring someone having done something weird) the private key can always be either used as a public key or produce the public key. In .NET the paradigm is that a private key instance can always be used as a public key.

In asymmetric cryptography, a private key can always recreate the public key; it's the other way around that's infeasibly hard.

For RSA keys the public key is the modulus (n) and the public exponent (e), and the minimal private key is the modulus (n) and the private exponent (d). From just (n, d) it's actually quite hard to figure out e (except that it's almost always 65537), but it turns out that not only does (effectively) no one use the minimal private key (preferring instead the "CRT" private key consisting of (n, d, p, q, dp, dq, qInv)), that the public standard data format for RSA private keys includes the e value:

     RSAPrivateKey ::= SEQUENCE {
         version           Version,
         modulus           INTEGER,  -- n
         publicExponent    INTEGER,  -- e
         privateExponent   INTEGER,  -- d
         prime1            INTEGER,  -- p
         prime2            INTEGER,  -- q
         exponent1         INTEGER,  -- d mod (p-1)
         exponent2         INTEGER,  -- d mod (q-1)
         coefficient       INTEGER,  -- (inverse of q) mod p
         otherPrimeInfos   OtherPrimeInfos OPTIONAL

For DSA the nomenclature splits the totality of the key into the "domain parameters" (p, g, q) and "the key" (x for the private key and y for the public key). The standard data format for DSA private keys does not include the y value, but it's easily recalculated from (p, g, q, x). So, DSA private keys can always produce their public key value.

ECC (ECDSA/ECDH/etc) is a bit like DSA, there's the context (what curve you're on) and then the unique portion of the key. "The curve" includes a base generator point (G), and the private key is just a number (d). d * G gives Q, the public key. So ECC keys can always recreate their public key. The standard data format for EC private keys "optionally" includes the public key just to avoid the need for tedious computation on the part of someone loading the key. I put optionally in quotes because it goes on to say "Though the ASN.1 indicates publicKey is OPTIONAL, implementations that conform to this document SHOULD always include the publicKey field."

  • Related