无法在Java中解密AES-256-GCM加密数据 [英] Unable to decrypt aes-256-gcm encrypted data in java

查看:283
本文介绍了无法在Java中解密AES-256-GCM加密数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我需要用Java解密file.out的数据,但是我无法做到这一点.

示例代码:

 //获取密码实例密码cipher = Cipher.getInstance("AES/GCM/NoPadding");字符串键="61616161616161616161661661616161";byte [] IV ="768A5C31A97D5FE9" .getBytes();//创建SecretKeySpecSecretKeySpec keySpec =新的SecretKeySpec(key.getBytes("UTF-8"),"AES");//创建GCMParameterSpecGCMParameterSpec gcmParameterSpec =新的GCMParameterSpec(128,IV);//为DECRYPT_MODE初始化密码cipher.init(Cipher.DECRYPT_MODE,keySpec,gcmParameterSpec);//执行解密byte [] unlockedText = cipher.doFinal(cipherText);//通过读取file.out获取数据 

但是,我收到一个异常,说javax.crypto.AEADBadTagException:标记不匹配!

解决方案

那不行.命令行 openssl enc 不支持AEAD密码/模式,尽管如果您错误地指定了这种密码并默默地产生了错误,则1.0.1的早期版本(2012年至2014年低于补丁h)无法捕获.输出.如果您实际上使用的是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 []键= Arrays.copyOf(javax.xml.bind.DatatypeConverter.parseHexBinary("61616161616161616161616161616161"),32);//展开数组时使用Arrays.copyOf零填充//然后使用SecretKeySpec(键,"AES")//和IVParameterSpec(iv)代替GCMParameterSpec//但在Java8之后,大部分javax.xml都被删除了,所以除非您//正在使用包含此内容的库(例如Apache)//或已经编写了自己的书,则需要类似byte [] fromHex(String h){byte [] v =新的byte [h.length()/2];for(int i = 0; i< h.length(); i + = 2)v [i] = Integer.parseInt(h.substring(i,i + 2),16);返回v;} 

比较使用openssl命令行进行AES加密工具,并使用Java解密 Blowfish加密Java/Scala并使用bash解密(后者是相反的方向,但匹配的需求是相同的)

I have encrypted a file by using OpenSSL aes-256-gcm. As aes-256-gcm not directed supported by command line I have installed LibreSSL and I am able to use the below command to encrypt the data of a file.

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

I need to decrypt the data of file.out in Java and I am unable to do that.

Sample code :

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

However, I am getting an exception saying javax.crypto.AEADBadTagException: Tag mismatch!

解决方案

That should't work. Commandline openssl enc doesn't support AEAD ciphers/modes, although early versions of 1.0.1 (below patch h, in 2012-2014) failed to catch if you incorrectly specified such a cipher and silently produced wrong output. If you are actually using LibreSSL and not OpenSSL, it appears to have inherited this problem and not fixed it, even though the whole point of the LibreSSL project was that they were going to fix all the bugs caused by the incompetent OpenSSL people.

If this were a cipher that worked correctly in OpenSSL (and also Java), like aes-256-ctr, then your only problem would be that openssl enc -K -iv take their arguments in hex (suitable for a shell context), whereas Java crypto is called from code that can handle binary data and expects its arguments in that form. As a result the values you provide to OpenSSL are actually 16 bytes (128 bits) and 8 bytes (64 bits), not 256 bits and 128 bits as they should be (for CTR; for GCM an IV of 96 bits would be correct, but as noted GCM won't work here). openssl enc automatically pads -K -iv with (binary) zeros, but Java doesn't. Thus you would need something more like

 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;
 }

Compare AES encrypt with openssl command line tool, and decrypt in Java and Blowfish encrypt in Java/Scala and decrypt in bash (the latter is the reverse direction, but the need to match is the same)

这篇关于无法在Java中解密AES-256-GCM加密数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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