Reputation: 43
I'm trying to develop a metro application on Windows 8.1 (c#) which will encrypt data with RSA.
The final goal is to encrypt an image (so a large byte array) with a given public key, and to send it away, to be decrypted on another platform (which will keep and use private key).
For the moment, for test purposes, I try to do all the job in my metro application : key creation, then crypt and decrypt data.
The code above works fine for a small string.
//Key creation
AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey key = provider.CreateKeyPair(1024);
IBuffer privateKey = key.Export(CryptographicPrivateKeyBlobType.Pkcs1RsaPrivateKey);
IBuffer publicKey = key.ExportPublicKey(CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
String publicKeyStr = CryptographicBuffer.EncodeToBase64String(publicKey);
String privateKeyStr = CryptographicBuffer.EncodeToBase64String(privateKey);
//Encrypt
IBuffer encryptionKeyBuffer = CryptographicBuffer.DecodeFromBase64String(publicKeyStr);
AsymmetricKeyAlgorithmProvider encodingProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey encryptKey = encodingProvider.ImportPublicKey(encryptionKeyBuffer, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
IBuffer buf = CryptographicBuffer.ConvertStringToBinary("Hello World!", BinaryStringEncoding.Utf16BE);
var encrypted = CryptographicEngine.Encrypt(encryptKey, buf, null);
//DecrYpt
IBuffer decryptKeyBuffer = CryptographicBuffer.DecodeFromBase64String(privateKeyStr);
AsymmetricKeyAlgorithmProvider decryptionProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey decryptKey = decryptionProvider.ImportKeyPair(decryptKeyBuffer, CryptographicPrivateKeyBlobType.Pkcs1RsaPrivateKey);
IBuffer decryptedBuf = CryptographicEngine.Decrypt(decryptKey, encrypted, null);
Debug.WriteLine(CryptographicBuffer.ConvertBinaryToString(BinaryStringEncoding.Utf16BE, decryptedBuf)); // Display "Hello World!", great
The problem is that when I try to encrypt larger data, I get an Exception on Encrypt Method "Value does not fall within the expected range."
For example the code :
int size = 59;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size; i++)
{
sb.Append("a");
}
IBuffer buf = CryptographicBuffer.ConvertStringToBinary(sb.ToString(), BinaryStringEncoding.Utf16BE);
var encrypted = CryptographicEngine.Encrypt(encryptKey, buf, null);
... works for size = 58 but throws an enxception on Encrypt with size = 59. The limit size depends on key size. This is the limit for a 1024 key size, but with 512 it's a bit smaller, and reversely.
My final buffer is an image, so obviously it will be much greater than my limit... and I don't really understand why the buffer is limited.
Did I do something wrong? Is there a problem in my code? Have you an idea of how to encrypt large data with this method?
Upvotes: 2
Views: 1020
Reputation: 61952
As you noted the size of the encryptable plaintext depends on the key size. When encrypting the message m is the base in modular exponentiation: me (mod n). If you have a message that is bigger or equal to n, it would be wrapped around to another message because of the modulus n.
If m > n and w ≡ m (mod n) then me (mod n) = we (mod n). So when you would decrypt the ciphertext, you wouldn't get the original message back. Because of this the library throws an error.
The solution is to use hybrid encryption. You first encrypt your data with a symmetric cipher like AES using a freshly generated random key. Now the random key for AES is at most 256 bit big, so it will fit into RSA with 1024 bit key (it doesn't fit into a 512 bit key because of padding). You encrypt the AES key with your public key and send the encrypted key along with the encrypted data.
On the other side you will use the private key to recover the random AES key and use it to decrypt the data.
SymmetricKeyAlgorithmProvider sp = SymmetricKeyAlgorithmProvider
.OpenAlgorithm(SymmetricAlgorithmNames.AesGcm);
The other recommended mode is SymmetricAlgorithmNames.AesCcm
. GCM and CCM provide authentication (integrity) which CBC doesn't.
Upvotes: 4