RSA加密,获取错误的长度

68

当调用以下函数时:

byte[] bytes = rsa.Encrypt(System.Text.UTF8Encoding.UTF8.GetBytes(stringToEncrypt), true);

我现在遇到了错误:bad length。

如果使用更小的字符串,它可以正常工作,有什么想法吗?我传递的字符串不到200个字符。

4个回答

101

RSA加密只适用于小量数据,能够加密的数据量取决于所使用密钥的大小,例如使用1024位RSA密钥和PKCS # 1 V1.5填充,最多可以加密117个字节,而使用2048位RSA密钥,则可以加密245个字节。

这样做是有充分理由的,因为非对称加密计算成本高昂。如果您想要加密大量数据,应该使用对称加密。但是,如果您需要确保不可否认性,那么您可以同时使用两种加密方式。您可以创建一个对称密钥,并使用非对称加密来交换它,然后使用安全交换后的对称密钥来加密大量数据。这就是SSL和WS-Secure在内部使用的方法。


你知道应该使用哪个 .net 对象来加密长达 500 个字符的字符串吗? - JL.
任何对称算法。这取决于您想要加密的目的。最好将其表述为另一个问题。 - blowdart
7
不仅是计算量大的问题。RSA算法加密一个特定数字,生成另一个数字。由于算法的运作方式,这个数字有一个最大大小限制。密钥越宽,能够加密的最大数字就越大。1024位密钥是一个128字节宽的数字,而2048位密钥为256字节。每个密钥能够加密最大宽度略小于其本身宽度的数字。如果输入数字过大,则输出结果将与加密在范围内的另一个数字相同,无法确定实际输入是哪一个。 - Jonathan Gilbert
当我尝试第二次加密相同的数据时,出现了这个异常。有什么想法是什么原因引起的吗? - mrid
可能是因为密文(加密输出)比原始明文要大,所以尽管原始明文的大小足够适合您的算法,但密文不行。 - thinkOfaNumber

62

对于未来搜索RSA不良长度异常的情况...

您可以使用以下方法计算可以使用特定密钥大小加密的最大字节数:

((KeySize - 384) / 8) + 37

然而,如果采用了最优非对称加密填充(OAEP)参数,就像原始帖子中一样,以下内容可以用于计算最大字节数:

((KeySize - 384) / 8) + 7

合法的密钥大小为384到16384,跳过的大小为8。


2
((KeySize - 384) / 8) + 7 对我无效。请参见 https://crypto.stackexchange.com/questions/42097/what-is-the-maximum-size-of-the-plaintext-message-for-rsa-oaep 正确的公式应该是:((KeySize - 384) / 8) + 6。 - Bin4ry

21
如上所述,“bad length”类型异常的解决方案是混合使用对称和非对称加密,以便加密的文本大小不受密钥大小的限制。基本上,您可以使用RSA加密来非对称地加密随机密钥

 

加密:

    
     
  1. 生成所需长度的随机密钥,例如AES或Rijndael对称加密技术。

  2.  
  3. 使用步骤1生成的随机密钥,对您的文本/数据进行AES / Rijndael对称加密。

  4.  
  5. 使用RSA,非对称地加密在步骤1中生成的随机密钥。

  6.  
    

解密:

    
     
  1. 首先使用您的私钥RSA解密AES / Rijndael生成的随机密钥。

  2.  
  3. 然后使用RSA解密随机密钥,以解密原始文本/数据。

  4.  

您可以查看以下C#示例进行演示:

http://www.technical-recipes.com/2013/using-rsa-to-encrypt-large-data-files-in-c/


8
我在进行 RSA 2048 加密时,遇到了同样的问题,即对少于 200 个字符的明文进行加密。
我认为,我们可以通过以下简单的步骤来实现目标,而不必涉及对称或非对称加密的复杂性;
通过这样做,我成功地加密和解密了 40 倍大的文本。
加密:
1. 使用 *Zip() 方法压缩明文并转换为字节数组 2. 使用 RSA 进行加密
解密:
1. 使用 RSA 解密密文 2. 使用 **Unzip() 方法解压解密后的数据
*byte[] bytes = Zip(stringToEncrypt); // 下面是 Zip() 方法的复制品
**decryptedData = Unzip(decryptedBytes); // 下面是 Unzip() 方法的复制品
public static byte[] Zip(string str)
{
    var bytes = System.Text.Encoding.UTF8.GetBytes(str);    
    using (var msi = new MemoryStream(bytes))
    using (var mso = new MemoryStream())
    {
        using (var gs = new GZipStream(mso, CompressionMode.Compress))
        {                        
            CopyTo(msi, gs);
        }    
        return mso.ToArray();
    }
}
public static string Unzip(byte[] bytes)
{
    using (var msi = new MemoryStream(bytes))
    using (var mso = new MemoryStream())
    {
        using (var gs = new GZipStream(msi, CompressionMode.Decompress))
        {                     
            CopyTo(gs, mso);
        }    
        return System.Text.Encoding.UTF8.GetString(mso.ToArray());
    }
}

public static void CopyTo(Stream src, Stream dest)
    {
        byte[] bytes = new byte[4096];

        int cnt;

        while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
        {
            dest.Write(bytes, 0, cnt);
        }
    }

嗨,CopyTo是做什么用的? - foyss
1
@foyss 谢谢您指出,我已经在答案中添加了CopyTo()方法。 - S.ATTA.M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接