RSA using BouncyCastle

Trying to do RSA using BouncyCastle, but struggling to find your way around the API? In a previous post (see here) I pondered why the RSA implementation in System.Security.Cryptography is restricted to only the most common usage scenarios. I mentioned BouncyCastle as an alternative for those who wanted a more flexible API, but never got around to providing examples where BouncyCastle was used. By request, this post provides usage examples by building a crude and simple, but efficient set of methods for RSA key generation, encryption, and decryption, all built on top of BouncyCastle.

BouncyCastle provides flexibility and control over your encryption approach, which comes at a cost. The BouncyCastle API might be a bit hard to cope with at first, but if you know encryption in general you should be able to find your way around the API without too much effort. This post will be focusing on RSA, since that was my original need, but it should be mentioned that BouncyCastle provides many other asymmetric (and symmetric) algorithms for which the usage is similar to what you find below.

Creating RSA keys

Creating RSA keys is a simple task. The method below lets you specify the key size in bits, and creates a key pair for you.

  1.  
  2. public AsymmetricCipherKeyPair GenerateKeys(int keySizeInBits)
  3. {
  4.   RsaKeyPairGenerator r = new RsaKeyPairGenerator();
  5.   r.Init(new KeyGenerationParameters(new SecureRandom(),
  6.     keySizeInBits));
  7.   AsymmetricCipherKeyPair keys = r.GenerateKeyPair();
  8.   return keys;
  9. }
  10.  

That’s all there is to it.

Encryption

Now that we have a key pair, we are ready to encrypt and decrypt using RSA. In the example below, we use a key (public or private) to encrypt a byte sequence. To encrypt a string, simply convert the string to a byte array using Encoding.GetBytes.

  1.  
  2. public byte[] Encrypt(byte[] data, AsymmetricKeyParameter key)
  3. {
  4.   RsaEngine e = new RsaEngine();
  5.   e.Init(true, key);
  6.  
  7.   int blockSize = e.GetInputBlockSize();
  8.  
  9.   List<byte> output = new List<byte>();
  10.  
  11.   for (int chunkPosition = 0; chunkPosition < data.Length;
  12.     chunkPosition += blockSize)
  13.   {
  14.     int chunkSize = Math.Min(blockSize, data.Length
  15.       (chunkPosition * blockSize));
  16.     output.AddRange(e.ProcessBlock(data, chunkPosition,
  17.       chunkSize));
  18.   }
  19.   return output.ToArray();
  20. }
  21.  

The approach above uses a list to gather output for the sake of simplicity. Note that the RSA engine can only process a limited block size at a time (block size depends on the key size). The approach above generalizes the RSA engine, and processes a data set of an arbitrary size.

The above method does not impose constraints on which key you use for encryption. Use the public key or the private key as you see fit for your solution.

Decryption

The Decrypt method is very similar to the Encrypt method:

  1.  
  2. public byte[] Decrypt(byte[] data, AsymmetricKeyParameter key)
  3. {
  4.   RsaEngine e = new RsaEngine();
  5.   e.Init(false, key);
  6.  
  7.   int blockSize = e.GetInputBlockSize();
  8.  
  9.   List<byte> output = new List<byte>();
  10.  
  11.   for (int chunkPosition = 0; chunkPosition < data.Length;
  12.     chunkPosition += blockSize)
  13.   {
  14.     int chunkSize = Math.Min(blockSize, data.Length
  15.       (chunkPosition * blockSize));
  16.     output.AddRange(e.ProcessBlock(data, chunkPosition,
  17.       chunkSize));
  18.   }
  19.   return output.ToArray();
  20. }
  21.  

Again, it’s up to you which key you choose to use. If you want to use the common approach, encrypt using a symmetric cipher, hash the data, and sign the hash with your private key using the above Encrypt method. If you want to use another approach like encrypting the actual data using your private key, you are free to do so.

