6

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

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

dpMyN7L5HI8VZEs1biQJ7g==

爪哇:

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

4

1 回答 1

5

如果无数在线十六进制转换器不起作用,那么您可以简单地将您在 Java 中使用的密钥打印为十六进制。这是关于此壮举的一个流行的 SO 问题。

完成后,您会发现它仍然无法正常工作,因为您使用的是不同的算法。

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

那么您在 Java 中生成的密钥只有 16 个字节长,因此 OpenSSL 中的匹配密码将是“aes-128-ecb”。

正如 dave_thompson_085 在评论中所说:

  • echo添加您的 Java 代码未添加的换行符。您需要以这种方式创建明文:echo -n "lun01". 或者,如果您使用的是 Windows,请查看此内容。

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

  • 完整命令:

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

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

更好的方法是添加身份验证,例如添加具有先加密后 MAC 方法的 HMAC 标签,或者简单地使用像 GCM 这样的身份验证模式。


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

于 2015-08-14T21:26:46.467 回答