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)

2 Answers2

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

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

Naor Tedgi
  • 5,204
  • 3
  • 21
  • 48
  • 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)` – Prashant Jeet Singh Jan 13 '19 at 20:22
  • and you run the main with the correct order of arguments first the *.enc file and then the password? – Naor Tedgi Jan 13 '19 at 20:23
  • yes did the same. Even tried storing file path and password in variable but no luck – Prashant Jeet Singh Jan 13 '19 at 20:25
  • did you try pass as first argument the absolute path to the file? – Naor Tedgi Jan 13 '19 at 20:27
  • yes `private static final String file="D:\\Eclipse_Workspace\\Cryptography\\avengers.enc"; private static final String password = "test";` – Prashant Jeet Singh Jan 13 '19 at 20:29
  • please attach your main function to the question – Naor Tedgi Jan 13 '19 at 20:30
  • 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 comment – Naor Tedgi Jan 13 '19 at 20:34
  • I have updated the question with hardcoded parameters. – Prashant Jeet Singh Jan 13 '19 at 20:42
  • which openssl are you using ? (openssl version) – Naor Tedgi Jan 13 '19 at 20:49
  • Open SSL version in ubuntu : OpenSSL 1.1.0g – Prashant Jeet Singh Jan 13 '19 at 20:52
  • my avengers.enc file content is `U2FsdGVkX194TyUFrb4gOn86XYaKjKP98YdOlQDJz+t/76mvVmNKl+NyKKUnYwYH` – Prashant Jeet Singh Jan 13 '19 at 21:06
  • 2
    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. – Maarten Bodewes Jan 13 '19 at 21:07
  • @NaorTedgi Thanks for the help – Prashant Jeet Singh Jan 13 '19 at 21:21
  • 3
    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](https://www.linuxquestions.org/questions/linux-newbie-8/new-openssl-1-1-0-broken-compatibility-with-openssl-1-0-1-a-4175632653/). – Maarten Bodewes Jan 13 '19 at 21:22
  • 1
    i think it will be great if @PrashantJeetSingh you will answer the question and explain what was the problem and how you solve it – Naor Tedgi Jan 13 '19 at 21:27