Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encrypt using OpenSSL in the same way Java does

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

like image 723
Felipe Gutierrez Avatar asked Aug 14 '15 21:08

Felipe Gutierrez


People also ask

How does OpenSSL encryption work?

Command line OpenSSL uses a rather simplistic method for computing the cryptographic key from a password, which we will need to mimic using the C++ API. OpenSSL uses a hash of the password and a random 64bit salt. Only a single iteration is performed.

How does OpenSSL generate the salt and the IV?

OpenSSL uses a salted key derivation algorithm. The salt is a piece of random bytes generated when encrypting, stored in the file header; upon decryption, the salt is retrieved from the header, and the key and IV are re-computed from the provided password and salt.


1 Answers

If the countless online hex converters don't work for, 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
    

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.


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.

like image 159
Artjom B. Avatar answered Oct 26 '22 22:10

Artjom B.