解密 RSA 数据 Java 时出错:javax.crypto.BadPaddingException:解密错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25698921/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 08:28:36  来源:igfitidea点击:

Error in decryption of RSA data Java: javax.crypto.BadPaddingException: Decryption error

javaencryptioncryptographyrsa

提问by d3im

I have problem with decryption (or maybe wrong encryption, too) of data with RSA in Java. I wanna encrypt public key with some more info in String and then decrypt this public key and encrypt with it something (I use 2048 RSA):

我在 Java 中使用 RSA 解密(或者也可能是错误的加密)数据时遇到问题。我想用 String 中的更多信息加密公钥,然后解密这个公钥并用它加密一些东西(我使用 2048 RSA):

Encryption:

加密:

public void saveExportToFile(String fileName, BigInteger mod, BigInteger exp, String info, PublicKey puk) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(baos));
    try {
        oout.writeObject(mod);
        oout.writeObject(exp);
        oout.writeChars(info);
        oout.close();
        baos.close();
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, puk);

        FileOutputStream fos = new FileOutputStream(new File(fileName));
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        byte[] data = baos.toByteArray();

        int i = 0;
        byte[] buffer = new byte[128];
        byte[] cipherData = null;
        while (i < data.length) {
            if (i+128 >= data.length) {
                buffer = new byte[data.length - i];
                System.arraycopy(data, i, buffer, 0, data.length - i);
                cipherData = cipher.doFinal(buffer);
                bos.write(cipherData);
            } else {
                System.arraycopy(data, i, buffer, 0, 128);
                cipherData = cipher.doFinal(buffer);
                bos.write(cipherData);
            }
            i += 128;
        }

        bos.close();
    } catch (Exception e) {
        throw new IOException("Unexpected error", e);
    }
}

Decryption:

解密:

public void getDataFromRSA(String sendname, PrivateKey privateKey) {
    try {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(sendname)));

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        int length = 0;
        int allLength = 0;
        byte[] buffer = new byte[128];
        byte[] bufferAC = null;
        byte[] outData = null;
        byte[] allData = null;
        byte[] tmpData = null;
        while ( (length = bis.read(buffer)) != -1) {
            if (length < 128) {
                bufferAC = new byte[length];
                System.arraycopy(buffer, 0, bufferAC, 0, length);
                outData = cipher.doFinal(bufferAC);
            } else {
                outData = cipher.doFinal(buffer); // HERE IS THE ERROR
            }
            allLength += outData.length;
            tmpData = allData;
            allData = new byte[allLength];
            System.arraycopy(tmpData, 0, allData, 0, tmpData.length);
            System.arraycopy(outData, 0, allData, tmpData.length, outData.length);
        }
    } catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | ClassNotFoundException | InvalidKeySpecException e) {
        e.printStackTrace();
    }
}

EDITOK, it seems I don't know about encryption as much as I thought. I'd like to use only RSA (if it's possible) since I don't need to transfer info more than once (size of info vary). I've edited encryption like this:

编辑好的,看来我不像我想象的那样了解加密。我只想使用 RSA(如果可能的话),因为我不需要多次传输信息(信息的大小会有所不同)。我已经像这样编辑了加密:

int i = 0;
byte[] buffer = new byte[245];
byte[] cipherData = null;
while (i < data.length) {
    if (i+245 >= data.length) {
        buffer = new byte[data.length - i];
        System.arraycopy(data, i, buffer, 0, data.length - i);
    } else {
        System.arraycopy(data, i, buffer, 0, 245);
    }
    cipherData = cipher.update(buffer);
    bos.write(cipherData);
    i += 245;
}
bos.write(cipher.doFinal()); // HERE IS THE ERROR
bos.close();

And now I get javax.crypto.IllegalBlockSizeException: Data must not be longer than 245 bytes(tried several lower values for buffer size). Is it because data length is not multiple of blocksize? Could this be fixed? Thanks for answers.

现在我得到了javax.crypto.IllegalBlockSizeException: Data must not be longer than 245 bytes(尝试了几个较低的缓冲区大小值)。是不是因为数据长度不是块大小的倍数?这可以解决吗?感谢您的回答。

回答by Maarten Bodewes

First of all, you should be using hybrid encryption, i.e. first encrypt the data using a symmetric cipher and then encrypt the random secret with an RSA key - sending both to the receiver.

首先,您应该使用混合加密,即首先使用对称密码加密数据,然后使用 RSA 密钥加密随机秘密 - 将两者都发送给接收者。

Second, you should never have to perform doFinalin a loop for a single message. Use updateand a single doFinalinstead.

其次,您永远不必doFinal为单个消息循环执行。使用update和单个doFinal代替。

And thirdly, 2048 bits is 256 bytes. As long as you keep trying to decrypt 128 bytes instead of 256, you will get this exception. Usually I use 2048 / Byte.SIZEinstead, it makes the code more readable and will avoid mistakes.

第三,2048 位是 256 字节。只要您继续尝试解密 128 个字节而不是 256 个字节,您就会收到此异常。通常我用2048 / Byte.SIZE它来代替,它使代码更具可读性并且会避免错误。

回答by Tariq Abbas

This exception occurs when you try to encrypt data with private key and decrypt with public key, you need to reverse this or you have to use a single key to encrypt and decrypt your data. This would solve this exception.

当您尝试使用私钥加密数据并使用公钥解密时,会发生此异常,您需要反转这一点,或者您必须使用单个密钥来加密和解密您的数据。这将解决这个异常。