Encrypt using OpenSSL in the same way Java does

笑着哭i 提交于 2019-12-04 14:35:33

问题


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


回答1:


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.



来源:https://stackoverflow.com/questions/32018672/encrypt-using-openssl-in-the-same-way-java-does

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!