Serializing/Deserializing .Net's native RSA Public/Private keys

rahul's picture

Okay, here's the second consecutive blog post on serializing/deserializing RSA public/private keys, this time generated by the native RSACryptoServiceProvider available in .Net (the previous post available here related to serializing keys generated by open-source Bounty Castle library).

Serializing .Net's RSA keys as such is simple using the ToXmlString method available. Here's the code for generating and serializing the public and private keys to 2 separate strings:

 

CspParameters _cpsParameter;
_cpsParameter = new CspParameters();
_cpsParameter.Flags = CspProviderFlags.UseArchivableKey | CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(_cpsParameter);
string serialized=rsa.ToXmlString(true);

XElement element=XElement.Parse(serialized);

string publicKey = "";
publicKey += element.Element("Modulus").ToString();
publicKey += element.Element("Exponent").ToString();

privateKey = "";
privateKey += element.Element("P").ToString();
privateKey += element.Element("Q").ToString();
privateKey += element.Element("DP").ToString();
privateKey += element.Element("DQ").ToString();
privateKey += element.Element("InverseQ").ToString();
privateKey += element.Element("D").ToString();

The publicKey variable contains the Modulus and Exponent of the key pair constituting the public key, while the privateKey variable contains the other parts of the key pair, namely P, Q, DP, DQ, InverseQ and D.

The only interesting line above is passing in Flags to use the MachineKeyStore. If you don't pass in this flag, you might get a "The System cannot find the file specified" error for the ToXmlString method, especially if the code is running under an ASP.NET application. This is because by default, the ToXmlString tries to use the current user's key store and that might not exist for the ASP.NET account. This also means that the ASP.NET account should have access to the machine's key store.

Converting the serialized strings back to an RSA object is also easy with the FromXmlString method available on RSACryptoServiceProvider. Here's the code for the same:

 

{syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; }public static RsaKeyPair createFrom (string publicKey) { string serialized="<RSAKeyValue>" + publicKey + "</RSAKeyValue>"; var rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(serialized); ..... } public static RsaKeyPair createFrom (string privateKey, string publicKey) { string serialized="<RSAKeyValue>" + publicKey + privateKey + "</RSAKeyValue>"; CspParameters _cpsParameter; _cpsParameter = new CspParameters(); _cpsParameter.Flags = CspProviderFlags.UseMachineKeyStore; var rsa = new RSACryptoServiceProvider(_cpsParameter); rsa.FromXmlString(serialized); ..... }{/syntaxhighlighter}

The first method creates the RSA object from public key only, while the second creates it from both public and private keys. Again the second method (which creates the RSA object from private key) needs to specify to use the MachineKeyStore or it may throw the same exception ("The System cannot find the file specified.")

Attached below is the complete code for serializing and deserializing .Net's System.Security.Cryptography.RSA public and private key components.

As mentioned in the last blog post also, you might want to encrypt the private key before storing/transmitting it, or use the .Net secure Key containers for the purpose.

 

AttachmentSize
RsaKeyPair.cs2.17 KB

Comments

just a quick note to say many thanks for sharing this code.

I am in the middle of designing a "Key Distribution Server". This software will create and distribute encryption keys as part of a multi-tiered encryption scheme. The KDS will need to generate the keys, send the public part to a encryption service and the private part to a decryption service via WCF service methods. 

I was fairly certain I could send the keys via WCF methods in a serialized form, I was a little concerned about how the keys could be rehydrated on in the services and therefore I was looking around to see whether anyone had done it before and stumbled across your articles. Your code has confirmed that it is possible so a big thank you for publishing it.

My next challenge is to be able to cache the private key in some form of secure volatile memory store in the decryption service to limit the number of hits the KDS will take.

Carl

By Carl (not verified)
rahul's picture

Thanks Karl for the feedback. I have not researched on your "next challenge" but something based of .Net's SecureString class (like a Dictionary or List) might help you.

By rahul

I was thinking that a secure string would be useful however it is a question of what context to persist the securestring against. The service will expose methods however they will not be stateful and there is no application level caching options available as far as I know in WCF.

More research needed!

Thanks
Carl

By Carl Reid (not verified)
rahul's picture

One way could be to use a third-party caching toolkit. Or you can create your own Desktop app that does the caching in memory, and your WCF service can communicate with it.

If your WCF service is a part of an ASP.NET app and hosted by IIS, then I think you should be able to use the Application object for your needs.

By rahul

hi RAHUL,

can i have snippet code for creation of public and private keys in C or C++.

By shravan (not verified)
rahul's picture

Sorry Shravan, please google for your dialect of C/C++ and I am sure you would certainly find something.

By rahul

Add new comment