使用OpenSSL加密的方式与Java相同 [英] Encrypt using OpenSSL in the same way Java does

查看:216
本文介绍了使用OpenSSL加密的方式与Java相同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须使用bash脚本加密字符串,就像我使用javax.crypto.Cipher加密一样。在java我使用AES-256,密钥为0123456789。但是当我使用openssl时,我必须将0123456789转换为十六进制,但结果与java不一样

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 ==

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

d230b216e9d65964abd4092f5c455a21

推荐答案

如果无数的在线十六进制转换器不起作用,那么您只需将您在Java中使用的密钥打印为十六进制即可。 此处是关于此专长的热门搜索引擎优化问题。

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.

使用 Cipher.getInstance(AES); 时,它很可能默认为AES / ECB / PKCS5Padding与aes-256-cbc不同,因为ECB和CBC是完全不同的两个运作模式。为防止这种歧义,请始终完全限定您的密码,例如: Cipher.getInstance(AES / CBC / PKCS5Padding);

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");.

然后,你在Java中生成的密钥只有16个字节长,因此OpenSSL中的匹配密码将是aes-128-ecb。

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在评论中说:

As dave_thompson_085 said in a comment:


  • echo 添加一个你的Java代码没有添加的换行符。您需要以这种方式创建明文: echo -nlun01。或者,如果您使用的是Windows,请参阅

  • 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.

您的Java代码将结果输出为十六进制,因此您需要在OpenSSL中执行相同的操作。您需要删除OpenSSL命令中的 -a 选项以防止Base64编码,然后您可以使用其他命令行工具,例如 od 在linux上使用 od -tx1 将二进制输出数据转换为十六进制。

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.

完整命令:

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


不要使用ECB模式!它在语义上不安全。您需要至少使用带有随机IV的CBC模式(检查它是随机的而不仅仅是零字节)。

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).

更好的方法是添加身份验证,例如添加一个带有加密然后MAC方法的HMAC标签,或者只是使用像GCM这样的认证模式。

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.

如果你是使用除ECB之外的任何东西,那么你不能在两个版本中加密相同的东西并期望出现相同的密文。由于它是随机的,您需要在一个版本中加密并在另一个版本中解密以确保兼容性。

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.

这篇关于使用OpenSSL加密的方式与Java相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