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

谈论javax.crypto.Cipher

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

  ArrayIndexOutOfBoundsException:RSA块的数据太多 

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

我在google上发现了一些关于“RSA / CBC / PKCS#7”的内容,这是什么“PKCS#7”? 为什么它没有列在太阳的标准算法名称上 ?

更新:

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

 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")Cipher.getInstance("RSA", "BC")抛出相同的exception。

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

为了加密任意长度的数据,首先需要将数据填充到块长度的倍数。 这可以通过任何方法完成,但有许多标准。 PKCS7很常见,您可以在维基百科上看到有关填充的文章的概述。

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

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

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

更新:

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

RSA不对位进行操作,它对整数进行操作。 因此,为了使用RSA,您需要将字符串消息转换为整数m: 0 < m < n ,其中n是生成过程中选择的两个不同素数的模数。 RSA算法中密钥的大小通常是指n 。 有关这方面的更多详细信息,请参阅维基百科关于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

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

Bouncy Castle附带的RSA实现仅允许加密单个数据块。 RSA算法不适合流数据,不应该以这种方式使用。 在这种情况下,您应该使用随机生成的密钥和对称密码对数据进行加密,之后您应该使用RSA加密随机生成的密钥,然后将加密的数据和加密的随机密钥发送到另一端。反转过程(即,使用他们的RSA私钥解密随机密钥,然后解密数据)。

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代码。

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

RSA只能用于加密,当用于加密的比特数大于您要加密的事物的大小+ 11字节时

公钥加密标准 – PKCS

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

列出了PKCS#7(参考您的链接)。 它的编码是PKCS7

描述

PKCS#7 SignedData对象,唯一重要的字段是证书。

使用PKCS7时,请使用java.security.cert.CertificateFactoryCertPath


RSA是分组密码。 它加密相同密钥大小的块。 因此,如果您尝试加密长度超过密钥大小的块,则BouncyCastle RSA会出现exception。

到目前为止,我可以告诉你这一切。

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