Bad Padding Исключение при расшифровке, но все еще работает - PullRequest
0 голосов
/ 27 февраля 2020
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
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;


public class Encryptor{

    private static final int bufferSize= 128;

    /**
     * @param args
     */
    public static void main(String[] args) {

        BufferedInputStream in = null; 
        BufferedOutputStream out = null; 
        SecretKeyFactory kf = null; 
        KeySpec ks = null; 
        byte[] salt = new byte[20]; 
        SecretKey key = null; 
        Cipher cipher = null; 
        SecretKeySpec keyspec = null; 
        int bytesRead = 0; 
        if (args.length != 4) {
            printUsageMessage();
            System.exit(1);
        }
        try {
            in = new BufferedInputStream(new FileInputStream(args[1]));
        } catch (FileNotFoundException e) {
            printErrorMessage("Unable to open input file: " + args[1], null);
            System.exit(1);
        }
        try {
            out = new BufferedOutputStream(new FileOutputStream(args[2]));
        } catch (FileNotFoundException e) {
            printErrorMessage("Unable to open output file: " + args[2], e);
            System.exit(1);
        }
        try {
            kf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        } catch (NoSuchAlgorithmException e2) {
            e2.printStackTrace();
        }
        String password = args[3];

        ks = new PBEKeySpec(password.toCharArray(), salt, 128, 128);
        try {
            key = kf.generateSecret(ks);
        } catch (InvalidKeySpecException e1) {
            e1.printStackTrace();
        }
        byte[] aeskey = key.getEncoded();
        try {

            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        } catch (NoSuchAlgorithmException e) {
            printErrorMessage("No Such Algorithm Exception when creating main cipher", e);
            System.exit(2);
        } catch (NoSuchPaddingException e) {
            printErrorMessage("No Such Padding Exception when creating main cipher", e);
            System.exit(2);
        }
        int cipherMode = -1;
        char mode = Character.toLowerCase(args[0].charAt(0));
        switch (mode) {
        case 'e':
            cipherMode = Cipher.ENCRYPT_MODE;
            break;
        case 'd':
            cipherMode = Cipher.DECRYPT_MODE;
            break;
        default:
            printUsageMessage();
            System.exit(1);
        }
        keyspec = new SecretKeySpec(aeskey, "AES");
        try {
            cipher.init(cipherMode, keyspec);
        } catch (InvalidKeyException e) {
            printErrorMessage("Invalid Key Spec", e);
            System.exit(2);
        }
        byte[] inputBuffer = new byte[bufferSize];
        byte[] outputBuffer = null;
        try {
            bytesRead = in.read(inputBuffer);
        } catch (IOException e) {
            printErrorMessage("Error reading input file " + args[1], e);
            System.exit(1);
        }
        while (bytesRead > 0) {
            outputBuffer = cipher.update(inputBuffer);
            try {
                out.write(outputBuffer);
            } catch (IOException e) {
                printErrorMessage("Error writing to output file " + args[2], e);
                System.exit(1);
            }
            try {
                bytesRead = in.read(inputBuffer);
            } catch (IOException e) {
                printErrorMessage("Error reading input file " + args[1], e);
                System.exit(1);
            }
        }
        try {
            outputBuffer = cipher.doFinal(inputBuffer);
        } catch (IllegalBlockSizeException | BadPaddingException e1) {
            e1.printStackTrace();
        }
        try {
            out.write(outputBuffer);
        } catch (IOException e) {
            printErrorMessage("Error on final write to output file " + args[2], e);
            System.exit(1);
        }
        try {
            in.close();
            out.close();
        } catch (IOException e) {
            printErrorMessage("Error closing file", e);
        }
    }


    private static void printErrorMessage(String errMsg, Exception e) {
        System.err.println(errMsg);
        if (e != null)
            System.err.println(e.getMessage());
    }


    private static void printUsageMessage() {
        System.out.println(progName + " $Revision: 1.1 $: Usage: " + progName + " E/D infile outfile passphrase");
    }

}

Я пытаюсь написать программу, которая шифрует и дешифрует текстовый документ с помощью пароля. Он не генерирует никаких ошибок при шифровании, но он генерирует исключение плохого заполнения при дешифровании, но все равно выводит правильный текст, но с дополнительными данными в конце. Я искал другие ответы, но не могу найти решение. Программа запускается путем компиляции в работающий jar-файл и запускается как java -jar имя файла e / d (шифрование / дешифрование) inputFile.txt пароль outputFile.txt.

Заранее спасибо

РЕДАКТИРОВАТЬ:

Exception:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
        at java.base/com.sun.crypto.provider.CipherCore.unpad(Unknown Source)
        at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(Unknown Source)
        at java.base/com.sun.crypto.provider.CipherCore.doFinal(Unknown Source)
        at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(Unknown Source)
        at java.base/javax.crypto.Cipher.doFinal(Unknown Source)
        at FileEncryptorSkeleton.main(FileEncryptorSkeleton.java:183)

это где я добавляю outputBuffer = cipher.doFinal (inputBuffer);

Пример ввода:

aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz

Пример Вывод:

aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzz

выводит изображение, поскольку недопустимые символы не отображаются в блоке трески

1 Ответ

2 голосов
/ 27 февраля 2020

Вы неоднократно звоните bytesRead = in.read(inputBuffer), затем cipher.update(inputBuffer). Когда достигается конец входного файла, только часть inputBuffer устанавливается на новые данные, а остальная часть остается остатком от предыдущего чтения, но вы используете все это. Затем вы вызываете cipher.doFinal(inputBuffer), который использует другую копию того, что осталось в буфере после последнего чтения.

При шифровании это приводит к шифрованию повторений некоторых данных из последних нескольких строк (до 128 байт). При дешифровании это приводит к вызову doFinal с данными, которые на самом деле не являются последней частью зашифрованного текста, таким образом, исключение «плохое заполнение».

Вместо этого do (обработка ясности по модулю для ясности):

bytesRead = in.read(inputBuffer);
while( bytesRead > 0 ){
    outputBuffer = cipher.update(inputBuffer, 0, readBytes); // only use the part read 
    out.write(outputBuffer);
    bytesRead = in.read(inputBuffer);
}
outputBuffer = cipher.doFinal(); // no data at all here, .update already processed it
out.write(outputBuffer);

PS: ECB, применяемый к общим данным (например, «текстовый документ»), почти всегда небезопасен; гугл есб пингвин. И PBKDF2 только с 128 итерациями не очень хорошо, а с постоянной солью очень плохо. Но это проблемы безопасности и оффтопа c здесь.

...