0
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");
    }

}

I am trying to write a program that encrypts and decrypts a text document using a password. It doesnt throw any errors on encrypt, but it does throw a bad padding exception on decrypt, but it still outputs the correct text but with extra stuff on the end. I have searched other answers but cannot find a solution. The program is run by compiling into runnable jar and running it like java -jar filename e/d (encrypt/decrypt) inputFile.txt outputFile.txt password.

Thanks in Advance

EDIT:

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)

this is where I add outputBuffer = cipher.doFinal(inputBuffer);

Sample Input:

aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz
aaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazzzzaaaazz

Sample Output:

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

output picture as invalid characters didnt show up in cod block

  • Please provide the exact place where you are seeing the error and also attached sample inputs that you are provided. I believe you must be seeing an exception, provide stack trace for it. – vavasthi Feb 27 '20 at 04:50
  • You may want to have a look at [this Q/A about handling exceptions](https://stackoverflow.com/a/15712409/589259) – Maarten Bodewes Feb 27 '20 at 11:59
  • Please don't vandalise your post. – Adriaan Apr 22 '20 at 07:36

1 Answers1

2

You repeatedly call bytesRead = in.read(inputBuffer) then cipher.update(inputBuffer). When the end of the input file is reached, only part of inputBuffer is set to new data and the rest is leftover residue from the previous read, but you use all of it. Then you call cipher.doFinal(inputBuffer) which uses another copy of whatever is left in the buffer after the last read.

On encryption, this results in encrypting repetitions of some data from the last few lines (up to 128 bytes). On decryption, this results in calling doFinal with data that is not actually the last part of the ciphertext, thus the 'bad padding' exception.

Instead do (modulo error handling for clarity):

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 applied to general data (like a 'text document') is almost always insecure; google ECB penguin. And PBKDF2 with only 128 iterations is not very good, and with constant salt is very bad. But those are security issues and offtopic here.

dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70
  • 1
    Absolute Legend! Im only using ECB because the assignment requires us to create separate methods using ECB, CBC with default IV and then with random IV. –  Feb 27 '20 at 09:45