Encrypt using OpenSSL in the same way Java does
Asked Answered
D

1

6

I have to encrypt an string using bash script in the same way I encrypt using javax.crypto.Cipher. At java I use AES-256 with the key "0123456789". But When I use openssl I had to convert "0123456789" to hex, but the result is not the same of the java

echo "lun01" | openssl aes-256-cbc -e -a -K 7573746f726530313233343536373839 -iv 7573746f726530313233343536373839

dpMyN7L5HI8VZEs1biQJ7g==

Java:

public class CryptUtil {
    public static final String DEFAULT_KEY = "0123456789";

    private static CryptUtil instance;

    private String chiperKey;

    private CryptUtil(String chiperKey) {
        this.chiperKey = chiperKey;
    }

    public static CryptUtil getInstance() {
        if (null == instance) {
            instance = new CryptUtil(DEFAULT_KEY);
        }

        return instance;
    }

    public static CryptUtil getInstance(String cipherkey) {
        instance = new CryptUtil(cipherkey);
        return instance;
    }

    public String aesEncrypt(String plainText) {
            byte[] keyBytes = Arrays.copyOf(this.chiperKey.getBytes("ASCII"), 16);

            SecretKey key = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, key);

            byte[] cleartext = plainText.getBytes("UTF-8");
            byte[] ciphertextBytes = cipher.doFinal(cleartext);
            final char[] encodeHex = Hex.encodeHex(ciphertextBytes);

            return new String(encodeHex);

        return null;
    }

    public static void main(String[] args) {

        CryptUtil cryptUtil = CryptUtil.getInstance();
        System.out.println(cryptUtil.aesEncrypt("lun01"));
    }
}

d230b216e9d65964abd4092f5c455a21

Dog answered 14/8, 2015 at 21:8 Comment(2)
yes, I figure that. But it still not converting correct. I edit the question....Dog
Your hex value 7573746f726530313233343536373839 is the characters ustore0123456789 not 0123456789 plus nulls, and as @Artjom says your Java does AES-128 ECB mode (and PKCS#5 padding which OpenSSL also does). Further, the echo command (in bash a builtin) adds a newline to the data but your Java doesn't, and openssl enc -a encodes the result in base64 not hex. Fixing these: echo -n lun01 |openssl aes-128-ecb -K 30313233343536373839000000000000 |od -tx1 gives 0000000 d2 30 b2 16 e9 d6 59 64 ab d4 09 2f 5c 45 5a 21 matching your Java result.Smolensk
S
6

If the countless online hex converters don't work for you, then you can simply print the key that you use in Java as hex. Here is a popular SO question regarding this feat.

After you've done that, you will see that it still doesn't work, because you're using different algorithms.

When you use Cipher.getInstance("AES"); it will most likely default to "AES/ECB/PKCS5Padding" which is not the same as "aes-256-cbc", because ECB and CBC are two entirely different modes of operation. To prevent this ambiguity always fully qualify your ciphers, e.g.: Cipher.getInstance("AES/CBC/PKCS5Padding");.

Then the key that you generate in Java is only 16 bytes long, so the matching cipher in OpenSSL would be "aes-128-ecb".

As dave_thompson_085 said in a comment:

  • echo adds a newline character which your Java code does not add. You would need to create the plaintext in this way: echo -n "lun01". Or see this if you're on Windows.

  • Your Java code outputs the result as hex, so you need to do the same in OpenSSL. You need to remove the -a option in the OpenSSL command to prevent Base64 encoding and then you can utilize additional commandline tools such as od on linux to convert the binary output data to hex with od -tx1.

  • Full command:

      echo -n lun01 |openssl aes-128-ecb -K 30313233343536373839000000000000 |od -tx1
    

Security Recommendations

Don't use ECB mode! It's not semantically secure. You need to use at least CBC mode with a random IV (check that it's random and not just zero bytes).

Even better would be to add authentication by for example adding an HMAC tag with an encrypt-then-MAC approach or simply using an authenticated mode like GCM.

Additional info

If you're using anything other than ECB, then you cannot encrypt the same thing in both versions and expect that the same ciphertext appears. Since it is randomized, you would need to encrypt in one version and decrypt in the other to ensure compatibility.

Scirrhous answered 14/8, 2015 at 21:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.