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

Android中AES-GCM文件解密抛出AEADBadTagException异常求助

嘿,我之前踩过AES-GCM解密时这个BAD_DECRYPT的坑,结合你说的情况——字符串加解密正常但文件解密报错,大概率是文件读写时的字节处理出了问题,尤其是GCM模式依赖的核心要素没处理对。咱们一步步来排查:

  • IV(初始化向量)的存储与读取必须完全一致
    AES-GCM要求解密时用的IV和加密时完全相同,推荐用12字节长度的IV。如果加密时你把IV写到了文件开头,但解密时没读够长度,或者用了字符流读取导致字节损坏,就会触发校验失败。
    检查你的代码:加密时是不是先写IV再写密文?解密时是不是先读取完整的12字节IV?注意InputStream.read()可能不会一次读完所有字节,大文件场景下要循环读取确保IV完整。比如:

    // 加密时写IV
    byte[] iv = new byte[12];
    SecureRandom.getInstanceStrong().nextBytes(iv);
    outputStream.write(iv);
    // 解密时读IV
    byte[] iv = new byte[12];
    int bytesRead = 0;
    while (bytesRead < 12) {
        int read = inputStream.read(iv, bytesRead, 12 - bytesRead);
        if (read == -1) throw new IOException("IV读取不完整");
        bytesRead += read;
    }
    
  • 附加数据(AAD)必须加密解密完全匹配
    如果你加密时调用了cipher.updateAAD(aadBytes)设置了附加数据,解密时必须传入完全一样的AAD(内容、长度都不能变)。如果字符串加解密没用到AAD,但文件加解密用了(或者反过来),就会出现这个异常。不需要AAD的话,两边都别调用这个方法。

  • 文件读写必须用字节流,别碰字符流
    如果你用了FileReader/FileWriter这类字符流处理文件,会把字节转成字符再转回,过程中可能丢失或修改字节,破坏密文的完整性。字符串加解密用的是字节数组所以没问题,但文件必须用FileInputStream/FileOutputStream这类字节流全程处理。

  • 密文必须完整读写(包含GCM认证标签)
    AES-GCM加密后的结果是「加密数据+16字节认证标签」,你必须把cipher.doFinal()返回的所有字节都写入文件;解密时也要读取全部密文字节(包括标签)再传给cipher.doFinal(),不能截断。分块处理大文件时,要记得把cipher.update()的输出和doFinal()的输出都写入文件,解密同理。

  • 密钥必须完全一致
    虽然字符串加解密正常,但也要确认文件加解密时用的是同一个密钥。如果密钥是从密码派生的,要确保PBKDF2的迭代次数、盐值、哈希算法完全一致。

给你一个经过验证的文件加解密示例片段,你可以对照调整自己的代码:

// 加密文件(支持大文件分块)
public static void encryptFile(String inPath, String outPath, SecretKey key) throws Exception {
    try (FileInputStream fis = new FileInputStream(inPath);
         FileOutputStream fos = new FileOutputStream(outPath)) {
        // 生成12字节IV并写入文件
        byte[] iv = new byte[12];
        SecureRandom.getInstanceStrong().nextBytes(iv);
        fos.write(iv);

        // 初始化GCM cipher
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv));

        // 分块读写
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = fis.read(buffer)) != -1) {
            byte[] encryptedChunk = cipher.update(buffer, 0, bytesRead);
            if (encryptedChunk != null) fos.write(encryptedChunk);
        }
        // 写入最后一块和认证标签
        byte[] finalChunk = cipher.doFinal();
        if (finalChunk != null) fos.write(finalChunk);
    }
}

// 解密文件
public static void decryptFile(String inPath, String outPath, SecretKey key) throws Exception {
    try (FileInputStream fis = new FileInputStream(inPath);
         FileOutputStream fos = new FileOutputStream(outPath)) {
        // 读取IV
        byte[] iv = new byte[12];
        int bytesRead = 0;
        while (bytesRead < 12) {
            int read = fis.read(iv, bytesRead, 12 - bytesRead);
            if (read == -1) throw new IOException("无效的加密文件:IV缺失");
            bytesRead += read;
        }

        // 初始化GCM cipher
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));

        // 分块读写
        byte[] buffer = new byte[8192];
        while ((bytesRead = fis.read(buffer)) != -1) {
            byte[] decryptedChunk = cipher.update(buffer, 0, bytesRead);
            if (decryptedChunk != null) fos.write(decryptedChunk);
        }
        // 处理最后一块并校验标签
        byte[] finalChunk = cipher.doFinal();
        if (finalChunk != null) fos.write(finalChunk);
    }
}

// 生成AES-256密钥
public static SecretKey generateAESKey() throws NoSuchAlgorithmException {
    KeyGenerator keyGen = KeyGenerator.getInstance("AES");
    keyGen.init(256);
    return keyGen.generateKey();
}

对照这些点排查,应该能解决你的AEADBadTagException问题。

内容的提问来源于stack exchange,提问作者Ruthwik Warrier

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:36:09