Search code examples
javaexceptioncryptographyaes

Java AES giving BadPaddingException


I am trying to code a simple encryption and decryption method for my program in Java. It should encrypt and decrypt a string with another string as key.

While testing, a BadPaddingException occured.

My current method to encrypt:

public String encrypt(String strToEncrypt, String secretKey) {
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            byte[] salt = new Hash().hashString(secretKey).getBytes();
            KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            cipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);

            byte[] ciphertext = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
            System.out.println("Finished encryption");
            return new Base64().encodeToString(ciphertext);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

My current method to decrypt:

public String decrypt(String strToDecrypt, String secretKey) {  
        try {
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            byte[] salt = new Hash().hashString(secretKey).getBytes();
            KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
            IvParameterSpec ivspec = new IvParameterSpec(iv);
            cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
            
            byte[] decodedPlaintext = new Base64().decode(strToDecrypt);
            byte[] plaintext = cipher.doFinal(decodedPlaintext);
            System.out.println("Finished decryption");
            return new Base64().encodeToString(plaintext);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

I am getting the followed 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(CipherCore.java:975)
    at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
    at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
    at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2202)

Solution

  • With the kind help of Michael and President James K. Polk I could get the en- and decryption working and improved the generation of the salt. My mistake was, that I wasn't using the same IvParameterSpec for encryption and decryption.

    My encryption method:

    public static String encrypt(String strToEncrypt, String secretKey) {
            try {
                SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
                byte[] salt = new byte[16];
                SecureRandom.getInstanceStrong().nextBytes(salt);
                KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
                SecretKey tmp = factory.generateSecret(spec);
                SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
                IvParameterSpec ivspec = new IvParameterSpec(iv);
                cipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
    
                byte[] ivBytes = ivspec.getIV();
                byte[] ciphertext = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
                System.out.println("Finished encryption");
                byte[] outputBytes = concat(concat(salt, ivBytes), ciphertext);
                return new Base64().encodeToString(outputBytes);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    

    My decryption method:

    public static String decrypt(String strToDecrypt, String secretKey) {
            try {
                byte[] decodedCiphertext = new Base64().decode(strToDecrypt);
                SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
                byte[] salt = Arrays.copyOfRange(decodedCiphertext, 0, 16);
                KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
                SecretKey tmp = factory.generateSecret(spec);
                SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                byte[] iv = Arrays.copyOfRange(decodedCiphertext, 16, 32);
                IvParameterSpec ivspec = new IvParameterSpec(iv);
                cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
    
                
                byte[] plaintext = cipher.doFinal(Arrays.copyOfRange(decodedCiphertext, 32, decodedCiphertext.length));
                System.out.println("Finished decryption");
                return new String(plaintext, "UTF-8");
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }