error decrjavax.crypto.BadPaddingException: данный последний блок неправильно заполнен. Такие проблемы могут возникнуть, если при расшифровке используется плохой ключ. - PullRequest
0 голосов
/ 10 июля 2020

При работе с Java криптографией я столкнулся со следующей проблемой.

error decrjavax.crypto.BadPaddingException: данный последний блок не заполнен должным образом. Такие проблемы могут возникнуть, если во время дешифрования используется неверный ключ.

Я проверил все возможные ответы, но не смог найти точную причину этого.

Один наблюдение, что когда я использую 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();
        }
    }
}

Ответы [ 2 ]

3 голосов
/ 10 июля 2020

Ваша ошибка - это способ использования ваших потоков при шифровании:

Для 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();
    }
}
0 голосов
/ 12 августа 2020

Есть еще одна причина, по которой, вероятно, контент, который вам нужно описать, но аргументы имеют значение null при передаче в метод, он также выдаст вам badpaddedException.

...