如何使用Java 8编写带认证标签的AES-GCM解密代码?
Java 8 实现 AES-256-GCM 解密(对应Node.js crypto等效逻辑)
以下是与你提供的Node.js代码完全等效的Java 8实现,重点解决GCM模式下认证标签的处理问题:
import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; public class AESGCMDecryptor { private static final String ALGORITHM = "AES/GCM/NoPadding"; private static final int TAG_LENGTH_BITS = 128; // GCM默认标签长度为128位 public static String decryptSymmetric128BitHexKeyUTF8(String ciphertext, String iv, String tag, String key) throws Exception { // 1. 处理密钥:Node.js直接使用字符串的UTF-8字节作为AES密钥 byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); // 2. 解码IV和认证标签(Base64转字节数组) byte[] ivBytes = Base64.getDecoder().decode(iv); byte[] tagBytes = Base64.getDecoder().decode(tag); // 3. 合并密文与标签:GCM标准格式为「密文 + 认证标签」,Node.js将两者拆分存储,需重新合并 byte[] ciphertextBytes = Base64.getDecoder().decode(ciphertext); byte[] combinedData = new byte[ciphertextBytes.length + tagBytes.length]; System.arraycopy(ciphertextBytes, 0, combinedData, 0, ciphertextBytes.length); System.arraycopy(tagBytes, 0, combinedData, ciphertextBytes.length, tagBytes.length); // 4. 初始化GCM解密器 Cipher cipher = Cipher.getInstance(ALGORITHM); GCMParameterSpec gcmSpec = new GCMParameterSpec(TAG_LENGTH_BITS, ivBytes); cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec); // 5. 解密并自动验证标签:标签不匹配时会抛出AEADBadTagException byte[] plaintextBytes = cipher.doFinal(combinedData); return new String(plaintextBytes, StandardCharsets.UTF_8); } // 测试用例 public static void main(String[] args) throws Exception { String cipherText = "2LPVwa7s4+xyd8KF94r07TOCaOdf4X90NWqhHQCpoJGT+T3TYjKCWf3V+A=="; String iv = "S4/yimaF8bu0jQW9uagIJA=="; String tag = "L6BtTic18dd4fNL2maytFA=="; String key = "password1232asdfpassword1232asdf"; String expectedPlainText = "The quick brown fox jumps over the lazy dog"; String decryptedText = decryptSymmetric128BitHexKeyUTF8(cipherText, iv, tag, key); System.out.println("解密结果:" + decryptedText); System.out.println("与预期匹配:" + decryptedText.equals(expectedPlainText)); } }
关键逻辑说明
- 密钥匹配:Node.js中直接传入字符串作为密钥,Java通过
String.getBytes(StandardCharsets.UTF_8)获取完全一致的字节数组,你的测试密钥正好是32字节(符合AES-256的要求)。 - 标签处理:GCM模式的标准输出是密文加标签,Node.js代码将两者分离存储,因此Java需要先将密文和标签拼接,才能让解密器自动完成标签验证。
- GCM参数配置:
GCMParameterSpec指定标签长度(128位,与Node.js默认值一致)和初始化向量(IV),确保解密逻辑对齐。 - 标签验证:调用
cipher.doFinal()时,Cipher会自动验证标签有效性,若标签不匹配或数据被篡改,会抛出AEADBadTagException异常。
注意事项
- 确保密钥长度与AES版本匹配:AES-256需要32字节密钥,AES-128需要16字节密钥,若密钥长度不符会抛出
InvalidKeyException。 - 标签长度需保持一致:GCM支持128/120/112/104/96位标签,需与加密端配置一致,否则解密会失败。
- 异常处理:实际生产代码中需捕获并处理
NoSuchAlgorithmException(算法不存在)、InvalidKeyException(密钥无效)、AEADBadTagException(标签验证失败)等异常。
内容的提问来源于stack exchange,提问作者thatman
相关产品推荐
相关产品推荐

