Asymmetric Encryption of Long Data
Few weeks ago a post about asymmetric encryption using RSACryptoServiceProvider. Asymmetric encryption is an expensive operation so it is not meant for very long data encryption. If you have an article or a book you should not encrypt it asymmetrically but what about a 200 byte long information? If you will try to encrypt 200 byte using RSACryptoServiceProvider you will get an exception. It seems that the longest data that can be encrypted using is RSACryptoServiceProvider is 80 bytes.
I thinks that there are many scenarios where it makes to encrypt few hundreds bytes long data asymmetrically and I was surprised to find out that the limit is so low.
The solution is parallel encryption. Simply split the long data to chunks of up to 80 bytes and encrypt them in parallel. There are no dependencies between these chunks of data so they can be parallelized very well.
Encryption:
public static byte[] EncryptAsyncPublic(byte[] data, X509Certificate2 certificate)
{
try
{
RSACryptoServiceProvider rsa =
certificate.PublicKey.Key as RSACryptoServiceProvider;
if (data.Length <= 80)
return rsa.Encrypt(data, true);
//The max encryption size is 85 so we split the data into chunk of 80 and encrypt them in parallel
List<byte[]> splits = data.Split(80);
List<byte[]> encryptedSplits = new List<byte[]>();
Parallel.For(0, splits.Count,
i => encryptedSplits.Add(rsa.Encrypt(splits[i], true)));
//Collect all the encrypted splits and create the final encrypted array
return encryptedSplits.Merge();
}
catch (Exception ex)
{
Logger.Log(ex.ToString(), EventLogEntryType.Error);
return null;
}
}
Decryption:
In the decryption method we will do exactly the same.
Asymmetric encryption using RSACryptoServiceProvider always produces 128 bytes. If the byte array to decrypt is longer than 128 bytes (256, 384 etc) it means that it is the result of parallel encryption of long data, therefor it should be decrypted in parallel.
public static byte[] DecrypyAsyncPrivate(byte[] cipher, X509Certificate2 certificate)
{
try
{
RSACryptoServiceProvider rsa =
certificate.PrivateKey as RSACryptoServiceProvider;
if (cipher.Length == 128)
return rsa.Decrypt(cipher, true);
// the encrypted data was split so we have to split
the result and decrypt in parallel
List<byte[]> splits = cipher.Split(128);
List<byte[]> decryptedSplits = new List<byte[]>();
Parallel.For(0, splits.Count,
i => decryptedSplits.Add(rsa.Decrypt(splits[i], true)));
Collect all the encrypted splits and bind them together
return decryptedSplits.Merge();
}
catch (Exception ex)
{
Logger.Log(ex.ToString(), EventLogEntryType.Error);
return null;
}
}
Enjoy
Manu