简体   繁体   English

解密文本文件中存储为位数组的数据时,为什么会出现“BadPaddingException:消息大于模数”?

[英]Why do I get "BadPaddingException: Message is larger than modulus" when decrypting data stored as a bit array from text file?

I'm using the RSA algorithm to encrypt some numbers, then store those numbers in a bit array within a text file.我使用 RSA 算法来加密一些数字,然后将这些数字存储在文本文件中的位数组中。 The numbers are encrypted and added to the text file just fine, but when I try and decrypt them using the method below, I get "BadPaddingException: Message is larger than modulus" this error in my console.这些数字被加密并添加到文本文件中就好了,但是当我尝试使用下面的方法解密它们时,我在控制台中收到“BadPaddingException:消息大于模数”这个错误。 I'm pretty new to encryption and this is really throwing me off.我对加密很陌生,这真的让我失望。

 Cipher cipher;
    KeyPair pair;

    public byte[] encryptData(String data) throws BadPaddingException, IllegalBlockSizeException {
        try{
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            pair = keyPairGen.generateKeyPair();
            PublicKey publicKey = pair.getPublic();
            cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            cipher.update(data.getBytes());
            cipher.doFinal();
        }
        catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException ex){
            ex.printStackTrace();
        }
        return cipher.doFinal();
    }

writing data into a file将数据写入文件

 String nums = request.getParameter("numbers");
        String password = (String) session.getAttribute("password");
        String filename =  (password +".txt");



        File dir = new File("/volume");
        dir.mkdir();
        File myfile = new File(dir, filename);
        System.out.println("filename: " + filename);
        FileOutputStream output;

        try {
            if (myfile.isFile()){
                 output = new FileOutputStream(myfile, true);
            }
            else{
                 output = new FileOutputStream(myfile);
            }
            byte[] encryptednums = encryptData(nums);
            output.write(encryptednums);
            output.close();
        } catch (BadPaddingException | IllegalBlockSizeException  | IOException e) {
            e.printStackTrace();
        }

Reading the file读取文件

    public byte[] bytesFileReader(File filename){
        try {
            return Files.readAllBytes(Paths.get(String.valueOf(filename)));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

Decryption解密

  HttpSession session = request.getSession();
        KeyPair pair = (KeyPair) session.getAttribute("keypair");
        Cipher cipher = (Cipher) session.getAttribute("cipher");
        String password = (String) session.getAttribute("password");

        String filename = (password +".txt");
        File dir = new File("/volume");
        dir.mkdir();
        File myfile = new File(dir, filename);

        byte[] encryptedBytes = bytesFileReader(myfile);

        try {
            cipher.init(Cipher.DECRYPT_MODE, pair.getPrivate());
            byte[] decipheredText = cipher.doFinal(encryptedBytes);
            System.out.println(new String(decipheredText, StandardCharsets.UTF_8));

        } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException e) {
            e.printStackTrace();
        }

    }

Probably worth noting that this is all taking place across two java servlets.可能值得注意的是,这一切都发生在两个 java servlet 上。

There is one main issue and some minor issues in your code.您的代码中有一个主要问题和一些小问题。 Let's start will a minor one: when converting a string to a byte array and vice versa all conversions have to use a fixed encoding (see your encryptData method):让我们开始一个次要的:当将字符串转换为字节数组时,反之亦然,所有转换都必须使用固定编码(请参阅您的 encryptData 方法):

cipher.update(data.getBytes());

The main issue is the plaintext size limitation when doing RSA encryption.主要问题是进行 RSA 加密时的明文大小限制。 You can calculate the maximum plaintext size with this formula您可以使用此公式计算最大明文大小

1) RSA keysize divided by 8 - e.g. 2048 / 8 = 256 bytes
2) PKCS1 padding takes 11 bytes
3) maximum of plaintext bytes: 256 - 11 = 245 bytes

