BadPadding exception when trying to decrypt AES based encrypted text
Asked Answered
P

2

4

Problem Scenario: I am creating an encrypted file using OpenSSL AES-256-CBC mode in Ubuntu.

openssl aes-256-cbc -a -in avengers.txt -out avengers.enc 
test
test
File Content: avengersAssemble
avengers.enc file content: U2FsdGVkX194TyUFrb4gOn86XYaKjKP98YdOlQDJz+t/76mvVmNKl+NyKKUnYwYH

To Decrypt: openssl aes-256-cbc -a -d -in avengers.enc

Now I want to decrypt this encrypted file avengers.enc using java code i.e., I just store this file content and password (in this case test) to decrypt it.

My Aim: I want to decrypt using a password (symmetric encryption), encrypted from above command (128 or 192 or 256 cbc).

Please help.

I found this code but its showing BadPadding exception. Please refer answer post by @Maarten Bodewes in the link.

Code which I found from the link:

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.List;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.bouncycastle.util.encoders.Base64;

public class OpenSSLDecryptor {
    private static final Charset ASCII = Charset.forName("ASCII");
    private static final int INDEX_KEY = 0;
    private static final int INDEX_IV = 1;
    private static final int ITERATIONS = 1;

    private static final int ARG_INDEX_FILENAME = 0;
    private static final int ARG_INDEX_PASSWORD = 1;

    private static final String file = 
    "D:\\Eclipse_Workspace\\Cryptography\\avengers.enc";
     private static final String password = "test";

    private static final int SALT_OFFSET = 8;
    private static final int SALT_SIZE = 8;
    private static final int CIPHERTEXT_OFFSET = SALT_OFFSET + SALT_SIZE;

    private static final int KEY_SIZE_BITS = 256;

    /**
     * Thanks go to Ola Bini for releasing this source on his blog.
     * The source was obtained from <a href="http://olabini.com/blog/tag/evp_bytestokey/">here</a> .
     */
    public static byte[][] EVP_BytesToKey(int key_len, int iv_len, MessageDigest md,
            byte[] salt, byte[] data, int count) {
        byte[][] both = new byte[2][];
        byte[] key = new byte[key_len];
        int key_ix = 0;
        byte[] iv = new byte[iv_len];
        int iv_ix = 0;
        both[0] = key;
        both[1] = iv;
        byte[] md_buf = null;
        int nkey = key_len;
        int niv = iv_len;
        int i = 0;
        if (data == null) {
            return both;
        }
        int addmd = 0;
        for (;;) {
            md.reset();
            if (addmd++ > 0) {
                md.update(md_buf);
            }
            md.update(data);
            if (null != salt) {
                md.update(salt, 0, 8);
            }
            md_buf = md.digest();
            for (i = 1; i < count; i++) {
                md.reset();
                md.update(md_buf);
                md_buf = md.digest();
            }
            i = 0;
            if (nkey > 0) {
                for (;;) {
                    if (nkey == 0)
                        break;
                    if (i == md_buf.length)
                        break;
                    key[key_ix++] = md_buf[i];
                    nkey--;
                    i++;
                }
            }
            if (niv > 0 && i != md_buf.length) {
                for (;;) {
                    if (niv == 0)
                        break;
                    if (i == md_buf.length)
                        break;
                    iv[iv_ix++] = md_buf[i];
                    niv--;
                    i++;
                }
            }
            if (nkey == 0 && niv == 0) {
                break;
            }
        }
        for (i = 0; i < md_buf.length; i++) {
            md_buf[i] = 0;
        }
        return both;
    }


    public static void main(String[] args) {
        try {
            // --- read base 64 encoded file ---

            //File f = new File(args[ARG_INDEX_FILENAME]);
            File f = new File(file);
            List<String> lines = Files.readAllLines(f.toPath(), ASCII);
            StringBuilder sb = new StringBuilder();
            for (String line : lines) {
                sb.append(line.trim());
            }
            String dataBase64 = sb.toString();
            byte[] headerSaltAndCipherText = Base64.decode(dataBase64);

            // --- extract salt & encrypted ---

            // header is "Salted__", ASCII encoded, if salt is being used (the default)
            byte[] salt = Arrays.copyOfRange(
                    headerSaltAndCipherText, SALT_OFFSET, SALT_OFFSET + SALT_SIZE);
            byte[] encrypted = Arrays.copyOfRange(
                    headerSaltAndCipherText, CIPHERTEXT_OFFSET, headerSaltAndCipherText.length);

            // --- specify cipher and digest for EVP_BytesToKey method ---

            Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
            MessageDigest md5 = MessageDigest.getInstance("MD5");

            // --- create key and IV  ---

            // the IV is useless, OpenSSL might as well have use zero's
            final byte[][] keyAndIV = EVP_BytesToKey(
                    KEY_SIZE_BITS / Byte.SIZE,
                    aesCBC.getBlockSize(),
                    md5,
                    salt,
                    password.getBytes(ASCII),
                    ITERATIONS); //args[ARG_INDEX_PASSWORD]
            SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
            IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);

            // --- initialize cipher instance and decrypt ---

            aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] decrypted = aesCBC.doFinal(encrypted);

