3

I'm using Java 8 and I'm attempting to emulate the following openssl calls with Java.

Encrypt:

echo -n 'hello world' | openssl enc -a -aes-256-cbc -md sha256 -pass pass:97DE:4F76

U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=

Decrypt:

echo U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc= | openssl enc -d -a -aes-256-cbc -md sha256 -pass pass:97DE:4F76

hello world

Questions:

  1. My implementation doesn't work. I've visited many other StackOverflow answers but wasn't able to figure out the right implementation. Can anyone point me out in the right direction for solving this?
  2. The openssl system call in the example above uses digest sha256. If I were to use sha1, instead in the Java implemementation, would it be just a matter of changing PBKDF2WithHmacSHA256 with PBKDF2WithHmacSHA1?

Test.java

package test;

import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

public class Test {

    public static final String PASSWORD = "97DE:4F76";

    public static String encryptString(String clearText, String password) {
        return "";
    }

    // echo U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc= | openssl enc -d -a -aes-256-cbc -md sha256 -pass pass:97DE:4F76
    //
    // see https://stackoverflow.com/a/992413, https://stackoverflow.com/a/15595200,
    // https://stackoverflow.com/a/22445878, https://stackoverflow.com/a/11786924
    public static String decryptString(String cypherText, String password) {
        byte[] dataBase64 = DatatypeConverter.parseBase64Binary(cypherText);
        byte[] salt = {
                (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
                (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0
        };

        try {
            // generate the key
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); // "PBKDF2WithHmacSHA1"
            KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
            SecretKey tmp = factory.generateSecret(spec);
            SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

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

            byte[] decrypted = cipher.doFinal(dataBase64);
            String answer = new String(decrypted, "UTF-8");
            return answer;

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }

    public static void main(String[] args) {
        System.out.println(decryptString("U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=", PASSWORD));
    }
}

this is the current output of running the code above:

java.security.InvalidKeyException: Illegal key size     at
         javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)  at
         javax.crypto.Cipher.init(Cipher.java:1393)     at
         javax.crypto.Cipher.init(Cipher.java:1327)     at
         test.Test.decryptString(Test.java:42)  at
         test.Test.main(Test.java:55)

Update: this is the code I ended up implementing after I used this answer: https://stackoverflow.com/a/11786924 -> has the rest of the constants and implementation of EVP_BytesToKey

public static String decryptString(String cypherText, String password) {
        try {
            // decode the base64 cypherText into salt and encryptedString
            byte[] dataBase64 = DatatypeConverter.parseBase64Binary(cypherText);
            byte[] salt = Arrays.copyOfRange(dataBase64, SALT_OFFSET, SALT_OFFSET + SALT_SIZE);
            byte[] encrypted = Arrays.copyOfRange(dataBase64, CIPHERTEXT_OFFSET, dataBase64.length);
            System.out.println("dataBase64 = " + new String(dataBase64));
            System.out.println("salt: " + new BigInteger(1, salt).toString(16));
            System.out.println("encrypted: " + new BigInteger(1, encrypted).toString(16));    

            // --- specify cipher and digest for EVP_BytesToKey method ---
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            MessageDigest sha1 = MessageDigest.getInstance("SHA-256");

            // create key and IV
            final byte[][] keyAndIV = EVP_BytesToKey(
                    KEY_SIZE_BITS / Byte.SIZE,
                    cipher.getBlockSize(),
                    sha1,
                    salt,
                    password.getBytes("ASCII"),
                    ITERATIONS);
            SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
            IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);

            // initialize the Encryption Mode
            cipher.init(Cipher.DECRYPT_MODE, key, iv);

            // decrypt the message
            byte[] decrypted = cipher.doFinal(encrypted);
            String answer = new String(decrypted, "UTF-8"); // should this be "ASCII"?
            return answer;

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return "";
    }
Community
  • 1
  • 1
Unglued
  • 419
  • 6
  • 15
  • 3
    256 bit AES is restricted in Java for some legal reasons. You need to explicitly enable strong encryption in your JDK. Search for "Unlimited Strength Jurisdiction Policy" – Thilo Dec 29 '15 at 00:23
  • your 2) probably. Try it. – zapl Dec 29 '15 at 00:33
  • @Thilo, earlier I've downloaded JCE and placed it into the java folder with the other jars. However, I've just realized that I have multiple versions of java installed and I've placed those jars in the wrong folder version. Tomorrow morning when I'm back at work I will try again with the right version of java. – Unglued Dec 29 '15 at 01:03
  • 2
    I've marked this as a duplicate, since the other answer solved my problem! @Thilo, you were right about the JCE. Also, implementing the algorithm from the other answer for EVP_BytesToKey worked like a charm! – Unglued Dec 29 '15 at 21:18
  • [OpenSSL 1.1.0c changed the digest algorithm](http://stackoverflow.com/q/39637388/608639) used in some internal components. Formerly, MD5 was used, and 1.1.0 switched to SHA256. Be careful the change is not affecting you in both `EVP_BytesToKey` and commands like `openssl enc`. – jww Jan 26 '17 at 16:22

0 Answers0