2

I am modifying a Java program for decrypting a password encrypted by OpenSSL. Now I am getting the below exception

Exception in thread "main" 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:2222)
    at test.TestAesDecrypt.main(TestAesDecrypt.java:107)

On going through various links, understood it was due to difference in key generated. The key and iv used in OpenSSL and program is different. These are generated internally by OpenSSL and program.

If I hardcoded the OpenSSL key and iv to program, decryption works.

The password to encrypt is helloworld!

Passkey is TIKpasskey001002 . Original Program is from here.

How can I resolve the same?

C:\WINDOWS\system32>C:\OpenSSL-Win64\bin\openssl.exe aes-256-cbc -salt -in D:\Misc\tryouts\encryption3\password.txt -out D:\Misc\tryouts\encryption3\enpassfile.encr -pass file:D:\Misc\tryouts\encryption3\passkeyfile.txt -p
salt=E68886B9E9C2ACD8
key=5F9A0BAF409AF8F9B9FECA9008508A91CEEE86B3A334EC6E00D08A7A8B8372C5
iv =FF3EC566671077A5CC7F0695F8CC590B

C:\WINDOWS\system32>C:\OpenSSL-Win64\bin\openssl.exe aes-256-cbc -d -salt -in D:\Misc\tryouts\encryption3\enpassfile.encr -out D:\Misc\tryouts\encryption3\decpassfile.dcr -pass file:D:\Misc\tryouts\encryption3\passkeyfile.txt -p
salt=E68886B9E9C2ACD8
key=5F9A0BAF409AF8F9B9FECA9008508A91CEEE86B3A334EC6E00D08A7A8B8372C5
iv =FF3EC566671077A5CC7F0695F8CC590B

Values from Java Program:
Values from Java Program:
Encrypted cipher: 53616C7465645F5FE68886B9E9C2ACD84CB17D3CA8FEFC54E189766B97E815BD
Encrypted cipher via Apache Commons Hex: 53616c7465645f5fe68886b9e9c2acd84cb17d3ca8fefc54e189766b97e815bd
Pass Key: 54494B706173736B6579303031303032
Pass Key: TIKpasskey001002

keyValue: 6F16A5F5DA36A6A479CEBFAB6A8258D490A0A3994D204AC1AFD338AF7B4D4306
keyValue via Apache Commons Hex: 6f16a5f5da36a6a479cebfab6a8258d490a0a3994d204ac1afd338af7b4d4306
IV: E19C6128D0851D09F7E01F34061C88E3
IV via Apache Commons Hex: e19c6128d0851d09f7e01f34061c88e3

The program is

import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;

public class TestAesDecrypt {

    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    public static byte[] getBytes(String inputFile) {

        String outputFile = inputFile;
        File infile = new File(outputFile);

        byte[] readBytes = null;
        try {

            readBytes = IOUtils.toByteArray(new FileInputStream(infile));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return readBytes;
    }

    public static void main(final String[] args) throws Exception {

        final byte[] pass = getBytes("D:\\\\Misc\\\\tryouts\\\\encryption3\\\\passkeyfile.txt");
        final byte[] magic = "Salted__".getBytes(StandardCharsets.US_ASCII);
        final String inFile = "D:\\Misc\\tryouts\\encryption3\\enpassfile.encr";

        final byte[] inBytes = Files.readAllBytes(Paths.get(inFile));// decoder.decode(source);

        System.out.println("Encrypted cipher: " + bytesToHex(inBytes));
        System.out.println("Encrypted cipher via Apache Commons Hex: " + Hex.encodeHexString(inBytes));

        System.out.println("Pass Key: " + bytesToHex(pass));
        System.out.println("Pass Key: " + new String(pass));

        final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0, magic.length);
        if (!Arrays.equals(shouldBeMagic, magic)) {
            System.out.println("Bad magic number");
            return;
        }

        final byte[] salt = Arrays.copyOfRange(inBytes, magic.length, magic.length + 8);

        final byte[] passAndSalt = concat(pass, salt);

        byte[] hash = new byte[0];
        byte[] keyAndIv = new byte[0];
        for (int i = 0; i < 3; i++) {
            final byte[] data = concat(hash, passAndSalt);
            final MessageDigest md = MessageDigest.getInstance("MD5");
            hash = md.digest(data);
            keyAndIv = concat(keyAndIv, hash);
        }

        final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
        final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);

        /*
         * Key and IV from OpenSSL command -p 
         * final byte[] keyValue =
         * javax.xml.bind.DatatypeConverter.parseHexBinary(
         * "5F9A0BAF409AF8F9B9FECA9008508A91CEEE86B3A334EC6E00D08A7A8B8372C5"); final
         * byte[] iv = javax.xml.bind.DatatypeConverter.parseHexBinary(
         * "FF3EC566671077A5CC7F0695F8CC590B");
         */

        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");

        System.out.println("IV: " + bytesToHex(iv));
        System.out.println("IV via Apache Commons Hex: " + Hex.encodeHexString(iv));

        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
        /**** EXCEPTION OCCURS HERE START *****/
        final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
        /**** EXCEPTION OCCURS HERE STOP *****/
        final String clearText = new String(clear, StandardCharsets.ISO_8859_1);
        System.out.println(clearText);
    }

    private static byte[] concat(final byte[] a, final byte[] b) {
        final byte[] c = new byte[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
mehere
  • 1,487
  • 5
  • 28
  • 50
  • You had better spend one day to learn some basic cryptography knowledge first ( what is padding? what is cbc mode? what is IV? what is blocksize?). Then your problem can be easily resolved. – shawn Sep 30 '18 at 08:57
  • 1
    FYI, your `pass` variable has two bytes representing newline at the end, which you probably did not intend. My recommendation is to single out the code to reproduce the outcome of [`EVP_BytesToKey()`](https://www.openssl.org/docs/man1.0.2/crypto/EVP_BytesToKey.html) in java -- that seems to be the hardest part of your problem. – Reinier Torenbeek Sep 30 '18 at 15:50
  • I removed the newline. The issue still exists. – mehere Sep 30 '18 at 16:10
  • https://security.stackexchange.com/questions/29106/openssl-recover-key-and-iv-by-passphrase there is a Python demo to generate key & IV – shawn Sep 30 '18 at 16:32
  • https://stackoverflow.com/questions/26144068/decrypting-salted-aes-file-generated-on-command-line-with-ruby and the Ruby one – shawn Sep 30 '18 at 16:33

1 Answers1

2

In addition to removing the CRLF from the password value as per comment by reinier:

You are apparently using OpenSSL 1.1.0 or higher, which changed the hash used by default in enc PBKDF/PBE from MD5 to SHA256. See man enc (may require a special section like 1ssl) on a Unixy system which yours apparently isn't or on the web under HISTORY, and maybe Password to key function compatible with OpenSSL commands? . Note with SHA256 you need only 2 chunks not 4 in the PBKDF.

FYI you don't need to copy the array slices; both SecretKeySpec and IvParameterSpec have constructor overloads that use a slice of the byte array rather than the whole array. And AES-256 key is 32 bytes (at least in Java), which is what you coded even though you commented differently.

dave_thompson_085
  • 34,712
  • 6
  • 50
  • 70