            String answer = new String(decrypted, ASCII);
            System.out.println(answer);
        } catch (BadPaddingException e) {
            // AKA "something went wrong"
            throw new IllegalStateException(
                    "Bad password, algorithm, mode or padding;" +
                    " no salt, wrong number of iterations or corrupted ciphertext.");
        } catch (IllegalBlockSizeException e) {
            throw new IllegalStateException(
                    "Bad algorithm, mode or corrupted (resized) ciphertext.");
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException(e);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }        
}

Exception:

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.doFinal(CipherCore.java:991)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at symmetric.main(symmetric.java:146)
Puck answered 13/1, 2019 at 18:35 Comment(2)
Prashant, could you try and replace the "MD5" string with "SHA-256" in the Java code and see if that works as well? I don't have 1.1 installed at the moment. It works perfectly if I use -md sha256 in the command line of 1.0.Flavourful
it workes with SHA-256Puck
P
3

OpenSSL uses EVP_BytesToKey with uses Message Digest Algorithms like md5, sha256, etc. In the above code the function, EVP_ByteToKey has a MessageDigest parameter to which MD5 is passed but MD5 was not added in the OpenSSL command while encryption. So below is the actual command to be used with the message digest algorithm i.e., MD5.

openssl aes-256-cbc -a -in avengers.txt -out avengers.enc -md md5
 openssl aes-256-cbc -a -d -in avengers.enc -md md5 

To use any other message digest algorithm just pass that algoriyhm in MessageDigest md5 = MessageDigest.getInstance("SHA-256"); Refer link under MessageDigest Algoritms. Also, have to pass -md sha256 in command. Refer man page for openSSL

Puck answered 13/1, 2019 at 21:46 Comment(4)
Cool, I'll note this in my other answer as well. If you could try it without -md5 and with "SHA-256" you would safe me quite a lot of time :) Note that you can accept your own answer after a day or two. I'll refer to this answer from my other post.Flavourful
Great, better to use SHA-256 if you don't need MD5 for backward compatibility. Note that MD5 has not yet been broken for this kind of functionality (key derivation).Flavourful
Sure. Thanks for help and suggestion @MaartenBodewesPuck
great job @PrashantJeetSinghGebhart
G
0

openssl version

 LibreSSL 2.6.5

use your example with this jar file

http://www.java2s.com/Code/Jar/b/Downloadbouncycastlejar.htm

exactly the same code except for this import

import bwmorg.bouncycastle.util.encoders.Base64;

decrypt the same data with the same key

and it works perfectly

maybe its parameters issue

Gebhart answered 13/1, 2019 at 19:50 Comment(15)
I tried above jar but no luck still getting same exception 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.doFinal(CipherCore.java:991) at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847) at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446) at javax.crypto.Cipher.doFinal(Cipher.java:2164) at symmetric.main(symmetric.java:150)Puck
and you run the main with the correct order of arguments first the *.enc file and then the password?Gebhart
yes did the same. Even tried storing file path and password in variable but no luckPuck
did you try pass as first argument the absolute path to the file?Gebhart
yes private static final String file="D:\\Eclipse_Workspace\\Cryptography\\avengers.enc"; private static final String password = "test";Puck
please attach your main function to the questionGebhart
in the code you provide the argument gets from the main args here you posted hardcoded variables I want to see the code with the variables you mention here in the previous commentGebhart
I have updated the question with hardcoded parameters.Puck
which openssl are you using ? (openssl version)Gebhart
Open SSL version in ubuntu : OpenSSL 1.1.0gPuck
my avengers.enc file content is U2FsdGVkX194TyUFrb4gOn86XYaKjKP98YdOlQDJz+t/76mvVmNKl+NyKKUnYwYHPuck
Could you try to add -md md5 to your command line interface? It states the hash function used for EVP_BytesToKey if I'm not mistaken.Flavourful
@NaorTedgi Thanks for the helpPuck
Thank you guys as well, I'll add a warning to the other post. Of course, MD5 has been deprecated for a reason, I will try and see if I can make it work with SHA256 as well, which replaced MD5 as default if I'm not mistaken. I'll first have to install a 1.1 version though. This is a change from 1.0 to 1.1 that I found on the internet.Flavourful
i think it will be great if @PrashantJeetSingh you will answer the question and explain what was the problem and how you solve itGebhart

© 2022 - 2024 — McMap. All rights reserved.