RSA块的数据太多失败。什么是PKCS#7?

时间:2010-04-05 15:08:57

标签: java security cryptography

谈论javax.crypto.Cipher

我试图使用Cipher.getInstance("RSA/None/NoPadding", "BC")加密数据,但我得到了例外:

ArrayIndexOutOfBoundsException: too much data for RSA block

看起来与“NoPadding”有关,所以,阅读填充,看起来像CBC是这里使用的最佳方法。

我在google上发现了一些关于“RSA / CBC / PKCS#7”的内容,这是什么“PKCS#7”?为什么它没有列在sun's standard algorithm names上?

更新

我想知道,如果是填充问题,为什么这个例子运行得很好?

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.Cipher;

/**
 * Basic RSA example.
 */
public class BaseRSAExample
{
    public static void main(
        String[]    args)
        throws Exception
    {
        byte[]           input = new byte[] { (byte)0xbe, (byte)0xef };
        Cipher          cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
        KeyFactory       keyFactory = KeyFactory.getInstance("RSA", "BC");

        // create the keys

        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
                new BigInteger("d46f473a2d746537de2056ae3092c451", 16),
                new BigInteger("11", 16));
        RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(
                new BigInteger("d46f473a2d746537de2056ae3092c451", 16),  
                new BigInteger("57791d5430d593164082036ad8b29fb1", 16));

        RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(pubKeySpec);
        RSAPrivateKey privKey = (RSAPrivateKey)keyFactory.generatePrivate(privKeySpec);

        // encryption step

        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        byte[] cipherText = cipher.doFinal(input);

        // decryption step

        cipher.init(Cipher.DECRYPT_MODE, privKey);

        byte[] plainText = cipher.doFinal(cipherText);

    }
}

更新2:

我意识到,即使我只使用Cipher.getInstance("RSA", "BC"),它也会抛出相同的异常。

7 个答案:

答案 0 :(得分:11)

如果使用分组密码,则输入必须是块比特长度的精确倍数。

为了加密任意长度的数据,首先需要将数据填充到块长度的倍数。这可以通过任何方法完成,但有许多标准。 PKCS7非常常见,您可以看到概述on the wikipedia article on padding

由于块cipers在块上运行,因此您还需要提供一种连接加密块的方法。这非常重要,因为天真的技术大大降低了加密的强度。还有wikipedia article on this

您所做的是尝试加密(或解密)长度与密码的块长度不匹配的数据,并且您还明确要求不填充,也没有链接操作模式。

因此,分组密码无法应用于您的数据,并且您收到了报告的异常。

更新:

作为对您的更新和GregS评论的回应,我想承认GregS是对的(我不知道这与RSA有关),并详细说明:

RSA不对位进行操作,它对整数进行操作。因此,为了使用RSA,您需要将字符串消息转换为整数m:0 < m < n,其中n是生成过程中选择的两个不同素数的模数。 RSA算法中密钥的大小通常是指n。有关详细信息,请参阅wikipedia article on RSA

将字符串消息转换为整数而不丢失(例如截断初始零)的过程通常遵循PKCS#1标准。此过程还为消息完整性(哈希摘要),语义安全性(IV)编辑添加了一些其他信息。使用这些额外数据,可以提供给RSA / None / PKCS1Padding的最大字节数是(keylength-11)。我不知道PKCS#1如何将输入数据映射到输出整数范围,但是 我的印象是它可以使任何长度输入小于或等于keylength - 11并为RSA加密产生一个有效的整数。

如果您不使用填充,您的输入将被简单地解释为数字。您的示例输入{0xbe,0xef}很可能被解释为{10111110 + o 11101111} = 1011111011101111_2 = 48879_10 = beef_16(原文如此!)。从0 <0 beef_16&lt; d46f473a2d746537de2056ae3092c451_16,您的加密将成功。它应该以低于d46f473a2d746537de2056ae3092c451_16的任何数字成功。

bouncycastle FAQ中提到了这一点。他们还说明了以下内容:

  

随附的RSA实施   Bouncy Castle只允许   加密单个数据块。   RSA算法不适合   流数据,不应使用   那样。在这样的情况下你   应使用a加密数据   随机生成的密钥和对称的   密码,之后你应该加密   使用RSA随机生成的密钥,   然后发送加密数据和   加密的随机密钥到另一个   结束他们可以扭转这个过程   (即,使用解密随机密钥   他们的RSA私钥然后解密   数据)。

答案 1 :(得分:4)

RSA是一种带有约束的一次性非对称加密。它一次加密单个“消息”,但消息必须符合基于公钥大小的相当严格的限制。对于典型的1024位RSA密钥,最大输入消息长度(使用PKCS#1标准中描述的RSA)是117字节,不再是。此外,使用这样的密钥,加密消息的长度为128字节,与输入消息长度无关。作为一种通用的加密机制,RSA效率很低,浪费了网络带宽。

对称加密系统(例如AES或3DES)效率更高,它们带有“链接模式”,允许它们处理任意长度的输入消息。但它们没有RSA的“非对称”属性:使用RSA,您可以在不泄露解密密钥的情况下公开加密密钥。这就是RSA的重点。使用对称加密,任何有权加密消息的人也拥有解密消息所需的所有信息,因此您无法公开加密密钥,因为它也会使解密密钥公开。

因此,习惯上使用混合系统,其中(大)消息使用对称密钥(其是随机字节的任意短序列)对称加密(例如,使用AES),并且具有该混合系统。用RSA加密的密钥。接收方然后使用RSA解密来恢复该对称密钥,然后使用它来解密消息本身。

除了上面相当简单的描述之外,加密系统,特别是混合系统,充满了一些细节,如果不加以处理,可能会使你的应用程序对攻击者极其脆弱。因此,最好使用具有已经处理所有艰苦工作的实现的协议。 PKCS#7就是这样一个协议。如今,它以CMS的名义标准化。它用于几个地方,例如S / MIME的核心(加密和签名电子邮件的标准)。用于加密网络流量的另一个众所周知的协议是SSL(现在标准化为TLS,并且经常与HTTP结合使用,作为着名的“HTTPS”协议)。

Java包含SSL的实现(请参阅javax.net.ssl)。 Java不包含CMS实现(至少不在其API中),但Bouncy Castle有一些CMS代码。

答案 2 :(得分:1)

此错误表示输入数据大小大于密钥模数大小。您需要更大的密钥大小来加密数据。如果不能更改密钥长度,或者您可能需要调查是否真的期望大输入数据。

答案 3 :(得分:0)

RSA只能用于加密,当用于加密的位数大于你要加密的东西的大小+ 11个字节时

公钥加密标准 - PKCS

答案 4 :(得分:0)

列出了PKCS#7(指你的链接)。它的编码是PKCS7

说明

  

PKCS#7 SignedData对象,带有   只有重要的领域   证书。

使用java.security.cert.CertificateFactory时使用CertPathPKCS7


RSA是分组密码。它加密相同密钥大小的块。 因此,如果您尝试加密块,BouncyCastle RSA会出现异常 这比密钥大小要长。

到目前为止,我只能告诉你。

答案 5 :(得分:0)

向下滚动一下,你会看到它。它不是一个密码算法(如RSA)或像CBC这样的密码模式,而是描述证书被编码为字节的方式(即数据结构语法)。您可以找到它的规范here

答案 6 :(得分:0)

您不应直接使用RSA加密数据。使用随机对称密钥(即AES / CBC / PKCS5Padding)加密数据,并使用RSA / None / PKCS1Padding加密对称密钥。