关于c#:RSA – 可以加密,但加密的邮件太大,无法解密

RSA - Can Encrypt, But encrypted Message is too large for decrypting

编辑:多亏了拉斯五世的建议?GS?卡尔森。我能解决我的问题。我使用bitconverter将字节转换为字符串,然后使用utf8.getbytes将它们转换回字节。这不管用。我决定用

Convert.FromBase64String
Convert.ToBase64String

我正在尝试将RSA实现到客户机-服务器C程序中。

我的计划是在服务器上生成一个公钥,并在握手期间将其发送到客户机。然后,客户机将生成一个用RSA公钥加密的AES密钥,并将其发送回服务器。然后,我将在会话期间使用AES加密通信。

问题是,当服务器接收到加密消息时,我会收到一个错误,说明文件超出了限制。即使客户机上的加密消息和服务接收到的消息长度相同,并且内容相同,但如果我将它们转换为XML字符串来比较2的话。

error: System.Security.Cryptography.CryptographicException: The data to be decrypted exceeds the maximum for the module by 256 bytes.

正在将序列化公钥发送到客户端:

1
2
3
4
5
6
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类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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);
}

用于序列化和反序列化的代码:Serialize:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}

Deserialize:

1
2
3
4
5
6
7
8
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);
}

接收、加密和发送回客户

1
2
3
4
5
6
7
8
9
10
11
12
13
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);

服务器接收和解密AES密钥

1
2
3
4
5
6
7
// 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}");


为什么在从加密字节中获取字符串时使用bitconverter?是否尝试使用encoding.utf8.getString?


可以用RSA加密的最大数据大小是245,您应该用随机生成的对称密钥加密主块,并用您的私钥加密该密钥。

StackExchange上的此链接有更多信息。


我强烈建议你考虑用溴化钠来解决这类问题。他们明确的目标是为加密操作提供一个更好的API,以减少误用库而破坏安全的可能性。

另外,您是否也考虑过如何对服务器进行身份验证?您可能不需要新生成的RSA密钥。