Reputation: 1
Edit: Thanks to the advice from Lasse Vågsæther Karlsen. I was able to solve my problem. I used Bitconverter to convert bytes to a string and then used UTF8.GetBytes to convert them back to bytes. This doesn't work. I decided to use
Convert.FromBase64String
Convert.ToBase64String
I'm trying to implement RSA into a Client-Server C# Program.
My Plan is to generate a public key on the server and send it to the client during the handshake. The client will then generate an AES Key that is encrypted with the RSA public key and send it back to the server. I will then use AES to encrypt communication during the session.
The problem is that, when the Server receives the encrypted Message, I get an error that says the file exceeds limitations. Even though the encrypted message on the client and when the service receives it are the same length and have the same content if I convert them into an XML string to compare the 2.
error: System.Security.Cryptography.CryptographicException: The data to be decrypted exceeds the maximum for the module by 256 bytes.
Sending serialized public key to client:
RSAManager rSAManager = new RSAManager();
string publicKeyString = SerializeKey(rSAManager.publicKey); // Serialize the public key so we can send it to the clients
// Send test data to the remote device.
Send(client, $"{publicKeyString}!");
RSAManager
Class:public class RSAManager
{
#region Keys, Containername, Keysizes
public RSAParameters publicKey;
public RSAParameters privateKey;
static string CONTAINER_NAME = "MyContainerName";
public enum KeySizes
{
SIZE_512 = 512,
SIZE_1024 = 1024,
SIZE_2048 = 2048,
SIZE_952 = 952,
SIZE_1369 = 1369
};
#endregion
#region Methods
public RSAManager()
{
GenerateKeys();
}
public void GenerateKeys()
{
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false; //Don't store the keys in a key container
publicKey = rsa.ExportParameters(false);
privateKey = rsa.ExportParameters(true);
}
}
/// <summary>
/// Encrypts the given byte array with the RSA standard
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public byte[] Encrypt(string message)
{
byte[] input = Encoding.UTF8.GetBytes(message);
byte[] encrypted;
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false;
rsa.ImportParameters(publicKey);
encrypted = rsa.Encrypt(input, true);
}
return encrypted;
}
/// <summary>
/// Decrypts the given byte array with the RSA standard
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public string Decrypt(byte[] encrypted)
{
byte[] decrypted;
using (var rsa = new RSACryptoServiceProvider(2048))
{
rsa.PersistKeyInCsp = false;
rsa.ImportParameters(privateKey);
decrypted = rsa.Decrypt(encrypted, true);
}
return Encoding.UTF8.GetString(decrypted);
}
static string SerializeKey(RSAParameters publicKey)
{
string publicKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs1 = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs1.Serialize(sw, publicKey);
//get the string from the stream
publicKeyString = sw.ToString();
}
return publicKeyString;
}
static RSAParameters DeSerializeKey(string publicKeyString)
{
var sr = new System.IO.StringReader(publicKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
return (RSAParameters)xs.Deserialize(sr);
}
string publicKeyString = TrimString(new string[] {"!"},content);
RSAManager rSAManager = new RSAManager();
rSAManager.publicKey = DeSerializeKey(publicKeyString);
string randomAESKey = GetRandomString(40);
Console.WriteLine($"Randomstring: {randomAESKey");
byte[] encrypted = rSAManager.Encrypt(randomAESKey);
string encryptedAESKey = BitConverter.ToString(encrypted);
Console.WriteLine($"Encrypted. {encryptedAESKey}");
Console.WriteLine("Length of encrypted string: " + encryptedAESKey.Length);
// Echo the data back to the server.
Send(handler, encryptedAESKey);
// Write the response to the console.
Console.WriteLine("Length of encrypted response: " + response.Length);
Console.WriteLine("Length of public Key: " + SerializeKey(rSAManager.publicKey).Length);
// Decrypt functions needs byte array so we need to encode it. This line always causes the error.
string encryptedResponse = rSAManager.Decrypt(Encoding.UTF8.GetBytes(response));
// Received encrypted response
Console.WriteLine($"Decrypted response: {encryptedResponse}");
Upvotes: 0
Views: 2332
Reputation: 233
I strongly recommend that you consider using libsodium for this kind of problem. Their explicit goal is to provider a better API for cryptographic operations to make it less likely that you will screw up your security by misusing the library.
Also, have you also considered how you are going to authenticate the server? You might not need a newly generated RSA key.
Upvotes: -1
Reputation: 128
Any reason why you are using BitConverter while getting a string back from encrypted bytes? Did you try using Encoding.UTF8.GetString?
Upvotes: 1
Reputation: 16119
The maximum size of data that can be encrypted with RSA is 245, what you're supposed to do is encrypt the main block with a randomly generated symmetric key and encrypt that key with your private key.
This link on StackExchange has some more info.
Upvotes: 1