You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AES/GCM解密时调用update后doFinal仅返回部分明文问题

AES/GCM解密时update+doFinal返回部分明文的问题分析与解决

问题现象

使用AES/GCM/NoPadding算法解密时,若先调用cipher.update(ciphertext)再执行cipher.doFinal()(或cipher.doFinal(new byte[0])),仅能得到部分明文。例如输入JSON:

String jsonExample = "{\"dataType\":\"STRING\",\"strValue\":\"000000\"}";

解密后仅返回"000000";但直接调用cipher.doFinal(ciphertext)则能完整还原原始字符串。小体积文本可正常解密,特定尺寸文本出现数据丢失。

核心原因

问题出在忽略了Cipher.update()方法的返回值:

  • Cipher.update()处理数据时,若输入数据量超过Cipher内部缓冲区大小,会立即返回一部分处理后的明文;剩余未处理的数据会在cipher.doFinal()时完成处理并返回。
  • 你的解密代码仅返回了doFinal()的结果,丢弃了update()返回的那部分明文,导致最终只得到后半段数据。
  • 小文本能正常运行,是因为数据量未超过缓冲区大小,update()返回空数组,所有明文都由doFinal()返回,因此未暴露问题。

解决办法

修改解密代码,收集update()和doFinal()的所有返回值并合并,才能得到完整明文。示例代码如下:

方式1:数组直接合并

javax.crypto.Cipher cipher = 
      javax.crypto.Cipher.getInstance("AES/GCM/NoPadding", new BouncyCastleProvider());
GCMParameterSpec spec = new GCMParameterSpec(Constants.GCM_TAG_BYTES * 8, nonce);
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, dataKey, spec);

// 获取update返回的部分明文
byte[] partialData = cipher.update(ciphertext);
// 获取doFinal返回的剩余明文
byte[] finalData = cipher.doFinal();

// 合并两部分数据
byte[] decrypted = new byte[partialData.length + finalData.length];
System.arraycopy(partialData, 0, decrypted, 0, partialData.length);
System.arraycopy(finalData, 0, decrypted, partialData.length, finalData.length);

return decrypted;

方式2:用ByteArrayOutputStream收集(更灵活)

javax.crypto.Cipher cipher = 
      javax.crypto.Cipher.getInstance("AES/GCM/NoPadding", new BouncyCastleProvider());
GCMParameterSpec spec = new GCMParameterSpec(Constants.GCM_TAG_BYTES * 8, nonce);
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, dataKey, spec);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] chunk;

// 收集update的输出
chunk = cipher.update(ciphertext);
if (chunk != null && chunk.length > 0) {
    outputStream.write(chunk);
}

// 收集doFinal的输出
chunk = cipher.doFinal();
if (chunk != null && chunk.length > 0) {
    outputStream.write(chunk);
}

return outputStream.toByteArray();

关键注意事项

  • 无论使用哪种对称加密模式(ECB、CBC、GCM等),都不能忽略Cipher.update()的返回值,这是JCE Cipher类的通用处理逻辑,和具体加密模式无关。
  • GCM作为AEAD模式,解密时会自动验证附在密文末尾的认证标签,但标签的验证逻辑不影响update()和doFinal()的返回值规则,只需正确收集所有输出即可。

内容的提问来源于stack exchange,提问作者P basak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 03:25:27