使用 Java 的 AES-256-GCM 解密中的标签不匹配错误
Posted
技术标签:
【中文标题】使用 Java 的 AES-256-GCM 解密中的标签不匹配错误【英文标题】:Tag mismatch error in AES-256-GCM Decryption using Java 【发布时间】:2017-05-10 08:18:28 【问题描述】:我有以下用 javascript 编写的函数,用于使用 aes-256-gcm 进行加密:
encrypt: function (text, masterkey)
try
// random initialization vector
var iv = crypto.randomBytes(12);
// random salt
var salt = crypto.randomBytes(64);
// derive key: 32 byte key length - in assumption the masterkey is a cryptographic and NOT a password there is no need for
// a large number of iterations. It may can replaced by HKDF
var key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512');
// AES 256 GCM Mode
var cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// encrypt the given text
var encrypted = Buffer.concat([cipher.update(text, 'utf8'), cipher.final()]);
// extract the auth tag
var tag = cipher.getAuthTag();
// generate output
return Buffer.concat([salt, iv, tag, encrypted]).toString('base64');
catch(e)
// error
return null;
上述函数的加密文本使用以下函数成功解密回来:
decrypt: function (data, masterkey)
try
// base64 decoding
var bData = new Buffer(data, 'base64');
var salt = bData.slice(0, 64);
var iv = bData.slice(64, 76);
var tag = bData.slice(76, 92);
var text = bData.slice(92);
// derive key using; 32 byte key length
var key = crypto.pbkdf2Sync(masterkey, salt , 2145, 32, 'sha512');
// AES 256 GCM Mode
var decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
// decrypt the given text
var decrypted = decipher.update(text, 'binary', 'utf8') + decipher.final('utf8');
return decrypted;
catch(e)
// error
return null;
现在,我需要一个 Java 中的解密方法,它相当于上面的 Javascript 解密函数。以下是我为解密编写的Java代码:
public void decrypt(byte[] nkb, String crKey)
//nkb is byte array formed by Base64 decoding of 'data' variable in the Javascript code
//crKey corresponds to the 'masterkey' variable
byte[] salt = Arrays.copyOfRange(nkb, 0, 64);
byte[] iv = Arrays.copyOfRange(nkb, 64, 76);
byte[] tag = Arrays.copyOfRange(nkb, 76, 92);
byte[] text = Arrays.copyOfRange(nkb, 92, nkb.length);
PBEKeySpec ks = new PBEKeySpec(crKey.toCharArray(), salt, iterations, 256);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
SecretKey pbeKey = skf.generateSecret(ks);
byte[] decrypted = decrypt(iv, pbeKey.getEncoded(), text, tag);
public static byte[] decrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes, byte[] tagBytes)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException,
NoSuchProviderException
GCMParameterSpec ivSpec = new GCMParameterSpec(tagBytes.length*Byte.SIZE, ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes); //getting tag mismatch error here
正如我在上面的代码中所评论的,我在最后一行得到了一个标签不匹配错误。如果能帮助我找出我做错了什么,我将不胜感激。
我在这行代码中有错误:
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec)
java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
at javax.crypto.Cipher.implInit(Cipher.java:805)
at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
at javax.crypto.Cipher.init(Cipher.java:1396)
at javax.crypto.Cipher.init(Cipher.java:1327)
at com.micropro.namwebservice.utils.CryptoUtils.decrypt(CryptoUtils.java:93)
at com.micropro.namwebservice.utils.CryptoUtils.decrypt(CryptoUtils.java:82)
【问题讨论】:
【参考方案1】:您需要将标记提供给 Java GCM 代码,以便它可以检查消息是否真实。 Java API 期望将标签附加到密文中。更改代码以执行此操作的最简单方法是替换该行
return cipher.doFinal(textBytes);
两行:
cipher.update(textBytes);
return cipher.doFinal(tagBytes);
【讨论】:
它工作得很好,谢谢。这是否意味着标记字节被附加在文本字节的末尾? @AnishHirlekar 是的,Java 期望密文的字节紧跟标签字节,并检查标签是否匹配,如果不匹配则抛出异常。以上是关于使用 Java 的 AES-256-GCM 解密中的标签不匹配错误的主要内容,如果未能解决你的问题,请参考以下文章
Nodejs AES-256-GCM 通过 webcrypto api 解密加密的客户端消息
Nodejs AES-256-GCM 在客户端通过浏览器 webcrypto api 加密和解密
跨平台AES 256 GCM Javascript和Elixir