解密时读取CipherInputStream触发BadPaddingException问题排查
AES/CBC解密时BadPaddingException问题排查与修复
核心问题:加密阶段Cipher未使用传入密钥重新初始化
你的代码存在致命逻辑错误:
- 程序启动时先用随机生成的密钥和IV初始化了
cipher为加密模式,但进入加密分支后,你加载了用户传入的Base64密钥到skeySpec,却没有重新初始化Cipher。 - 这导致实际加密文件用的是随机生成的密钥,而解密时用的是你传入的指定密钥,密钥不匹配直接触发
BadPaddingException。
修复步骤
1. 修正加密流程的Cipher初始化
将加密分支内的Cipher初始化移到用户密钥加载之后,确保加密使用正确的密钥:
if (mode.equals("enc")) { System.out.println("initVector=" + Util.bytesToHex(initVector)); // 先加载用户传入的密钥 skeySpec = new SecretKeySpec(Base64.getDecoder().decode(args[1]), ALGORITHM); // 重新初始化Cipher,使用正确的密钥和随机IV cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); final Path encryptedPath = currentPath.resolve(args[3]); // 替换getResourceAsStream为文件系统读取,兼容当前目录文件 try (InputStream fin = Files.newInputStream(Path.of(args[2])); OutputStream fout = Files.newOutputStream(encryptedPath); CipherOutputStream cipherOut = new CipherOutputStream(fout, cipher)) { final byte[] bytes = new byte[1024]; fout.write(initVector); for (int length = fin.read(bytes); length != -1; length = fin.read(bytes)) { cipherOut.write(bytes, 0, length); } // 移除手动close,try-with-resources会自动处理 } catch (IOException e) { LOG.log(Level.INFO, "Unable to encrypt", e); } return; }
2. 优化解密分支的错误处理
补充IV读取不完整时的错误处理,避免无效解密:
int first16bytes = encryptedData.read(storedIV); if (first16bytes != storedIV.length) { throw new IOException("Failed to read complete IV from encrypted file"); }
3. 移除不必要的手动流关闭操作
try-with-resources语法会自动关闭所有实现AutoCloseable的资源,解密分支里的decryptStream.close()可以删除。
验证方法
修复后重新编译执行:
- 编译:
javac -g FileEncryptor.java Util.java - 加密:
java FileEncryptor enc 90F6seEyxAK9cxblqsKJGQ== input.txt ciphertext.enc - 解密:
java FileEncryptor dec 90F6seEyxAK9cxblqsKJGQ== ciphertext.enc decrypted.txt
此时解密流程不会再触发BadPaddingException,且解密后的文件与原文件内容一致。
内容的提问来源于stack exchange,提问作者iceyjc
相关产品推荐
相关产品推荐

