Ошибка во время дешифрования AES. Исключение IllegalBlockSizeException

#java #encryption #aes

#java #шифрование #aes

Вопрос:

Я пробую простую программу, которая шифрует и расшифровывает текстовый файл. Шифрование работает нормально, но расшифровка запутана.

Это мой файл с классом jCryptFile, который выполняет эту работу. Сначала это создает 16-байтовое хранилище ключей ключей из строки входного ключа. Затем расшифровывает файл. Все делается с использованием класса Cipher в java:

Файл jCryptFile.java:

 public class jCryptFile {
    public static final String ALGORITHM = "AES";
    public static final String TRANSFORMATION = "AES";

    public static void encrypt(String key, File inputFile, File outputFile) throws CryptoException {
        doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
    }

    public static void decrypt(String key, File inputFile, File outputFile) throws CryptoException {
        doCrypto(Cipher.DECRYPT_MODE, key,inputFile, outputFile);
    }

    public static void doCrypto(int cipherMode, String key, File inputFile, File outputFile) throws CryptoException {
        try {
            SecureRandom random = new SecureRandom();
            byte[] salt = new byte[16];
            random.nextBytes(salt);

            KeySpec spec = new PBEKeySpec(key.toCharArray(), salt, 65536, 256);
            SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            byte[] keystore = f.generateSecret(spec).getEncoded();
            Key secretKey = new SecretKeySpec(keystore, ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(cipherMode, secretKey);

            FileInputStream inputStream = new FileInputStream(inputFile);
            byte[] inputBytes = new byte[(int) inputFile.length()];
            inputStream.read(inputBytes);

            byte[] outputBytes = cipher.doFinal(inputBytes);

            FileOutputStream outputStream = new FileOutputStream(outputFile);
            outputStream.write(outputBytes);

            inputStream.close();
            outputStream.close();
        } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | IOException | InvalidKeySpecException ex) {
            throw new CryptoException("Error Encrypting/Decrypting File...", ex);
        }
    }
}
  

Файл CryptoException.java:

 public class CryptoException extends Exception {
    public CryptoException(){}

    public CryptoException(String message, Throwable throwable) {
        super(message, throwable);
    }
}
  

Это и есть тот самый Main.java файл с основным методом:

 public class Main {

    public static void main(String[] args) {
        String key = "Mary has one cat1";
        File inputFile = new File("document.txt");
        File encryptedFile = new File("encryptedDocument.encrypted");
        File decryptedFile = new File("decrypted.decrypted");
        try {
            jCryptFile.encrypt(key, inputFile, encryptedFile);
            jCryptFile.decrypt(key, inputFile, decryptedFile);
        } catch (CryptoException ex) {
            System.out.println(ex.getMessage());
            ex.printStackTrace();
        }
    }
}
  

Когда я запускаю это, это выдает следующую ошибку:

 Error Encrypting/Decrypting File...
com.jcryptfile.CryptoException: Error Encrypting/Decrypting File...
    at com.jcryptfile.jCryptFile.doCrypto(jCryptFile.java:54)
    at com.jcryptfile.jCryptFile.decrypt(jCryptFile.java:26)
    at com.jcryptfile.Main.main(Main.java:14)
Caused by: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
    at java.base/com.sun.crypto.provider.CipherCore.prepareInputBuffer(CipherCore.java:1007)
    at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:850)
    at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)
    at com.jcryptfile.jCryptFile.doCrypto(jCryptFile.java:46)
  

Комментарии:

1. Вы генерируете случайную соль во время дешифрования. Но вы должны использовать соль из шифрования, иначе ключи для шифрования и дешифрования разные.

2. В настоящее время вы используете шифрование в режиме ECB, которое имеет несколько серьезных проблем. Прежде всего, это позволяет изменять зашифрованный и открытый текст без обнаружения. Ваш код не всегда может выдавать исключение с ошибочным заполнением, даже если ключ неверен. И, наконец, режим ECB небезопасен, даже если он есть. Java по умолчанию "AES/ECB/PKCS5Padding" используется по умолчанию.