35

What is the best way to initate a new RSACryptoServiceProvider object from an X509Certificate2 I pulled out of a key store? The certificate is associated with both public (for encryption) and private (for decryption) keys.

I'm current using the FromXmlString method but there must be a better way.

Thanks

Rosdi Kasim
  • 24,267
  • 23
  • 130
  • 154
Petey B
  • 11,439
  • 25
  • 81
  • 101
  • Please consider changing the accepted answer to Rosdi Kasim's. The currently accepted answer is now very out of date and unreliable. – NickG Jun 09 '20 at 17:09

3 Answers3

51

Note: While this is the accepted answer and was valid back in 2011, this code won't work now under .NET Core. See this answer if you are using .NET Framework 4.6+, or .NET Core / .NET.

RSACryptoServiceProvider publicKeyProvider = 
    (RSACryptoServiceProvider)certificate.PublicKey.Key;

and

RSACryptoServiceProvider privateKeyProvider = 
    (RSACryptoServiceProvider)certificate.PrivateKey;

The key property on the public or private key property of the certificate is of type AsymmetricAlgorithm.

Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
blowdart
  • 55,577
  • 12
  • 114
  • 149
  • Thanks blowdart, worked like a charm. Maybe I should buy your book. – Petey B May 03 '11 at 17:10
  • Note: should be `certificate.PrivateKey;` not `certificate.PrivateKey.Key;` – Petey B May 03 '11 at 17:42
  • Great answer, short and sweet. Are the non-RSA providers just irrelevant? Presumably there's a reason why these properties are AsymmetricAlgorithm, and no guarantee their runtime type will actually be RSACryptoServiceProvider..? – The Dag Mar 08 '12 at 12:54
  • Well Elliptic Curve is also asymmetric, but there's no real concept of keys. And of course a base class makes for expandability should someone come out with something greater. – blowdart Mar 10 '12 at 06:25
  • I'll buy his book if he covers RSA keys, import exports. I gave up reading and writing ASN.1 public keys formatted as SubjectPublicKeyInfo. Went to Bouncy Castle and am 99% of the way there. (PS you working on AntiXSS on codeplex? When is the next version?) – makerofthings7 Jul 02 '12 at 02:03
  • Know what's funny? Exposing the PrivateKey in public environment is a bad security practice, especially on the Cloud servers. :-/ – fletchsod Aug 31 '17 at 16:30
  • 4
    doesnt work 'System.InvalidCastException: 'Unable to cast object of type 'System.Security.Cryptography.RSACng' to type 'System.Security.Cryptography.RSACryptoServiceProvider'.'' – Ulterior Dec 13 '19 at 09:46
  • 4
    I'm getting error "Unable to cast object of type 'System.Security.Cryptography.RSACng' to type 'System.Security.Cryptography.RSACryptoServiceProvider'." in .NET Core 3.1 – MarsRoverII May 11 '20 at 10:11
45

The recommended way is to use RSA base class and call certificate.GetRSAPrivateKey().

RSA publicKeyProvider = certificate.GetRSAPrivateKey();

Since .NET 4.6, casting to RSACryptoServiceProvider as suggested by @blowdart is no longer recommended. This is even more an issue now since there are several versions of .NET (such as .NET Core).

By casting to RSACryptoServiceProvider that way, there is a good chance you might get this cast exception (depending on the platform and libraries used):

Unable to cast object of type 'System.Security.Cryptography.RSACng' to type 'System.Security.Cryptography.RSACryptoServiceProvider'

The reason is the actual implementation could be different from each platform, on Windows RSACng is used.

Here is a link that describes this issue (look for answer by Jeremy Barton).

Rosdi Kasim
  • 24,267
  • 23
  • 130
  • 154
9

Blowdart's answer is indeed correct. However, for clarity I should point out that if you want your RSACryptoServiceProvider instance to contain both the public and private keys of the X509 certificate (assuming the certificate does have a private key). Check the certificate's HasPrivateKey property.

RSACryptoServiceProvider rsa;
if (cert.HasPrivateKey)
    rsa = (RSACryptoServiceProvider)cert.PrivateKey;
else
    rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;

In the case of RSA when only the public key is present the RSA Parameters will be only Exponent and Modulus, all others will be null; If on the other hand the private key is present the RSA Parameters will contain D, DP, DQ, Exponent, InverseQ, Modulus, P and Q.

Emile
  • 271
  • 3
  • 3
  • (RSACryptoServiceProvider)(c.HasPrivateKey ? c.PrivateKey : c.PublicKey.Key); However: I wouldn't ever do this. I'd only load the private key when I intended to use the provider for something that *requires* it - and then of course it's no help just loading the public key instead. – The Dag Mar 08 '12 at 13:02
  • Dag is correct, but to clarify... I either want to decrypt with the private key, or encrypt with the public key. There's no situation where I want just whatever might be available. – Suamere Aug 03 '19 at 18:18