In my example code I'm using a RSA keypair with size of ( UNSECURE ) 512 bits = 64 bytes, minus 11 bytes for padding there are 53 bytes that can get encrypted.在我的示例代码中,我使用了大小为 ( UNSECURE ) 512 位 = 64 字节的 RSA 密钥对,减去 11 个字节用于填充,有 53 个字节可以加密。 The first round will run like expected, the next encryption with 54 bytes of data runs into the第一轮将按预期运行,下一个 54 字节数据的加密运行到

IllegalBlockSizeException: Data must not be longer than 53 bytes

As your code has only the methods but does not show what data is written I can only assume that you try to decrypt all written data in one run - there is a high chance for failure.由于您的代码只有方法但没有显示写入的数据,我只能假设您尝试在一次运行中解密所有写入的数据 - 失败的可能性很高。

The reason why my code runs into the error (and yours not) is the update- and double (!) final-call (beware I left out the catching that you maybe need):我的代码遇到错误的原因(而不是你的)是更新和双重(!)最终调用(注意我遗漏了你可能需要的捕获):

change:
cipher.update(data.getBytes());
cipher.doFinal();
return cipher.doFinal();
to:
return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

output:输出:

BadPaddingException: Message is larger than modulus
encrypting 12345678901234567890123456789012345678901234567890123
encryptedData length: 64
decryptedData: 12345678901234567890123456789012345678901234567890123
encrypting 123456789012345678901234567890123456789012345678901234
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Data must not be longer than 53 bytes

Security warning: this code uses an UNSECURE 512 bit long RSA key (use minimum 2048 bit) and encrypts with RSA padding PKCS1 that is vulnerable - please use OEAP padding!安全警告:此代码使用不安全的 512 位长 RSA 密钥(使用最少 2048 位)并使用易受攻击的 RSA 填充 PKCS1 进行加密 - 请使用 OEAP 填充! . .

code:代码:

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.nio.charset.StandardCharsets;
import java.security.*;

public class Main {

    static KeyPair keyPair;

    public static void main(String[] args) throws NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, NoSuchPaddingException {
        System.out.println("BadPaddingException: Message is larger than modulus");
        // https://stackoverflow.com/questions/64722370/why-do-i-get-badpaddingexception-message-is-larger-than-modulus-when-decrypti
        keyPair = generateKeyPair(512); // ### do not use RSA keys with 512 bits length, minimum 2048 bits
        // 512 bit = 64 byte - 11 byte for padding = maximal 53 bytes data to encrypt
        System.out.println("\nencrypting 53 chars");
        String data53Chars = "12345678901234567890123456789012345678901234567890123";
        //String data53Chars = "12345678901234567890";
        System.out.println("encrypting " + data53Chars);
        byte[] encryptedData = encryptData(data53Chars);
        System.out.println("encryptedData length: " + encryptedData.length);
        String decryptedData = decryptData(encryptedData);
        System.out.println("decryptedData: " + decryptedData);
        // now 54 bytes
        System.out.println("\nencrypting 54 chars");
        String data54Chars = "123456789012345678901234567890123456789012345678901234";
        System.out.println("encrypting " + data54Chars);
        encryptedData = encryptData(data54Chars);
        System.out.println("encryptedData length: " + encryptedData.length);
        decryptedData = decryptData(encryptedData);
        System.out.println("decryptedData: " + decryptedData);
    }

    public static byte[] encryptData(String data) throws BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException {
        PublicKey publicKey = keyPair.getPublic();
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
    }

    public static String decryptData(byte[] encryptedBytes) throws InvalidKeyException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException {
        byte[] decipheredText = new byte[0];
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
        decipheredText = cipher.doFinal(encryptedBytes);
        return new String(decipheredText, StandardCharsets.UTF_8);
    }

    static KeyPair generateKeyPair(int keyLength) throws NoSuchAlgorithmException {
        final String KEY_ALGORITHM = "RSA";
        KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keygen.initialize(keyLength, new SecureRandom());
        KeyPair keyPair = keygen.generateKeyPair();
        return keyPair;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM