.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.
Thank you, Rahul.
seems like a lot of great effort! needed this for my project.
god bless you for sharing this online.
Very useful example!
Simple, clean, working sample code.
You just saved my day
Genesio from Italy
Typo: “Bounty Castle” should be “Bouncy Castle”.
Hi Rahul,
it’s nice work. Thanks.
I just want to ask, for private and public key string parameters, can I define any of string value ? how about the length? does it have any rule ? or I can use any string ?
public static RsaKeyPair createFrom (string @private, string @public)
Hi Rahul, I create 1024 key with your create function (public static RsaKeyPair create)
and I want to return the private and public key in string format. I search there is several method. I compare your code with another code which I found in stackoverflow, and the result for private key in string format is different. but the public key in string format is same. Do you have any suggestion? Thanks in advance
public RsaPrivateCrtKeyParameters privateKey { get; internal set; }
public RsaKeyParameters publicKey { get; internal set; }
public string @public { get; internal set; }
public string @private { get; internal set; }
//adding 2 string variable to compare
public string @public2 { get; internal set; }
public string @private2 { get; internal set; }
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.privateKey);
byte[] serializedPrivate = privateKeyInfo.ToAsn1Object().GetDerEncoded();
pair.@private = Convert.ToBase64String(serializedPrivate);
TextWriter textWriterPrivate = new StringWriter();
PemWriter pemWriterPrivate = new PemWriter(textWriterPrivate);
pemWriterPrivate.WriteObject(p.Private);
pemWriterPrivate.Writer.Flush();
pair.@private2 = textWriterPrivate.ToString();
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pair.publicKey);
byte[] serializedPublic = publicKeyInfo.ToAsn1Object().GetDerEncoded();
pair.@public = Convert.ToBase64String(serializedPublic);
TextWriter textWriterPublic = new StringWriter();
PemWriter pemWriterPublic = new PemWriter(textWriterPublic);
pemWriterPublic.WriteObject(p.Public);
pemWriterPublic.Writer.Flush();
pair.@public2 = textWriterPublic.ToString();
————————————————————————————————-
with your method :
private key : MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKk8oX+GkJZvhl00g33ZCmFttLjveyhqx8lmbgDBmj7DUBWPq/eFUmMVH3rKqUb6CSfSgoYtN8HHsPukKIwZAJSVdb834pB1o/iRc8OUy283dWipNb1ALG7dj8jAZlfBAvJhyZF2PvNd+YyicVOr7AbjZVjZhcP4gImc6q8XfMcxAgMBAAECgYEAhQZtg0oIuNbs7LJscS17JV4QYhWL3xcf90UWTm3filoHxwrph2Q6gDuIRQKr0GiVbcHgawt7+ku25/X/ETBN7S70QBMh0A38+dUMv9MujLz9mURwpI5w+Q5xLl6+2Jbo6idP5Sah3z9LbsF1puacEBmzyG4FHI391CMlPknEemECQQD/ivd37YFlUfNUQ0fFYc7t6DpXtbZ2Ma7s4VYgeGjlFMKRpjnnIew2nlJg0DURlsUTmB4gegV6Fw9rce75xex9AkEAqYojSBU+2gc4WHB6D6/BpSDQcaIsEKDpyVTiCrLULxU7ZBIQz28ONGScGhHn8l5Jw53y3VDT23WfR+rIsD3nxQJALyY42svboBIqz1VKnMSbJZI/kYdZjx1DpTk+ZudQk1PtQmplLJw5tSopEOvZntEus5rRlDRvZkNy+OQgr70xEQJAfheVIflbI4EXMP+GaMBI/20mWj1JFJz5A5oz+80A7nuWDlk5U22/XMwvJVyH68Sgi/KfPGbvCluyuSQvWpTQGQJAC+FzndA5N/DXjk8jENgoQEGUH5V00Hn0ootiutjYSM2DGVE3G9wQBHFp6APsFs7tF1HdqendrjvEeiNdDM2c0g==
public key : MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpPKF/hpCWb4ZdNIN92QphbbS473soasfJZm4AwZo+w1AVj6v3hVJjFR96yqlG+gkn0oKGLTfBx7D7pCiMGQCUlXW/N+KQdaP4kXPDlMtvN3VoqTW9QCxu3Y/IwGZXwQLyYcmRdj7zXfmMonFTq+wG42VY2YXD+ICJnOqvF3zHMQIDAQAB
with openSSL method :
private key :
—–BEGIN RSA PRIVATE KEY—–
MIICXAIBAAKBgQCpPKF/hpCWb4ZdNIN92QphbbS473soasfJZm4AwZo+w1AVj6v3
hVJjFR96yqlG+gkn0oKGLTfBx7D7pCiMGQCUlXW/N+KQdaP4kXPDlMtvN3VoqTW9
QCxu3Y/IwGZXwQLyYcmRdj7zXfmMonFTq+wG42VY2YXD+ICJnOqvF3zHMQIDAQAB
AoGBAIUGbYNKCLjW7OyybHEteyVeEGIVi98XH/dFFk5t34paB8cK6YdkOoA7iEUC
q9BolW3B4GsLe/pLtuf1/xEwTe0u9EATIdAN/PnVDL/TLoy8/ZlEcKSOcPkOcS5e
vtiW6OonT+Umod8/S27BdabmnBAZs8huBRyN/dQjJT5JxHphAkEA/4r3d+2BZVHz
VENHxWHO7eg6V7W2djGu7OFWIHho5RTCkaY55yHsNp5SYNA1EZbFE5geIHoFehcP
a3Hu+cXsfQJBAKmKI0gVPtoHOFhweg+vwaUg0HGiLBCg6clU4gqy1C8VO2QSEM9v
DjRknBoR5/JeScOd8t1Q09t1n0fqyLA958UCQC8mONrL26ASKs9VSpzEmyWSP5GH
WY8dQ6U5PmbnUJNT7UJqZSycObUqKRDr2Z7RLrOa0ZQ0b2ZDcvjkIK+9MRECQH4X
lSH5WyOBFzD/hmjASP9tJlo9SRSc+QOaM/vNAO57lg5ZOVNtv1zMLyVch+vEoIvy
nzxm7wpbsrkkL1qU0BkCQAvhc53QOTfw145PIxDYKEBBlB+VdNB59KKLYrrY2EjN
gxlRNxvcEARxaegD7BbO7RdR3anp3a47xHojXQzNnNI=
—–END RSA PRIVATE KEY—–
public key :
—–BEGIN PUBLIC KEY—–
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpPKF/hpCWb4ZdNIN92QphbbS4
73soasfJZm4AwZo+w1AVj6v3hVJjFR96yqlG+gkn0oKGLTfBx7D7pCiMGQCUlXW/
N+KQdaP4kXPDlMtvN3VoqTW9QCxu3Y/IwGZXwQLyYcmRdj7zXfmMonFTq+wG42VY
2YXD+ICJnOqvF3zHMQIDAQAB
—–END PUBLIC KEY—–
Opps I tried to get the value of modulus, public exponent, private exponent, prime p, prime q, and another value, and the result is same. So I think it just different way to export. Please correct me if I am wrong. Thanks
sw.WriteLine(“Public Modulus : ” + pair.publicKey.Modulus.ToString(16));
sw.WriteLine(“Public Exponent : ” + pair.publicKey.Exponent.ToString(16));
sw.WriteLine(“Private Modulus : ” + pair.privateKey.Modulus.ToString(16));
sw.WriteLine(“Private Exponent : ” + pair.privateKey.Exponent.ToString(16));
sw.WriteLine(“Prime 1 (p) : ” + pair.privateKey.P.ToString(16));
sw.WriteLine(“Prime 2 (q) : ” + pair.privateKey.Q.ToString(16));
sw.WriteLine(“exponent1 (d mod (p-1)) : ” + pair.privateKey.DP.ToString(16));
sw.WriteLine(“exponent2 (d mod (q-1)) : ” + pair.privateKey.DQ.ToString(16));
you littraly saved my life with this 🙂
thank you so much !!!!!!!
Thank you very much. You really help me 🙂
Hi Rahul,
That’s really nice work. now could you please tell me how can i do encryption and decryption with the generated string public and private key.
I am using this concept to encrypt my data. please have a look this code.
string inputMessage = “Test Message”;
UTF8Encoding utf8enc = new UTF8Encoding();
byte[] inputBytes = utf8enc.GetBytes(inputMessage);
RsaKeyPairGenerator rsaKeyPairGnr = new RsaKeyPairGenerator();
rsaKeyPairGnr.Init(new KeyGenerationParameters(new SecureRandom(), 512));
AsymmetricCipherKeyPair keyPair = rsaKeyPairGnr.GenerateKeyPair();
RsaKeyParameters publicKey = (RsaKeyParameters)keyPair.Public;
IAsymmetricBlockCipher cipher = new RsaEngine();
cipher.Init(true, PublicKey);
byte[] cipheredBytes = cipher.ProcessBlock(inputBytes, 0, inputMessage.Length);
string p = utf8enc.GetString(cipheredBytes);
textBox4.Text = p;
this is running perfectly but data is not encrypted with the string public key, I would like to encrypt the message with the string public key and do the decryption as well. could you please provide me some sample of that code.
Thanks in advance
Thanks a lot for this post, I had a hard time searching for a solution to this.
In my case I needed to serialize/deserialize a PGP keypair instead of just an RSA pair, so I needed to do it this way:
http://pastebin.com/mA8rPyXG
It works like a charm 🙂
Really this is great 🙂 Thanks again to make life easier.
Hi rahul , thanks for this post.
recently i was asked to do almost the same task(c# application/service)as you mentioned in this.the Difference is instead of database we would be storing the keys to an HSM device(safe net).I got aprotectToolkit SDK from this vendor which supports PKCS#11 stds. same which the device was following.But that was more suitable for c/c++ development. So i got an API , NCryptoki which provides a .net library for PKCS#11.
They provided an User interface to create slotes,tokens,generate key pair etc. So i created a key pair and exported it to disk. By defult it is saving to a file with out extension.also it allowing to save it to .txt file or anything.
Ncryptoki provides all example code to generate key pair from code, search for keys using its attributes . but i need some thing like. i need to read that exported key file in code and then validate exixtence of the key in the HSM. I tried severals ways to read the key from the file and then convert it to the normal RSApublic key.But failed.
I have P, Q, N, Da nd E in decimal format. How do I convert them into RSAParameters Format?
I have below private key:
—–BEGIN RSA PRIVATE KEY—–
MIICXAIBAAKBgQCpPKF/hpCWb4ZdNIN92QphbbS473soasfJZm4AwZo+w1AVj6v3
hVJjFR96yqlG+gkn0oKGLTfBx7D7pCiMGQCUlXW/N+KQdaP4kXPDlMtvN3VoqTW9
QCxu3Y/IwGZXwQLyYcmRdj7zXfmMonFTq+wG42VY2YXD+ICJnOqvF3zHMQIDAQAB
AoGBAIUGbYNKCLjW7OyybHEteyVeEGIVi98XH/dFFk5t34paB8cK6YdkOoA7iEUC
q9BolW3B4GsLe/pLtuf1/xEwTe0u9EATIdAN/PnVDL/TLoy8/ZlEcKSOcPkOcS5e
vtiW6OonT+Umod8/S27BdabmnBAZs8huBRyN/dQjJT5JxHphAkEA/4r3d+2BZVHz
VENHxWHO7eg6V7W2djGu7OFWIHho5RTCkaY55yHsNp5SYNA1EZbFE5geIHoFehcP
a3Hu+cXsfQJBAKmKI0gVPtoHOFhweg+vwaUg0HGiLBCg6clU4gqy1C8VO2QSEM9v
DjRknBoR5/JeScOd8t1Q09t1n0fqyLA958UCQC8mONrL26ASKs9VSpzEmyWSP5GH
WY8dQ6U5PmbnUJNT7UJqZSycObUqKRDr2Z7RLrOa0ZQ0b2ZDcvjkIK+9MRECQH4X
lSH5WyOBFzD/hmjASP9tJlo9SRSc+QOaM/vNAO57lg5ZOVNtv1zMLyVch+vEoIvy
nzxm7wpbsrkkL1qU0BkCQAvhc53QOTfw145PIxDYKEBBlB+VdNB59KKLYrrY2EjN
gxlRNxvcEARxaegD7BbO7RdR3anp3a47xHojXQzNnNI=
—–END RSA PRIVATE KEY—–
could you please let me know how can i create RSACryptoServiceProvider object from it?
I need to decrypt a message by using above private key.
If i have a Client side and a web api and i need everything encrypted assymetrical, how i do ? How send the public key securely ? I have to get the input text on client, encrypt, send to the web api, decrypt here, search on DB, get the json result, encrypt it and send to the client side encrypted. Then, decrypt and show…
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 ?
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!
Big time helper! 🙂
Thanks. You saved a lot of my time.
Happy to help Gargeya 🙂