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
相关产品推荐
相关产品推荐

