Serializing/Deserializing RSA Public/Private keys generated using Bouncy Castle library

.Net provides a good Cryptographic framework in the System.Security.Cryptography namepsace. But I have sometimes found it lacking for my needs (and non-intuitive at some other times).

Yesterday I needed to generate a RSA Public-Private key pair in a client-server communication, where the server generates the key pair and sends off the public key to the client, which the client subsequently uses to encrypt data being sent to the server. The server stores the Private key in the database used later to decrypt data received from the client and then send the encrypted response to it.

Clearly, this needed the ability to serialize the public and private portions of the RSA key pair separately to strings and then generate the original Key objects from the serialized strings. My initial instinct was this should be easy to do with .Net and there much be some API method somewhere.

The closest I found were the ToXmlString() and FromXmlString() methods in System.Security.Cryptography.RSA class. I will cover these methods in another blog post, but for my present scenario, I decided to go with the open-source Bouncy Castle cryptographic library's CSharp port (the decision was based on the fact that I was writing a client that needed to run on multiple diverse platforms, and Bouncy Castle library has a Java version with the same architecture and design as the C# version making secure communication between multiple platforms easier to manage). In fact the Java version was the primary version for the Bouncy Castle library and the C# version is a port of it.

It was easy to browse the architecture and class hierarchy of the library in Visual Studio's Object Browser. In no time was I able to write the following lines to generate a RSA key-pair using the Bouncy Castle library:

 

 

RsaKeyPairGenerator g=new RsaKeyPairGenerator();
g.Init(new KeyGenerationParameters(new SecureRandom(), 1024));
var pair=g.GenerateKeyPair();

 

Having done that so quickly, I thought it should be another breeze to serialize the Public and Private Key components inside the key pair object. However, it was not so easy as I found out.

The documentation for the Bouncy Castle library is limited (and more so for the CSharp version), and you essentially have to browse through the examples provided and explore the library manually to accomplish what you want. After some hair-pulling, I was finally able to find the classes and methods to serialize the Public/Private keys in the key pair. The code turned out to be as follows:

 

 

PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.Private);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetDerEncoded();
string serializedPrivate = Convert.ToBase64String(serializedPrivateBytes);

SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pair.Public);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
string serializedPublic = Convert.ToBase64String(serializedPublicBytes);

 

The code as such is pretty short, but it took me some real time to figure out the classes handling the serialization for the Keys. Having done that, the final step was to deserialize the strings into the original key objects. Some more browsing through the library and I was able to assemble the following code:

 

 

RsaPrivateCrtKeyParameters privateKey = (RsaPrivateCrtKeyParameters) PrivateKeyFactory.CreateKey(Convert.FromBase64String(serializedPrivate));
RsaKeyParameters publicKey = (RsaKeyParameters) PublicKeyFactory.CreateKey(Convert.FromBase64String(serializedPublic));

 

In the end, it was well worth the effort. Although I have used the Bouncy Castle's Java version briefly before, I haven't tried to serialize the RSA keys in its java version earlier. However I expect that to be on the similar lines (probably exactly similar).

Attached below is the complete code demonstrating serializing/deserializing RSA public/private keys using the Bouncty Castle library.

You might want to encrypt the serialized Private Key before storing it somewhere. It would be a serious security issue if someone gets access to all private keys stored plainly somewhere. For this purpose, you might want to have a look at the Org.BouncyCastle.Pkcs.EncryptedPrivateKeyInfoFactory class in the Bouncy Castle library that provides the CreateEncryptedPrivateKeyInfo method to generate encrypted Private Key bytes. You can then use the PrivateKeyFactory.DecryptKey method to create the original Private Key object from the encrypted key bytes.

 

AttachmentSize
Binary Data RsaKeyPair.cs1.92 KB

Comments

i am already doing this !! But a security department told me that they need all the datas encrypted 

Also, it not out of the scope ! I mean, i will use your code, but i am thinking about how to have more security !

My friend... its unsafe create a fixed Private and PublicKey ? instead of generate for every get

Hello...
If I have a public key RsaKeyParameters publicKey = (RsaKeyParameters)keyPair.Public; and i need to send this to a server, can i convert using:
 SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);

                    byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();

                    string serializedPublic = Convert.ToBase64String(serializedPublicBytes); ??
And then, how can i convert the serializedPublic to RsaKeyParameters publicKey again ?

rahul's picture

Hi Marcelo, I will consider this a futile exercise. I fail to understand how data sent over HTTPS can be made more secure by manually encrypting and descrypting server and client side. I would repeat, just stick to HTTPS.

I aggree with you, but is not a option. Like i told you before...

rahul's picture

Well then good luck finding a solution. Apart from using HTTPS, I am not aware of any other mechanism more secure than HTTPS to transmit data over web. Key Exchange is going to remain a problem, that you can resolve only via using existing secure communication channels (e.g. HTTPS, VPN etc that all essentially rely on the same public/private key cryptography). And if you rely on public/private key cryptography (read HTTPS) for key exchange, then why not use the same for data exchange too.

I spent days trying to figure out how to recreate the keys from strings.  This article was a huge help.  If there was a way to send you a tip or donation, I would totally do so.  Well deserved for posting up this article.  Thanks again!

rahul's picture

Glad to know Kevin that the blog post helped.