Reputation: 21
I am working on an assignment regarding RSA encryption and decryption. For this assignment we have to be able to encrypt and decrypt ANY size key.
I have written code that successfully encrypts and decrypts (given that key does not exceed the maximum key size) but now I need to modify this code to handle any size.
public partial class Form1 : Form
{
//Strings to hold public & private keys
String publicKey, privateKey;
UnicodeEncoding encoder = new UnicodeEncoding();
public Form1()
{
RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider();
InitializeComponent();
privateKey = myRSA.ToXmlString(true);
publicKey = myRSA.ToXmlString(false);
}
private void btnEncrypt_Click(object sender, EventArgs e)
{
var myRSA = new RSACryptoServiceProvider();
//Set cryptoserviceprovider with the proper key
myRSA.FromXmlString(publicKey);
//Encode the data to encrypt as a byte array
var dataToEncrypt = encoder.GetBytes(txtPlain.Text);
//Encrypt the byte array
var encryptedByteArray = myRSA.Encrypt(dataToEncrypt, false).ToArray();
var length = encryptedByteArray.Count();
var item = 0;
var sb = new StringBuilder();
//Change each byte in the encrypted byte array to text
foreach(var x in encryptedByteArray)
{
item++;
sb.Append(x);
if (item < length) sb.Append(",");
}
txtCypher.Text = sb.ToString();
}
private void btnDecrypt_Click(object sender, EventArgs e)
{
var myRSA = new RSACryptoServiceProvider();
//Split data into an array
var dataArray = txtCypher.Text.Split(new char[] { ',' });
//Convert chars to bytes
byte[] dataByte = new byte[dataArray.Length];
for(int i = 0; i < dataArray.Length; i++) dataByte[i] = Convert.ToByte(dataArray[i]);
//Decrypt the byte array
myRSA.FromXmlString(privateKey);
var decryptedBytes = myRSA.Decrypt(dataByte, false);
//place into cypher text box
txtPlain.Text = encoder.GetString(decryptedBytes);
}
}
I have come up with the following code to be able to encrypt any size (which seems to work to my knowledge):
//store dataLength
int dataLength = dataToEncrypt.Length;
//Check if dataLength > 117
if (dataLength > 117)
{
//Divide dataLength by 128 to determine how many cycles will be needed
float numOfCycles = (dataLength / 117);
//round up to nearest whole number
cycles = (int)Math.Ceiling(numOfCycles);
//for however many cycles
for (int i = 0; i < cycles; i++)
{
var myByteArray = new byte[117];
for (int j = 0; j < 117; j++)
{
int currentByte = i * 117 + j;
myByteArray[j] = dataToEncrypt[currentByte];
}
var encryptedByteArray = myRSA.Encrypt(myByteArray, false).ToArray();
var length = encryptedByteArray.Count();
var item = 0;
//Change each byte in the encrypted byte array to text
foreach (var x in encryptedByteArray)
{
item++;
sb.Append(x);
if (item < length) sb.Append(",");
}
txtCypher.Text = sb.ToString();
}
}
else
{
var encryptedByteArray = myRSA.Encrypt(dataToEncrypt, false).ToArray();
var length = encryptedByteArray.Count();
var item = 0;
var sb = new StringBuilder();
//Change each byte in the encrypted byte array to text
foreach(var x in encryptedByteArray)
{
item++;
sb.Append(x);
if (item < length) sb.Append(",");
}
txtCypher.Text = sb.ToString();
}
And the following code to decrypt any size which ISN'T WORKING:
float length = dataArray.Count();
float numOfCycles = (length / 117);
int cycles = (int)Math.Ceiling(numOfCycles);
for (int i = 0; i < cycles; i++)
{
byte[] dataByte = new byte[117];
for(int j = 0; j < 117; j++)
{
//Convert chars to bytes
dataByte[j] = Convert.ToByte(dataArray[ i * 117 + j ]);
}
//Decrypt the byte array
myRSA.FromXmlString(privateKey);
var decryptedBytes = myRSA.Decrypt(dataByte, false);
txtPlain.Text += encoder.GetString(decryptedBytes);
}
The following line: var decryptedBytes = myRSA.Decrypt(dataByte, false);
throws the error: An unhandled exception of type 'System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll
Additional information: Bad Data.
I have no idea why this error is being thrown, I have debugged the program and the data stored in dataByte[] does not seem to be any different from what was being stored inside when I successfully decrypt a message of size smaller than the maximum key size.
Upvotes: 2
Views: 1397
Reputation: 61942
RSA, as a asymmetric cryptosystem, is really slow compared to symmetric ciphers like AES. The proper way to implement this would be to generate a symmetric AES key, encrypt the actual data with AES (e.g. with CBC/CTR/GCM/EAX) and then encrypt the single key with RSA.
There is no standard to apply RSA to multiple "blocks", so it is not recommended to implement this. If you still want to implement it, here are some problems with your code.
RSA needs padding to be secure. Since you're using a 128 byte key and split the plaintext into 117 byte blocks, this means that you're using PKCS#1 v1.5 padding. Each block will be padded and then encrypted. The ciphertext is numerically strictly smaller than the modulus, but usually pretty close to it. Most ciphertexts will be 128 byte long, but some may be smaller, because a ciphertext is a serialized number where the leading zeros don't have to be stored. That means that you cannot simply write them one after the other and expect to read them back correctly.
You either need to pad the ciphertexts with 0x00 bytes so that they are all of the same length (128 byte) or store the length of each ciphertext before the corresponding ciphertext so that you know how much you have to read.
Upvotes: 2