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.