Search code examples
javaencryptioncryptographyaesbadpaddingexception

AES Encryption/Decryption : Given final block not properly padded


I am trying to write methods to encrypt or decrypt String (which mostly will be numeric). It works fine for some texts(e.g.- '1010000011','1010000012', '1010000013') but gives following error for others(e.g.- '1010000014', '1010000018'):

javax.crypto.BadPaddingException: Given final block not properly padded

Here goes my code:

public static SecretKey secKey;
private static IvParameterSpec ivspec;
static {
    try {
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec("i15646dont6321wanna".toCharArray(),
                "ahhalkdjfslk3205jlk3m4ljdfa85l".getBytes("UTF-8"), 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        secKey = new SecretKeySpec(tmp.getEncoded(), "AES");
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        ivspec = new IvParameterSpec(iv);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException | UnsupportedEncodingException e) {
        e.printStackTrace();
    }
}

public static String encryptData(String textToEncrypt) {

    byte[] encryptedBytes = null;
    String encryptedText = "";
    try {
        byte[] byteToEncrypt = textToEncrypt.getBytes(Charset.defaultCharset());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secKey, ivspec);
        encryptedBytes = cipher.doFinal(byteToEncrypt);
        encryptedText = new String(encryptedBytes);
    } catch (NoSuchAlgorithmException | IllegalBlockSizeException | BadPaddingException
            | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return encryptedText;
}

public static String decryptData(String textToDecrypt) {

    byte[] decryptedBytes = null;
    String decryptedText = "";
    try {
        byte[] byteToDecrypt = textToDecrypt.getBytes(Charset.defaultCharset());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secKey, ivspec);
        decryptedBytes = cipher.doFinal(byteToDecrypt);
        decryptedText = new String(decryptedBytes);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
            | IllegalBlockSizeException | BadPaddingException
            | InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return decryptedText;
}

The String to be encrypted is read from file and be written to some other file after encryption. This encrypted text will have to be decrypted back later. I am calling these methods in following manner:

String[] lineArray = line.split(" | "); //line is read from a file. 
String encryptedText = AESEncryption.encryptData(lineArray[0]);
String decryptedText = AESEncryption.decryptData(encryptedText);
System.out.println("Original Text: " + lineArray[0] + " | Encrypted text: "
                + encryptedText + " | Decrypted again: " + decryptedText);

Solution

  • You are trying to pass the encrypted data as a string. This is fatal. Encrypted data is bytes, not a string. Use the Base64 conversion utilities to convert the encrypted bytes to a Base64 string.

    Encryption: plaintext -> encrypted bytes -> Base64 text.

    Decryption: Base64 text -> encrypted bytes -> decrypted text.