19 March, 2009

RSA using BouncyCastle

Trying to do RSA using BouncyCastle, but struggling to find your way around the API? In a previous post (see [here](/posts/why-cripple-the-net-rsa-implementation)) I pondered why the RSA implementation in `System.Security.Cryptography` is restricted to only the most common usage scenarios. I mentioned [BouncyCastle](http://bouncycastle.org) 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.

NOTE: The general cryptographical security of the presented method is beyond the scope of the article. The code presented is not cryptographically secure for large data sets. If you're here looking for a way to do cryptographically secure RSA in the general case, you should look into more complicated approaches including padding, blinding, and more sophisticated block cipher modes. Cryptography is a topic undergoing constant research, so stay up to date and be sure to evaluate the strength of your solution for the scenarios in which you apply it.

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.

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.

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 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:

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 of course 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.

22 comments:

  1. i'm sorry my name is lalit not Not Working!

    ReplyDelete
  2. 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!

    ReplyDelete
  3. 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?

    ReplyDelete
  4. A simple type-casting solved the problem
    Again my silly mistake, sorry...

    ReplyDelete
  5. 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?

    ReplyDelete
  6. [...] 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 [...]

    ReplyDelete
  7. 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?

    ReplyDelete
  8. 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.

    ReplyDelete
  9. 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!

    ReplyDelete
  10. Charles: Glad to help, thanks for sharing!

    ReplyDelete
  11. 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.

    ReplyDelete
  12. 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

    ReplyDelete
  13. I have the same question as Craig, what if you already have the private key and want to use it to decrypt. Trying to get this working with AWS :)

    ReplyDelete
  14. @Craig @zack The AsymmetricKeyParameter itself is a base class for all asymmetric keys; it does not (and cannot) know what the actual key is. So, you need to construct a key parameter matching the key you want to use. If you're using an RSA private key, construct an RSAKeyParameters instance. If you're using El Gamal, construct an ElGamalKeyParameters instance, and so on. All these concrete key parameter classes inherit AsymmetricKeyParameter.

    ReplyDelete
  15. Brandon's got a point. Any help for that?

    ReplyDelete
  16. Nvm, got it. As chunkPosition gets enlarged by blockSize, it is enough to put

    int chunkSize = Math.Min(blockSize, data.Length –
    chunkPosition );

    instead of

    int chunkSize = Math.Min(blockSize, data.Length –
    (chunkPosition * blockSize));

    ReplyDelete
  17. Hi,
    I am looking for an infrastructure like JCE in java so I can “install” encryption providers.
    The one I am going to put in now is Bouncy Castle provider and use “PBEWITHMD5AND256BITAES-CBC-OPENSSL” but I want to be able to change the providers and algorithms just by configuration change. I have that in Java with JCE.
    Is there something like that in C# and are there docs / examples?

    Thanks.

    ReplyDelete
  18. Hi Harvard,

    Thanks for this. I was actually able to use your suggestions in blinding messages. However, I can't seem to go through the whole process of blinding a message, signing it, unblinding the signed message, and verifying the signature. I've written these codes: http://www.daniweb.com/forums/post1315685.html#post1315685

    Please, if you could have a look, perhaps you could tell me what I'm doing wrong.

    ReplyDelete
  19. Hi! I am using the new version of BouncyCastle for C# , and now it's working, but I can not load my previously generated PrivateKey could you give us and example of loading one with the RSAKeyParameters instance?

    Thank you very much

    ReplyDelete
  20. Hi Matt

    thanks a lot for the code
    i tried your code but i am getting error "attempt to process message to long for cipher" while decrypting the encrypted file.

    Please can you suggest me where i might have gone wrong.

    Thanks for helping me

    ReplyDelete
  21. i want Decrypt this code ????

    public static string Encrypt(string plainText) { RsaKeyParameters parameters = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(File.ReadAllText("PublicKeyFactory_Key.txt"))); IAsymmetricBlockCipher asymmetricBlockCipher = new Pkcs1Encoding(new RsaEngine()); asymmetricBlockCipher.Init(true, parameters); byte[] bytes = Encoding.UTF8.GetBytes(plainText); int inputBlockSize = asymmetricBlockCipher.GetInputBlockSize(); List list = new List(); int num = 0; while (num + inputBlockSize < bytes.Length) { list.AddRange(asymmetricBlockCipher.ProcessBlock(bytes, num, inputBlockSize)); num += inputBlockSize; } list.AddRange(asymmetricBlockCipher.ProcessBlock(bytes, num, bytes.Length - num)); return Convert.ToBase64String(list.ToArray()); }

    ReplyDelete