I'm working on implementing a hybrid cryptosystem for a project that involves a large amount of cross platform secure network communication. In this instance, the communicating parties are running .NET and Java, so I'm using the provided cryptosystem frameworks from each stack respectively.
I can successfully generate keypairs of the same size (4096 bit) on both of the systems, and have successfully transmitted the keys and loaded them into the remote systems so that I can encrypt with the public key of the remote system on each machine.
I then generate symmetric keys and IVs on both of the systems, and am trying to exchange the symmetric keys between the two systems. Unfortunately, after I've encoded the key and IV information in my custom communication protocol, the data is larger than the key size (not by much, it's typically in the 600-1000 byte area, but still over the ~500 byte limit for my key size).
My solution to this was splitting the data, and running the RSA encryption over the blocks of the appropriate size. However, I don't know what size to be splitting the blocks into, as I've been hearing many different formulas, such as:
((KEY_SIZE) / 8) - 11
((KEY_SIZE) / 8) - 42
However, whenever I encrypt information with the first block size (((KEY_SIZE) / 8) - 11
, which comes out to 501 bytes), RSACryptoServiceProvider.Encrypt(byte[] data, bool fOAEP) throws a Bad Length!
error. Whenever I use the second block size (((KEY_SIZE) / 8) - 42
), it successfully processes the block, but it gives me an output of 513 bytes (it seems any input of between 0-500 bytes gets padded up to this 513 byte value, which I assume is OAEP doing its job), which is too large to decrypt using my 4096 bit key according to my Java cryptosystem (javax.crypto.IllegalBlockSizeException: Data must not be longer than 512 bytes
). If this is the case, why is the .NET cryptosystem giving me a 513 byte output with OAEP, if it cannot be decrypted at this size?
My .NET RSA encryption implementation is below ._rsaProvider
has been initialized with the valid remote public key. RSA_BUFFER_SIZE
is a constant relative to the KEY_SIZE
(which is 4096) (doesn't work if RSA_BUFFER_SIZE
is 501, but works for 496 and below it seems, as explained above):
byte[] block;
using (MemoryStream stream = new MemoryStream())
{
int read = 0;
while (read < data.Length)
{
block = new byte[RSA_BUFFER_SIZE];
int toRead = Math.Min(data.Length - read, block.Length);
Buffer.BlockCopy(data, read, block, 0, toRead);
read += toRead;
byte[] decrypted = _rsaProvider.Encrypt(block, true);
stream.Write(decrypted, 0, decrypted.Length);
}
return stream.ToArray();
}
And here is the Java implementation of decrypting this information (RSA_BUFFER_SIZE
uses the same logic size as above with the same keysize):
byte[] block;
ByteArrayOutputStream output = new ByteArrayOutputStream();
int read = 0;
while (read < data.length) {
block = new byte[RSA_BUFFER_SIZE];
int toRead = Math.min(data.length - read, block.length);
System.arraycopy(data, read, block, 0, toRead);
read += toRead;
output.write(_localAsymmetricCipher.doFinal(block));
}
byte[] ret = output.toByteArray();
output.close();
return ret;
Is there an issue with my implementation?