简体   繁体   中英

File Encryption with the Java Cryptography Architecture using AES with a 128-bit key and PBKDF2

I am getting this error when I am decrypting a file

I am using PBKDF2 to convert a passphrase to a key and then using it. The encryption is working good but when I am trying to decrypt the same file it is giving the below error. The decrypted file gives a correct data except for the last few lines(probably the padding area). I have debugged it by outputting the IV and key while encrypting and decrypting and they both are the same but the error still exists.

public class FileEncryptorSkeleton{

    private static final String progName = "FileEncryptor";
    private static final int bufSize = 128;

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

        BufferedInputStream in = null;          // A buffered input stream to read from
        BufferedOutputStream out = null;        // And a buffered output stream to write to
        SecretKeyFactory kf = null;             // Something to create a key for us
        KeySpec ks = null;                      // This is how we specify what kind of key we want it to generate
        byte[] salt = new byte[20];             // Some salt for use with PBKDF2, only not very salty
        SecretKey key = null;                   // The key that it generates
        Cipher cipher = null;                   // The cipher that will do the real work
        SecretKeySpec keyspec = null;           // How we pass the key to the Cipher
        int bytesRead = 0;                      // Number of bytes read into the input file buffer
        byte[] iv = new byte[16];
        // First, check the user has provided all the required arguments, and if they haven't, tell them then exit
        if(args.length != 4) {
            printUsageMessage(); System.exit(1);
        }

        // Open the input file
        try {
            in = new BufferedInputStream(new FileInputStream(args[1]));
        } catch (FileNotFoundException e) {
            printErrorMessage("Unable to open input file: " + args[1], null);
            System.exit(1);
        }

        // And then the output file
        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 ex) {
                Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
            }

        // Set up a KeySpec for password-based key generation of a 128-bit key
            ks = new PBEKeySpec(args[3].toCharArray(), salt, 1000, 128);




        // Now run the passphrase through PBKDF2 to get the key
            try {
                    key = kf.generateSecret(ks);
                    }catch(InvalidKeySpecException e){
        System.exit(1);
                    }

        // Get the byte encoded key value as a byte array
        byte[] aeskey = key.getEncoded();

        // Now generate a Cipher object for AES encryption in ECBC mode with PKCS #5 padding
        // Use ECB for the first task, then switch to CBC for versions 2 and 3
        try {
            cipher = Cipher.getInstance("AES/CBC/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);
        }

        // Set a variable to indicate whether we're in encrypt or decrypt mode, based upon args[0]
        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);
        }

        // Set up a secret key specification, based on the 16-byte (128-bit) AES key array previously generated
        keyspec = new SecretKeySpec(aeskey, "AES");
        IvParameterSpec ivspec = new IvParameterSpec(iv);
        // Now initialize the cipher in the right mode, with the keyspec and the ivspec
        try {

            cipher.init(cipherMode, keyspec,ivspec);

        } catch (InvalidKeyException e) {
            printErrorMessage("Invalid Key Spec",e); System.exit(2);
        } catch (InvalidAlgorithmParameterException ex) {
                Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
            }

        // Set up some input and output byte array buffers
        byte[] inputBuffer = new byte[bufSize];
        byte[] outputBuffer = null;

        // "Prime the pump" - we've got to read something before we can encrypt it
        // and not encrypt anything if we read nothing.
        try {
            bytesRead = in.read(inputBuffer);
        } catch (IOException e) {
            printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
        }

        // As long as we've read something, loop around encrypting, writing and reading
        // bytesRead will be zero if nothing was read, or -1 on EOF - treat them both the same
        while (bytesRead > 0) {

            // Now encrypt this block
            outputBuffer = cipher.update(inputBuffer.toString().getBytes("UTF-8"));         
            // Write the generated block to file
            try {
                out.write(outputBuffer);
            } catch (IOException e) {
                printErrorMessage("Error writing to output file " + args[2],e); System.exit(1);
            }

            // And read in the next block of the file
            try {
                bytesRead = in.read(inputBuffer);
            } catch (IOException e) {
                printErrorMessage("Error reading input file " + args[1],e); System.exit(1);
            }
        }

            try {
                // Now do the final processing
                outputBuffer =cipher.doFinal(inputBuffer.toString().getBytes("UTF-8"));
                cipher.init(cipherMode, keyspec,ivspec);
                System.out.println(ivspec+"   "+cipherMode+"   "+keyspec);
            } catch (IllegalBlockSizeException ex) {
                Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
            } catch (BadPaddingException ex) {
                Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvalidKeyException ex) {
                Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvalidAlgorithmParameterException ex) {
                Logger.getLogger(FileEncryptorSkeleton.class.getName()).log(Level.SEVERE, null, ex);
            }

        // Write the final block of output
        try {
            out.write(outputBuffer);
        } catch (IOException e) {
            printErrorMessage("Error on final write to output file " + args[2],e); System.exit(1);
        }

        // Close the output files
        try {
            in.close();
            out.close();
        } catch (IOException e) {
            printErrorMessage("Error closing file", e);
        }

        // If we were continuing beyond this point, we should really overwrite key material, drop KeySpecs, etc.
    }

    /**
        * Print an error message on , optionally picking up additional detail from
        * a passed exception
        * @param errMsg
        * @param e
        */
    private static void printErrorMessage(String errMsg, Exception e) {
        System.err.println(errMsg);
        if (e != null) 
            System.err.println(e.getMessage());
    }

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

}

 Oct 18, 2019 11:27:46 PM FileEncryptorSkeleton main SEVERE: null javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption. at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975) at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056) at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853) at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446) at javax.crypto.Cipher.doFinal(Cipher.java:2164) at FileEncryptorSkeleton.main(FileEncryptorSkeleton.java:174)

Both the Cipher#update - and Cipher#doFinal -method use inputBuffer.toString() , which only contains the name of the object's class and the hashcode and not the actual data in the buffer.

It would be correct to read the first bytesRead bytes from the inputBuffer-byte[] (which were previously read from the in-BufferedInputStream ) and process them ( Cipher#update ):

outputBuffer = cipher.update(inputBuffer, 0, bytesRead); 

The loop containing the cipher#update -call is only left when no byte has been read to the inputBuffer-byte[] , so that for the final processing applies ( Cipher#doFinal ):

outputBuffer = cipher.doFinal();

In addition, the second cipher#init -call immediately after the cipher#doFinal -call is unnecessary ( Cipher#init ).

I am getting an error like "SEVERE cannot be resolved or is not a field" Can anyone suggest me the right import to resolve this issue?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM