java - RSA block 失败的数据过多。什么是 PKCS#7?

标签 java security cryptography

浅谈javax.crypto.Cipher

我尝试使用 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.

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?

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

    }
}

更新 2:

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

最佳答案

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

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

由于 block 密码器对 block 进行操作,因此您还需要想出一种连接加密 block 的方法。这非常重要,因为天真的技术大大降低了加密的强度。还有一个wikipedia article on this .

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

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

更新:

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

RSA 不对位进行运算,它对整数进行运算。因此,为了使用 RSA,您需要将字符串消息转换为整数 m:0 < m < n , 其中n是在生成过程中选择的两个不同素数的模数。 RSA 算法中 key 的大小通常是指 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 < beef_16 < d46f473a2d746537de2056ae3092c451_16,您的加密将成功。任何小于 d46f473a2d746537de2056ae3092c451_16 的数字都应该成功。

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

关于java - RSA block 失败的数据过多。什么是 PKCS#7?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2579103/

相关文章:

php - 在没有 SSL 的情况下保护与 php 服务器的连接

cryptography - 您采用哪种安全软件开发实践?

java - 如何使用函数 x 中的值作为函数 y 中的构造函数

java - 为什么 spring bootstrap 属性在不同的配置文件中会发生变化?

java - 文本下的 Itext 条码

java - Blender 3D 渲染 Java servlet 接口(interface)

java - 工厂模式 - 在 SQL 存储库中构建然后构建?

javascript - 使用 CryptoJS 对密码进行哈希处理然后使用 php password_hash() 的安全性

java - PrivilegedActionException 试图从 JavaScript 调用签名的 Java applet

c# - 为什么 Node.js 的符号和 CryptographicEngine 的符号结果不同?