Hello.

I'm working on a project that requires some data to be encrypted with AES 128. My encryption works fine but when I decrypt I get an Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length not multiple of 16 bytes exception.

Code:

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AESCipher {
    private final String INCORRECT_PASSWORD_LENGTH = "The password provided must be a length of " + 
                                                     "16 bytes.";
    private String password;
    private SecretKeySpec key;
    private Cipher cipher;

    /**
     * Generate the key from the password.
     */
    private void generateKey() throws Exception {
        key = new SecretKeySpec(this.password.getBytes(), "AES");
        cipher = Cipher.getInstance("AES/CBC/NoPadding");
    } 

    /**
     * Encrypt the data.
     * @param plainText
     *   The data to encrypt.
     * @return
     *   Encrypted data.
     * @throws Exception
     *   Exception if something went wrong.
     */
    public String encrypt(String plainText) throws Exception {
        byte[] cipherText;
        int cipherTextLength;

        cipher.init(Cipher.ENCRYPT_MODE, key);
        cipherText = new byte[cipher.getOutputSize(plainText.getBytes().length)];
        cipherTextLength = cipher.update(plainText.getBytes(), 0, plainText.getBytes().length, 
                                         cipherText, 0);
        cipherTextLength += cipher.doFinal(cipherText, cipherTextLength);
        System.out.println(new String(cipherText));

        return new String(cipherText);
    }

    /**
     * Decrypts the data.
     * @param cipherText
     *   The data to decrypt.
     * @return
     *   Decrypted data.
     * @throws Exception
     *   Exception if something went wrong.
     */
    public String decrypt(String cipherText) throws Exception {
        byte[] plainText;
        int plainTextLength;

        cipher.init(Cipher.DECRYPT_MODE, key);
        plainText = new byte[cipher.getOutputSize(cipherText.getBytes().length)];
        plainTextLength = cipher.update(cipherText.getBytes(), 0, cipherText.getBytes().length, 
                                        plainText, 0);
        plainTextLength += cipher.doFinal(plainText, plainTextLength);

        System.out.println(new String(plainText));

        return new String(plainText);
    }

    /**
     * Class initializer for AES encryption. 
     * @param password 
     *   The password that will be used to encrypt the data.
     * @throws EncryptionException
     *   If something went wrong during initialization, encryption and/or decryption.
     */
    public AESCipher(String password) throws EncryptionException {
        if(password.length() != 16) {
            throw new EncryptionException(INCORRECT_PASSWORD_LENGTH);
        }

        this.password = password;
        try {
            generateKey();
        } catch(Exception error) {
            throw new EncryptionException(error.getMessage());
        }
    }
}

Main method code:

public static void main(String[] args) throws Exception {
        AESCipher aes = new AESCipher("abcdfjlwrd1esfjl");
        String str = aes.encrypt("hello");
        aes.decrypt(str);
    }  

What is wrong and how do I fix it.

The output of the encrypt is a byte array that can contain any sequence of byte values, yet you try to convert that into a UniCode String using your system's default charset and back again and hope that will give the same byte array. Unless you are very lucky, it won't.
If you simplify your code to return the byte array from the encrypt, and pass that as input to the decrypt, you should be able to get that working. Then you could re-consider why you are trying to convert the byte array to String, and what alternatives there are (eg 2-chars-per-byte hex text)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.