【问题标题】:Unable to decrypt aes-256-gcm encrypted data in java无法在 java 中解密 aes-256-gcm 加密数据
【发布时间】:2020-07-03 06:31:42
【问题描述】:

我使用 OpenSSL aes-256-gcm 加密了一个文件。由于命令行不支持 aes-256-gcm,我已经安装了 LibreSSL,并且可以使用以下命令来加密文件的数据。

openssl enc -aes-256-gcm -K 61616161616161616161616161616161 -iv 768A5C31A97D5FE9 -e -in file.in -out file.out

我需要用 Java 解密 file.out 的数据,但我做不到。

示例代码:

    // Get Cipher Instance
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

    String key = "61616161616161616161616161616161";
    byte[] IV = "768A5C31A97D5FE9".getBytes();

    // Create SecretKeySpec
    SecretKeySpec keySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");

    // Create GCMParameterSpec
    GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, IV);

    // Initialize Cipher for DECRYPT_MODE
    cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);

    // Perform Decryption
    byte[] decryptedText = cipher.doFinal(cipherText); // for the data by reading file.out

但是,我收到一个异常说 javax.crypto.AEADBadTagException: Tag mismatch!

【问题讨论】:

    标签: java encryption aes-gcm


    【解决方案1】:

    这应该行不通。命令行openssl enc 不支持 AEAD 密码/模式,尽管如果您错误地指定了这样的密码并默默地产生了错误的输出,则 1.0.1 的早期版本(低于补丁 h,2012-2014)无法捕获。如果您实际上使用的是 LibreSSL 而不是 OpenSSL,那么它似乎继承了这个问题并且没有修复它,尽管 LibreSSL 项目的全部意义在于他们将修复由无能的 OpenSSL 人员造成的所有错误。

    如果这是一个在 OpenSSL(以及 Java)中正常工作的密码,比如 aes-256-ctr,那么你唯一的问题是 openssl enc -K -iv 将它们的参数采用十六进制(适用于 shell 上下文),而Java 加密是从可以处理二进制数据的代码中调用的,并且期望它的参数采用这种形式。因此,您提供给 OpenSSL 的值实际上是 16 字节(128 位)和 8 字节(64 位),而不是应有的 256 位和 128 位(对于 CTR;对于 GCM 是 IV 96 位是正确的,但如前所述,GCM 在这里不起作用)。 openssl enc 自动用(二进制)零填充 -K -iv,但 Java 没有。因此,您需要更多类似的东西

     byte[] key = Arrays.copyOf( javax.xml.bind.DatatypeConverter.parseHexBinary("61616161616161616161616161616161"), 32);
     // Arrays.copyOf zero-pads when expanding an array
     // then use SecretKeySpec (key, "AES")
     // and IVParameterSpec (iv) instead of GCMParameterSpec
    
     // but after Java8 most of javax.xml is removed, so unless you
     // are using a library that contains this (e.g. Apache) 
     // or have already written your own, you need something like
    
     byte[] fromHex(String h){
       byte[] v = new byte[h.length()/2];
       for( int i = 0; i < h.length(); i += 2 ) v[i] = Integer.parseInt(h.substring(i,i+2),16);
       return v;
     }
    

    比较AES encrypt with openssl command line tool, and decrypt in JavaBlowfish encrypt in Java/Scala and decrypt in bash(后者是反方向,但需要匹配的相同)

    【讨论】:

    • 我使用的是 OpenSSL 版本的 OpenSSL 1.1.1c,通过使用 LibreSSL,我可以使用以下命令进行加密和解密。 OpenSSL的ENC -AES-256-GCM -nopad -K 61616161616161616161616161616161 -IV 768A5C31A97D5FE9 -e -in file.in退房手续file13.out OpenSSL的ENC -d -AES-256-GCM -nopad -K 61616161616161616161616161616161 -IV 768A5C31A97D5FE9 -e -in file13.out -out file113.in 我使用的是 CBC 模式,我可以通过 openssl 命令加密并在 Java 中解密。我认为我在 GCM 模式下做错了什么。
    • @subratpadhi - LibreSSL 似乎忽略了 AES-GCM 上的身份验证标签 here,这实际上是一个错误。由于这适用于加密和解密,因此两者都在 in LibreSSL 中工作。但是,跨平台(例如使用 Java)解密失败(即使正确传递了密钥和 IV 以使它们在双方都相同),因为该标记是身份验证所必需的。
    • 能否绕过Java端的认证标签进行AES GCM解密?
    猜你喜欢
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 2021-03-05
    • 2021-06-04
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 2022-10-16
    相关资源
    最近更新 更多