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

Android加密大文件解密触发Keystore -38错误的排查求助

问题原因及修复方案

核心问题1:长度存储/读取的溢出问题

你用stream.write(cipher.getIV().length)和stream.write(config_encrypted.length)写入长度,但write(int)仅会写入低8位字节。当加密后的数据长度超过255时,长度值会被截断,导致读取时得到错误的密文长度,解密时传入不完整的密文,触发Keystore的-38 Invalid argument异常。

核心问题2:文件读取未确保完全读取

input.read(iv)和input.read(data_encrypted)无法保证一次性读取所有字节,read(byte[])仅返回实际读取的字节数,大文件场景下会导致数组未被填满,密文不完整进而引发解密失败。

修复后的代码

读取方法(read())

public byte[] read() throws MyReadException {
    byte[] data;

    try (FileInputStream input = new FileInputStream(this.file_path)) {
        DataInputStream dis = new DataInputStream(input);
        // 读取完整的int类型长度,避免溢出
        int iv_size = dis.readInt();
        byte[] iv = new byte[iv_size];
        
        // 循环读取直到填满IV数组
        int readLen;
        int totalRead = 0;
        while (totalRead < iv_size && (readLen = input.read(iv, totalRead, iv_size - totalRead)) != -1) {
            totalRead += readLen;
        }

        int encrypted_byte_size = dis.readInt();
        byte[] data_encrypted = new byte[encrypted_byte_size];
        totalRead = 0;
        // 循环读取直到填满密文数组
        while (totalRead < encrypted_byte_size && (readLen = input.read(data_encrypted, totalRead, encrypted_byte_size - totalRead)) != -1) {
            totalRead += readLen;
        }

        Cipher cipher = Cipher.getInstance(transformation);
        cipher.init(Cipher.DECRYPT_MODE, this.getKey(), new IvParameterSpec(iv));
        data = cipher.doFinal(data_encrypted);
    } catch (Exception e) {
        throw new MyReadException(e);
    }

    return data;
}

写入方法(write())

public void write(byte[] data) throws MyWriteException {
    try (FileOutputStream stream = new FileOutputStream(this.file_path)) {
        DataOutputStream dos = new DataOutputStream(stream);
        Cipher cipher = Cipher.getInstance(transformation);
        cipher.init(Cipher.ENCRYPT_MODE, this.getKey());

        byte[] config_encrypted = cipher.doFinal(data);
        // 写入完整的int类型IV长度
        dos.writeInt(cipher.getIV().length);
        stream.write(cipher.getIV());
        // 写入完整的int类型密文长度
        dos.writeInt(config_encrypted.length);
        stream.write(config_encrypted);
    } catch (Exception e) {
        throw new MyWriteException(e);
    }
}

额外注意事项

  • AES-CBC模式的IV固定为16字节,可直接写死长度值以简化代码,保留动态读取方式则更具通用性。
  • 使用try-with-resources语法自动关闭流,避免资源泄漏。
  • 确保transformation值为"AES/CBC/PKCS7Padding",与密钥生成时的配置完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 04:48:08