错误 decrjavax.crypto.BadPaddingException:给定的最终块未正确填充。如果在解密过程中使用了错误的密钥,就会出现此类问题

error decrjavax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption

我在使用 Java 密码学时遇到以下问题。

error decrjavax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

我已经检查了所有可能的答案,但找不到这背后的确切原因。

一个观察,当我使用 AES/CBC/NoPadding 代替 AES/CBC/PKCS5Padding 时,我可以成功执行它。

这是我的代码片段。

package demo;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;


public class TestEncryption {
    private static final int BUFFER_SIZE = 32;
    private static final int KEY_ITERATIONS = 65535;
    private static final int DEFAULT_KEY_BITS = 128;

    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String TRANSFORMATION = "AES";
    private static final String PBKDF_2_WITH_HMAC_SHA_256 = "PBKDF2WithHmacSHA256";
    private static final int IV_SIZE = 16;

    private final Cipher ecipher;
    private final Cipher dcipher;
    private SecretKey secretKey;

    /**
     * Initialize the ciphers using the given key.
     * @param key
     * @param keyBits
     */
    public TestEncryption(String key, int keyBits) {
        byte[] salt = new byte[8];

        if (key.length() < 8) {
            throw new IllegalArgumentException("key must contain 8 characters or more");
        }

        for (int i = 0; i < 8; i = i + 1) {
            salt[i] = ((byte) key.charAt(i));
        }

        char[] password = key.toCharArray();

        int keyLength = DEFAULT_KEY_BITS;

        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_2_WITH_HMAC_SHA_256);

            if (keyBits == 256) {
                keyLength = 256;
            }

            KeySpec spec = new PBEKeySpec(password, salt, KEY_ITERATIONS, keyLength);
            secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), TRANSFORMATION);
            ecipher = Cipher.getInstance(ALGORITHM);
            dcipher = Cipher.getInstance(ALGORITHM);
        } catch (InvalidKeySpecException | NoSuchPaddingException | NoSuchAlgorithmException e) {

            throw new RuntimeException("Failed to initialize encryption.", e);
        }

    }

    public void encryptFile(File src, File dest){
        try {
            InputStream inputStream = new FileInputStream(src);
            OutputStream outputStream = new FileOutputStream(dest);
            CipherOutputStream cipherOutputStream= new CipherOutputStream(outputStream, ecipher);

            // Generating IV.
            byte[] iv = new byte[IV_SIZE];
            SecureRandom random = new SecureRandom();
            random.nextBytes(iv);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

            // First write the IV at the beginning of the encrypted file.
            outputStream.write(iv, 0, IV_SIZE);

            System.out.println("key " + secretKey);
            // Initialize cipher with IV
            ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;

            // Encrypt input file and write in to output
            while ((bytesRead = inputStream.read(buffer)) > 0) {
                cipherOutputStream.write(buffer, 0, bytesRead);
            }

        } catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {

            System.out.println("error encryption" + e.getMessage());
            e.printStackTrace();
        }
    }

    public void decryptFile(File srcFile, File destFile) {
        try (
                InputStream is = new FileInputStream(srcFile);
                OutputStream out = new FileOutputStream(destFile);
                CipherInputStream cis = new CipherInputStream(is, dcipher)
        ) {
            // Extract IV
            byte[] iv = new byte[IV_SIZE];
            is.read(iv, 0, IV_SIZE);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

            // Initialize cypher with IV
            dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);

            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;

            while ((bytesRead = cis.read(buffer)) > 0) {
                out.write(buffer, 0, bytesRead);
            }
        } catch ( InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {

            System.out.println("error decr" + e.getMessage());
            e.printStackTrace();
        }
    }
}

package demo;

import java.io.*;

public class Client {

    public static void main(String [] args){
        File tempFile =null, src = null, dest = null;

        try {
            tempFile = new File("temp.txt");
            src = new File("C:\Users\x\Desktop\test.txt");
            dest = new File("C:\Users\x\Desktop\out.txt");
            TestEncryption encryption = new TestEncryption("helloworld", 256);
            encryption.encryptFile(src, tempFile);
            encryption.decryptFile(tempFile, dest);
        }
        finally {
            tempFile.delete();
            //src.delete();
            //dest.delete();
        }
    }
}

您的错误是加密时使用流的方式:

对于CipherOutputStream,必须在最后关闭,因为只有在关闭时才能写入最后的填充。

但是在您的代码中,cipherOutputStream 实例永远不会关闭。因此填充永远不会写入加密文件。

当然,在解密文件时,应该填充的地方没有填充,您得到的是 BadPaddingException

因此您应该将加密更改为:

public void encryptFile(File src, File dest) {
    try (InputStream inputStream = new FileInputStream(src);
            OutputStream outputStream = new FileOutputStream(dest)) {

        try (CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, ecipher)) {

            // Generating IV.
            byte[] iv = new byte[IV_SIZE];
            SecureRandom random = new SecureRandom();
            random.nextBytes(iv);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

            // First write the IV at the beginning of the encrypted file.
            outputStream.write(iv, 0, IV_SIZE);

            System.out.println("key 0x" + new BigInteger(1, secretKey.getEncoded()).toString(16));
            // Initialize cipher with IV
            ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;

            // Encrypt input file and write in to output
            while ((bytesRead = inputStream.read(buffer)) >= 0) {
                cipherOutputStream.write(buffer, 0, bytesRead);
            }
        }

    } catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {

        System.out.println("error encryption" + e.getMessage());
        e.printStackTrace();
    }
}

public void decryptFile(File srcFile, File destFile) {
    try (InputStream is = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile)) {
        try (CipherInputStream cis = new CipherInputStream(is, dcipher)) {
            // Extract IV
            byte[] iv = is.readNBytes(IV_SIZE);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

            // Initialize cypher with IV
            dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);

            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead;

            while ((bytesRead = cis.read(buffer)) >= 0) {
                out.write(buffer, 0, bytesRead);
            }
        }
    } catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {

        System.out.println("error decr" + e.getMessage());
        e.printStackTrace();
    }
}

还有一个原因可能是你需要描述的内容,但是传递给方法时参数为null,也会抛出badpaddedException。