Encrypting long text asymmetrically

One of the recurring tasks that everybody has made in every programming language has been asymmetric encryption.

With .Net it is very simple to encrypt data, it is well documented and there are lots of blogs and articles, but people still run into two common issues.

The first one is what most people want to do is encrypt a text, not a number or a sequence of bytes. The .Net framework has implemented the most popular algorithms, and they are all based on byte arrays. There are many blogs and articles that talk about how to convert strings to byte arrays and vice versa. The most common solution is to use Encoding.Convert.

The second most typical issue (and I think less talked/blogged about) is the length limitation of the asymmetric encryption. This limitation comes from the mathematical algorithm they are based. The length varies depending on the key size used. When trying to encrypt a long string a System.Security.Cryptography.CryptographicException exception is raised stating a "Bad length" or "Key not valid for use in specified state" message.

In order to overcome this limitation there are two widely implemented (but not standardized) solutions.

The first one is to divide the text to be encrypted into chunks, encrypt the chunks and concatenate the result. When decrypting we need to divide the encrypted message in chunks, decrypt the chunks and concatenate the result.

The attached code has a EncryptByChunks/DecryptByChunks that shows a sample of this implementation using an RSACryptoServiceProvider. This sample could be improved by calculating the size of the chunks based on the Key size.



The second solution consist on using a symmetric algorithm. The idea is to generate a random symmetric key, encrypt the message with that key, encrypt the symmetric key with the asymmetric public key. When decrypting the message, first we decrypt the symmetric key with the asymmetric private key, then decrypt the message using the decrypted symmetric key. This is (what more or less) SSL does.

The attached code has a EncryptWithSymmetricAid/DecryptWithSymmetricAid that shows a sample of this implementation. It uses RSACryptoServiceProvider for the asymmetric algorithm and TripleDESCryptoServiceProvider for the symmetric.



Running a couple of rudimentary "stress" testing with a loop of 1000 iterations and a message of 1 MByte we can see that the symmetric-aided approach takes approximately 10 times less to complete (4 seconds versus 39 seconds) than the "chunk" solution.


Note: Never try to implement a custom encryption algorithm by yourself, always use a known encryption algorithm. (That of course may not apply to renowned mathematicians that like programming)

This has been said many times but people keep falling into the error of ignoring the suggestion, therefore keeping a false feeling of safety.