【问题标题】:RSA - Can Encrypt, But encrypted Message is too large for decryptingRSA - 可以加密,但加密的消息太大而无法解密
【发布时间】:2018-11-08 09:42:27
【问题描述】:

编辑:感谢 Lasse Vågsæther Karlsen 的建议。我能够解决我的问题。我使用 Bitconverter 将字节转换为字符串,然后使用 UTF8.GetBytes 将它们转换回字节。这行不通。我决定使用

Convert.FromBase64String Convert.ToBase64String

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

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

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

错误:System.Security.Cryptography.CryptographicException:要解密的数据超出模块的最大值 256 字节。

向客户端发送序列化公钥:

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 类:

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);

服务器接收和解密 AES KEY

// 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.ToStringEncoding.GetBytes 不能成对使用。

标签: c# encryption aes rsa


【解决方案1】:

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

This link on StackExchange 有更多信息。

【讨论】:

  • 我可以加密消息,但在服务器上解密是个问题。我可以在同一个程序中解密消息,但不能在将消息发送到服务器后解密。
  • @Rhelmar 这表明您正在破坏传输中的数据。
【解决方案2】:

您在从加密字节中获取字符串时使用 BitConverter 的任何原因? 您是否尝试过使用 Encoding.UTF8.GetString?

【讨论】:

  • 该死,你打败了我 :) 我个人会使用 Convert.ToBase64String/Convert.FromBase64String。
  • 我会远离 UTF8 来编码对称密钥。密钥实际上应该是随机的 binary 并且二进制数据不会往返于 UTF-8(并非所有字节序列都是有效的 UTF8)。
【解决方案3】:

我强烈建议您考虑使用libsodium 来解决此类问题。他们的明确目标是为加密操作提供更好的 API,以降低您因滥用库而破坏安全性的可能性。

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

【讨论】:

  • 这是评论,不是答案
  • @JamesKPolk 这可能不是他正在寻找的答案,但这是我会给出的答案。另外,我不允许发表评论。
  • 这是一个很好的评论,只是不是一个答案!您需要多少分才能发表评论?
猜你喜欢
  • 1970-01-01
  • 2012-05-08
  • 2011-02-08
  • 2017-02-16
  • 1970-01-01
  • 2012-05-30
  • 2017-11-08
  • 2012-03-13
相关资源
最近更新 更多