当数据阵列的第一个条目为零时,使用RSA加密获得太短的数组

use*_*751 5 java arrays encryption rsa bouncycastle

我试图使用java bouncy castle库来使用RSA来解密和解密一个短字节数组.我做了以下步骤:

  1. 生成2048位密钥对.
  2. 创建一个短数据字节数组,其中第一个条目为零.
  3. 使用生成的密钥和RSA加密数据阵列.
  4. 使用生成的密钥和RSA解密加密的数据阵列.
  5. 比较原始和解密的数据数组.

我注意到原始和解密的数据数组不一样.解密的数据数组缺少第一个条目,因此比原始数据数组短1.仅当数据数组的第一个条目为"0"时才会发生这种情况.为什么会这样?解密不应该返回相同的数据数组吗?或者我对图书馆的假设,使用和理解是错误的?

这里是完整的测试用例(带有导入以便更好地理解):

import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.Arrays;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.provider.JDKKeyPairGenerator;
import org.bouncycastle.util.encoders.Hex;
import org.hive2hive.core.H2HJUnitTest;
import org.junit.Test;

public class EncryptionUtil2Test {

    @Test
    public void testBug() throws IOException, InvalidKeyException, IllegalBlockSizeException,
        BadPaddingException, DataLengthException, IllegalStateException, InvalidCipherTextException,
        NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException,
        InvalidAlgorithmParameterException {

        Security.addProvider(new BouncyCastleProvider());

        // generate RSA keys
        BigInteger publicExp = new BigInteger("10001", 16); // Fermat F4, largest known fermat prime
        JDKKeyPairGenerator gen = new JDKKeyPairGenerator.RSA();
        RSAKeyGenParameterSpec params = new RSAKeyGenParameterSpec(2048, publicExp);
        gen.initialize(params, new SecureRandom());
        KeyPair keyPair = gen.generateKeyPair();

        // some data where first entry is 0
        byte[] data = { 0, 122, 12, 127, 35, 58, 87, 56, -6, 73, 10, -13, -78, 4, -122, -61 };

        // encrypt data asymmetrically
        Cipher cipher = Cipher.getInstance("RSA", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
        byte[] rsaEncryptedData = cipher.doFinal(data);

        // decrypt data asymmetrically
        cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
        byte[] dataBack = cipher.doFinal(rsaEncryptedData);

        System.out.println("data      = " + Hex.toHexString(data));
        System.out.println("data back = " + Hex.toHexString(dataBack));

        assertTrue(Arrays.equals(data, dataBack));

    }

}
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

Maa*_*wes 3

这是因为没有指定必须使用的填充机制;您要做的就是将填充机制留给提供者,在本例中为 Bouncy。Bouncy 似乎默认不使用填充机制。

在这种情况下,“RSA”运算的结果就是执行模幂运算(使用私有指数)时得到的数字。由于数字不是字节数组,因此必须将其转换为字节数组。由于数字的初始零的数量是未知的,因此它们被简单地去除。

为了避免这种情况(并按照定义使用 RSA,RSA需要 padding ),如果您想要更现代/安全的版本,请尝试使用"RSA/ECB/PKCS1Padding"或。"RSA/ECB/OAEPWithSHA-1AndMGF1Padding"众所周知,没有填充的 RSA 是不安全的。

想象一下,如果明文转换为数字 1 会发生什么。如果使用公共指数执行模幂,结果仍然只是 1。显然,这不是 RSA 的初衷。

如果没有随机填充,加密还具有令人讨厌的特性,即对于相同的密文加密为相同的结果(如果您有已知的密文,则加密"yes""no"很容易区分"yes")。