I hope this post helps those of you who want to apply RSA (or any other asymmetric cipher) to more subtle cases than those supported by the .NET framework.

15 Comments so far »

  1. Not Working! said

    on March 24 2009 at 14:29

    hi! first of all thanks a lot! there is no documentation on the bouncy castle web page, or any where for that matter, on C# coding. I wanted to modify RSA signature for using blinding. but the above code dosen’t work.. i’m unable to makeout what’s wrong. i pasted the code in Class1.cs and called the functions as: Class1 rdc=new Class1(); AsymmetricCipherKeyPair keys = rdc.GenerateKeys(960); byte[] plainbytes = System.Text.Encoding.UTF8.GetBytes(txt1.Text); byte[] cipherbytes = rdc.Encrypt(plainbytes, keys.Private); byte[] plainbytes_de = rdc.Decrypt(cipherbytes, keys.Public); txt2.Text = Convert.ToBase64String(cipherbytes); txt3.Text = Convert.ToBase64String(plainbytes_de);

    please tell me what i’m doing wrong… also there is a RsaBlindingEngine in Bouncy Castle… How is it usefull?

  2. lalit said

    on March 24 2009 at 14:33

    i’m sorry my name is lalit not Not Working!

  3. Håvard said

    on March 24 2009 at 21:29

    Hi Lalit.

    You haven’t stated what you are trying to achieve, so I’ll assume you expect txt3.Text to contain the plain text from txt1.Text to verify that encryption and decryption works as intended. If that is the case, then you should convert plainbytes_de to a string using Encoding.UTF8.GetString, not Convert.ToBase64String.

    The RSA blinding engine in BouncyCastle should work fine. Just generate keys, use RSABlindingFactorGenerator to generate a blinding factor for you, and use RSABlindingEngine for encryption/decryption.

    Good luck!

  4. lalit said

    on March 24 2009 at 23:57

    Thanks a million! That solved the problem (silly mistake on my side)! But I’m stuck again, the constructor of RSABlindingFactorGenerator requires an object of RsaKeyParameters type. Do you know how to make this from the key pair or only the public key?

  5. lalit said

    on March 25 2009 at 01:36

    A simple type-casting solved the problem Again my silly mistake, sorry…

  6. Kombajn said

    on April 18 2009 at 15:28

    Is http://www.discryptor.net/ using it right?

  7. Anibal said

    on June 23 2009 at 18:34

    Hi Harvard! Thanks for your example! I’ve been trying to implement it into my J2ME script for decryption, and “almost” work!

    This is my “decryption part” code, and here, you can note some differences with your code:

    public String RSADecrypt(byte[] data,RSAKeyParameters key) { RSAEngine e = new RSAEngine(); e.init(false, key); int blockSize = e.getInputBlockSize(); StringBuffer strOut=new StringBuffer(); for (int chunkPosition = 0; chunkPosition <data.length; chunkPosition += blockSize) { int chunkSize = Math.min(blockSize, Math.abs(data.length - (chunkPosition * blockSize))); byte[] pb=e.processBlock(data, chunkPosition, chunkSize); String strBuf=new String(pb); System.out.println(“Got:”+strBuf); strOut.append(strBuf); } return strOut.toString(); }

    First, I’ve changed the AsymmetricKeyParameter with RSAKeyParameters, because I’ve already the modulus and private exponent for the private key. It works fine.

    Also, where you wrote: int chunkSize = Math.min(blockSize, data.length – (chunkPosition * blockSize));

    I wrote: int chunkSize = Math.min(blockSize, Math.abs(data.length – (chunkPosition * blockSize)));

    That’s because if not, I got: java.lang.NegativeArraySizeException.

    Well, once i did this, and set a crypto message for a decoded “Hello World!” text, I get:

    “Got:!dlroW olleH”

    If I try to decrypt larger texts, for example:

    “I hope this post helps those of you who want to apply RSA (or any other asymmetric cipher) to more subtle cases than those supported by the .NET framework.”

    The result is:

    Got:op siht epoh I Got:esoht spleh ts Got:aw ohw uoy fo Got:SR ylppa ot tn Got:ehto yna ro( A Got:c cirtemmysa r Got:erom ot )rehpi Got: sesac eltbus Got:pus esoht naht Got: eht yb detrop Got:krowemarf TEN. Got:.

    For a final string like: “op siht epoh Iesoht spleh tsaw ohw uoy fo SR ylppa ot tnehto yna ro( Ac cirtemmysa rerom ot )rehpi sesac eltbus pus esoht naht eht yb detropkrowemarf TEN..”

    Any idea?

    Thanks in advance!

  8. Brandon said

    on August 11 2009 at 14:26

    I’ve copied this into a VB.NET application running framework 2.0.

    I can’t seem to get it to decrypt more than one block of data. This code in the decrypt method

    While chunkPosition < data.Length

    Dim chunkSize As Integer = System.Math.Min(blockSize, data.Length – (chunkPosition * blockSize)) output.AddRange(e.ProcessBlock(data, chunkPosition, chunkSize)) chunkPosition += blockSize

    End While

    Only ever adds one range of bytes to the List, because the e.ProcessBlock line never gives back more than that. Also, the calculation that figures out chunksize returns a huge negative number on the second iteration. I’ve changed this number in the debugger to the same size block as the initial iteration to no avail. Any help?

  9. The Dangers of Copy/Paste Coding | Design Limbo said

    on October 28 2009 at 16:13

    [...] Google returned for me was a post by Havard Stranden on his blog, someone who I’ve read before and even used his Copyable software before. Havard had [...]

  10. Uzeyir said

    on November 5 2009 at 16:46

    Hi, I want to change cryptoprovider(f/e: “Microsoft Enhanced Cryptographic Provider v1.0″) as keylength when generate pair key with AsymmetricCipherKeyPair class. Can anyone helps with it?

  11. Sekhar said

    on January 8 2010 at 12:03

    In Encryption List class are used by you. From jar this List is class is coming, this is an User Defined class or it is coming from any jar file, please mention those details.

  12. Charles said

    on January 10 2010 at 19:33

    Sekhar,

    The above code is in c# although slightly modified it works great for the Java implementation of bouncycastle!

    The list you are reffering to is actualy a data-type in c#. You can see examples of using a list here: http://dotnetperls.com/list

    Thanks so much for posting something on this Havard! As other people have said; I could find no examples or documentation on this anywhere. I am using the Java implementation, but your code example is more then enough to get started.

    Thanks again!

  13. Håvard said

    on January 15 2010 at 15:11

    Charles: Glad to help, thanks for sharing!

  14. gary said

    on January 25 2010 at 22:07

    Hello all I have a question concerning rsa key pairs. I am currently working for a client to simulate large volumes of encrypted traffic. the issue I am having with the keys is, I already have my private key given to me but its in a file with the certificate and its format is something like this “56 H3 75 …..” there are 10 sets like this. how would I use this to generate the private key or how would I import it.

  15. Craig Martin said

    on March 2 2010 at 08:41

    Hi There,

    This doesn’t exactly apply to this post, but I thought I would ask it here anyway as there is very little on using BouncyCastle in C# (as has been noted by previous posts here!).

    Is there anyway to create an AsymmetricKeyParameter using a previously generated private key? I am generating a key pair, storing the private key in an encrypted form and then when it is time to create a P12 for the end user to retrieve their certificate, I am decrypting the previously stored private key, but now have no idea how to actually make it into an AsymmetricKeyParameter so as to create the P12 using BouncyCastle.

    Is what I am trying to do even possible?

    Any help is greatly appreciated.

    Cheers, Craig Martin

Comment RSS · TrackBack URI

Leave a comment

Name: (Required)

eMail: (Required)

Website:

Comment:

Get Adobe Flash playerPlugin by wpburn.com wordpress themes