java RSA 块的太多数据失败。什么是 PKCS#7?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2579103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Too much data for RSA block fail. What is PKCS#7?
提问by Tom Brito
Talking about javax.crypto.Cipher
谈论 javax.crypto.Cipher
I was trying to encrypt data using Cipher.getInstance("RSA/None/NoPadding", "BC")but I got the exception:
我试图使用加密数据,Cipher.getInstance("RSA/None/NoPadding", "BC")但出现异常:
ArrayIndexOutOfBoundsException: too much data for RSA block
Looks like is something related to the "NoPadding", so, reading about padding, looks like CBC is the best approach to use here.
看起来与“NoPadding”有关,因此,阅读有关填充的内容,看起来 CBC 是此处使用的最佳方法。
I found at google something about "RSA/CBC/PKCS#7", what is this "PKCS#7"? And why its not listed on sun's standard algorithm names?
我在谷歌上找到了一些关于“RSA/CBC/PKCS#7”的信息,这个“PKCS#7”是什么?为什么它没有列在sun 的标准算法名称中?
Update:
更新:
I'm wondering, if is a padding problem, why this example run just fine?
我想知道,如果是填充问题,为什么这个例子运行得很好?
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);
}
}
Update 2:
更新 2:
I realized that even if I use just Cipher.getInstance("RSA", "BC")it throws the same exception.
我意识到即使我只使用Cipher.getInstance("RSA", "BC")它也会抛出相同的异常。
采纳答案by Alexander Torstling
If you use a block cipher, you input must be an exact multiple of the block bit length.
如果使用分组密码,则输入必须是分组位长度的精确倍数。
In order to encipher arbitrary length data, you need first to pad you data to a multiple of the block length. This can be done with any method, but there are a number of standards. PKCS7 is one which is quite common, you can see an overview on the wikipedia article on padding.
为了加密任意长度的数据,您首先需要将数据填充为块长度的倍数。这可以用任何方法完成,但有许多标准。PKCS7 是一种非常常见的,您可以在 wikipedia 上的 padding 文章中看到概述。
Since block cipers operate on blocks, you also need to come up with a way of concatenating the encrypted blocks. This is very important, since naive techniques greatly reduce the strength of the encryption. There is also a wikipedia article on this.
由于块密码对块进行操作,因此您还需要想出一种连接加密块的方法。这非常重要,因为幼稚的技术大大降低了加密的强度。还有一篇关于此的维基百科文章。
What you did was to try to encrypt (or decrypt) data of a length which didn't match the block length of the cipher, and you also explicitly asked for no padding and also no chaining mode of operation.
您所做的是尝试加密(或解密)长度与密码块长度不匹配的数据,并且您还明确要求没有填充和链接操作模式。
Consequently the block cipher could not be applied to your data, and you got the reported exception.
因此,块密码无法应用于您的数据,并且您收到了报告的异常。
UPDATE:
更新:
As a response to your update and GregS's remark, I would like to acknowledge that GregS was right (I did not know this about RSA), and elaborate a bit:
作为对您的更新和 GregS 评论的回应,我想承认 GregS 是对的(我不知道 RSA),并详细说明一下:
RSA does not operate on bits, it operates on integer numbers. In order to use RSA you therefore need to convert your string message into an integer m: 0 < m < n, where nis the modulus of the two distinct primes chosen in the generation process. The size of a key in the RSA algorithm typically refers to n. More details on this can be found on the wikipedia article on RSA.
RSA 不对位进行运算,而是对整数进行运算。因此,为了使用 RSA,您需要将字符串消息转换为整数 m: 0 < m < n,其中n是在生成过程中选择的两个不同素数的模数。RSA 算法中密钥的大小通常是指n. 可以在维基百科上关于 RSA 的文章中找到有关这方面的更多详细信息。
The process of converting a string message to an integer, without loss (for instance truncating initial zeroes), the PKCS#1standard is usually followed. This process also adds some other information for message integrity (a hash digest), semantical security (an IV) ed cetera. With this extra data, the maximum number of bytes which can be supplied to the RSA/None/PKCS1Padding is (keylength - 11). I do not know how PKCS#1 maps the input data to the output integer range, but my impression is that it can take any length input less than or equal to keylength - 11 and produce a valid integer for the RSA encryption.
将字符串消息不丢失地转换为整数的过程(例如截断初始零),通常遵循PKCS#1标准。此过程还为消息完整性(散列摘要)、语义安全性(IV)等添加了一些其他信息。有了这个额外的数据,可以提供给 RSA/None/PKCS1Padding 的最大字节数是 (keylength - 11)。我不知道 PKCS#1 如何将输入数据映射到输出整数范围,但我的印象是它可以接受小于或等于 keylength - 11 的任何长度输入,并为 RSA 加密生成一个有效整数。
If you use no padding, your input will simply be interpreted as a number. Your example input, {0xbe, 0xef} will most probably be interpreted as {10111110 +o 11101111} = 1011111011101111_2 = 48879_10 = beef_16 (sic!). Since 0 < beef_16 < d46f473a2d746537de2056ae3092c451_16, your encryption will succeed. It should succeed with any number less than d46f473a2d746537de2056ae3092c451_16.
如果您不使用填充,您的输入将被简单地解释为一个数字。您的示例输入 {0xbe, 0xef} 很可能会被解释为 {10111110 +o 11101111} = 1011111011101111_2 = 48879_10 = beef_16(原文如此!)。由于 0 <beef_16 <d46f473a2d746537de2056ae3092c451_16,您的加密将成功。任何小于 d46f473a2d746537de2056ae3092c451_16 的数字都应该成功。
This is mentioned in the bouncycastle FAQ. They also state the following:
bouncycastle FAQ 中提到了这一点。他们还声明了以下内容:
The RSA implementation that ships with Bouncy Castle only allows the encrypting of a single block of data. The RSA algorithm is not suited to streaming data and should not be used that way. In a situation like this you should encrypt the data using a randomly generated key and a symmetric cipher, after that you should encrypt the randomly generated key using RSA, and then send the encrypted data and the encrypted random key to the other end where they can reverse the process (ie. decrypt the random key using their RSA private key and then decrypt the data).
Bouncy Castle 附带的 RSA 实现只允许加密单个数据块。RSA 算法不适合流式传输数据,不应以这种方式使用。在这种情况下,您应该使用随机生成的密钥和对称密码对数据进行加密,然后您应该使用 RSA 加密随机生成的密钥,然后将加密的数据和加密的随机密钥发送到另一端,在那里他们可以反转该过程(即使用他们的 RSA 私钥解密随机密钥,然后解密数据)。
回答by Thomas Pornin
RSA is a one-shot asymmetric encryption with constraints. It encrypts a single "message" in one go, but the message has to fit within rather tight limits based on the public key size. For a typical 1024 bit RSA key, the maximum input message length (with RSA as described in the PKCS#1standard) is 117 bytes, no more. Also, with such a key, the encrypted message has length 128 bytes, regardless of the input message length. As a generic encryption mechanism, RSA is very inefficient, and wasteful of network bandwidth.
RSA 是一种具有约束的一次性非对称加密。它一次性加密单个“消息”,但该消息必须符合基于公钥大小的相当严格的限制。对于典型的 1024 位 RSA 密钥,最大输入消息长度(使用PKCS#1标准中描述的 RSA )是 117 个字节,不能更多。此外,使用这样的密钥,无论输入的消息长度如何,加密消息的长度都是 128 字节。RSA作为一种通用的加密机制,效率非常低,而且浪费网络带宽。
Symmetricencryption systems (e.g. AES or 3DES) are much more efficient, and they come with "chaining modes" which allow them to process input messages of arbitrary length. But they do not have the "asymmetric" property of RSA: with RSA, you can make the encryption key public without revealing the decryption key. That's the whole point of RSA. With symmetric encryption, whoever has the power to encrypt a message also has all the needed information to decrypt messages, hence you cannot make the encryption key public because it would make the decryption key public as well.
对称加密系统(例如 AES 或 3DES)效率更高,它们带有“链接模式”,允许它们处理任意长度的输入消息。但它们没有 RSA 的“非对称”属性:使用 RSA,您可以公开加密密钥,而无需透露解密密钥。这就是 RSA 的全部意义所在。使用对称加密,有权加密消息的人也拥有解密消息所需的所有信息,因此您不能公开加密密钥,因为它也会公开解密密钥。
Thus it is customary to use an hybrid system, in which a (big) message is symmetrically encrypted (with, e.g., AES), using a symmetric key (which is an arbitrary short sequence of random bytes), and have that key encrypted with RSA. The receiving party then uses RSA decryption to recover that symmetric key, and then uses it to decrypt the message itself.
因此,习惯上使用混合系统,其中(大)消息使用对称密钥(它是随机字节的任意短序列)对称加密(例如,使用 AES),并使用对称密钥加密该密钥RSA。接收方然后使用 RSA 解密来恢复该对称密钥,然后使用它来解密消息本身。
Beyond the rather simplistic description above, cryptographic systems, in particular hybrid systems, are clock full of little details which, if not taken care of, may make your application extremely weak against attackers. So it is best to use a protocol with an implementation which already handles all that hard work. PKCS#7 is such a protocol. Nowadays, it is standardized under the name of CMS. It is used in several places, e.g. at the heart of S/MIME (a standard for encrypting and signing emails). Another well-known protocol, meant for encrypting network traffic, is SSL (now standardized under the name of TLS, and often used in combination with HTTP as the famous "HTTPS" protocol).
除了上面相当简单的描述之外,密码系统,特别是混合系统,时钟充满了小细节,如果不加以注意,可能会使您的应用程序对攻击者的攻击极其脆弱。所以最好使用一个协议,它的实现已经处理了所有这些艰苦的工作。PKCS#7 就是这样一个协议。如今,它以CMS的名义标准化。它在多个地方使用,例如在 S/MIME(用于加密和签名电子邮件的标准)的核心。另一个众所周知的用于加密网络流量的协议是 SSL(现在标准化为TLS,并且经常与 HTTP 结合使用,作为著名的“HTTPS”协议)。
Java contains an implementation of SSL (see javax.net.ssl). Java does not contain a CMS implementation (at least not in its API) but Bouncy Castlehas some code for CMS.
Java 包含 SSL 的实现(请参阅 参考资料javax.net.ssl)。Java 不包含 CMS 实现(至少在其 API 中没有),但Bouncy Castle有一些 CMS 代码。
回答by ordinary guy
This error indicates that the input data size is greater than the key modulus size. You will need a bigger key size to encrypt the data. If changing the key length is not an option, alternatively you may need to investigate if you are really expecting that big input data.
此错误表示输入数据大小大于密钥模数大小。您将需要更大的密钥大小来加密数据。如果更改密钥长度不是一个选项,或者您可能需要调查您是否真的期待大输入数据。
回答by ig0774
Scroll down a bit and you'll see it. It's not an cypher algortihm (like RSA) or a cypher mode like CBC, but a description of the way the certificate is encoded as bytes (i.e., a data structure syntax). You can find the spec for it here.
向下滚动一点,你会看到它。它不是密码算法(如 RSA)或密码模式(如 CBC),而是对证书编码为字节(即数据结构语法)方式的描述。您可以在此处找到它的规范。
回答by Rasmus Faber
You should not encrypt your data using RSA directly. Encrypt your data with a random symmetric key (i.e. AES/CBC/PKCS5Padding) and encrypt the symmetric key using RSA/None/PKCS1Padding.
您不应直接使用 RSA 加密您的数据。使用随机对称密钥(即 AES/CBC/PKCS5Padding)加密您的数据,并使用 RSA/None/PKCS1Padding 加密对称密钥。
回答by Dave
RSA can only be used to encrypt, when the number of bits being used to encrypt is greater then the size of the thing you are tying to encrypt + 11 bytes
RSA 只能用于加密,当用于加密的位数大于您要加密的内容的大小时 + 11 个字节
Public-Key Cryptography Standards - PKCS
公钥密码学标准 - PKCS
回答by Buhake Sindi
PKCS#7 is listed (referring to your link). It's encoding is PKCS7
列出了 PKCS#7(参考您的链接)。它的编码是PKCS7
Description
描述
A PKCS#7 SignedData object, with the only significant field being certificates.
一个 PKCS#7 SignedData 对象,唯一重要的字段是证书。
Use java.security.cert.CertificateFactoryor CertPathwhen using PKCS7.
使用java.security.cert.CertificateFactory或CertPath使用时PKCS7。
RSA is a block cipher. It encrypts block of the same key size. Therefore, BouncyCastle RSA gives an exception if you try to encrypt a block which is longer than the key size.
RSA 是一种分组密码。它加密相同密钥大小的块。因此,如果您尝试加密长度超过密钥大小的块,BouncyCastle RSA 会给出一个例外。
That's all I can tell you so far.
到目前为止我能告诉你的就是这些。

