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

Tom*_*ito 11 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"?为什么它没有列在太阳的标准算法名称上

更新:

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

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

    }
}
Run Code Online (Sandbox Code Playgroud)

更新2:

我意识到即使我使用Cipher.getInstance("RSA", "BC")它也会引发同样的异常.

Ale*_*ing 11

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

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

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

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

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

更新:

作为对您的更新和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 <beef_16 <d46f473a2d746537de2056ae3092c451_16开始,您的加密将成功.它应该以低于d46f473a2d746537de2056ae3092c451_16的任何数字成功.

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

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