aes解密需严格匹配加密参数:算法/模式/填充、密钥、iv、编码及字节处理;密钥须为16/24/32字节并用secretkeyspec包装,iv须与加密时完全相同且正确传递,base64解码后解密再utf-8转字符串。

在 Java 中用 Cipher.init() 执行 AES 解密,关键不是“调对方法”,而是确保解密上下文与加密时完全一致:算法/模式/填充、密钥、IV(如使用)、字符编码和字节处理方式。稍有偏差就会抛出 BadPaddingException 或得到乱码。
AES 解密必须匹配加密参数
AES 是对称算法,解密前必须准确还原加密时的完整配置。常见组合是 AES/CBC/PKCS5Padding 或 AES/GCM/NoPadding。若加密端用 CBC 模式且显式指定了 IV,解密时必须传入**同一个 IV 字节数组**;若用 GCM,还需提供相同的 AAD 和标签长度。
- 检查加密方文档或代码,确认完整转换符(Transformation),例如
"AES/CBC/PKCS5Padding" - 密钥必须是 128、192 或 256 位(对应 16、24、32 字节),且需用
SecretKeySpec包装,不能直接传字符串 - IV 长度必须与算法要求一致(CBC 为 16 字节,GCM 通常 12 字节),且不可复用 —— 解密时必须用加密时生成并随文传输的那个 IV
正确构造 Cipher 并初始化解密器
不要跳过异常处理,也不要依赖默认行为。明确指定 provider(如 "SunJCE")可提升可移植性,但非必需。
- 创建 Cipher 实例:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - 准备密钥对象:
SecretKeySpec keySpec = new SecretKeySpec(rawKeyBytes, "AES"); - 准备 IV(CBC 示例):
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes); - 调用 init():
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);—— 注意是DECRYPT_MODE,不是ENCRYPT_MODE
安全还原报文:从字节到原始内容
加密报文通常是 Base64 编码的字符串(如 HTTP Header 或 JSON 字段中传输)。解密前要先解码为原始密文字节;解密后得到明文字节,再按约定编码(如 UTF-8)转成字符串。
- 若输入是 Base64 字符串:
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedB64); - 执行解密:
byte[] decryptedBytes = cipher.doFinal(encryptedBytes); - 还原为字符串:
String plainText = new String(decryptedBytes, StandardCharsets.UTF_8); - 若解密后含前导/尾随控制字符或长度异常,检查是否加密时额外做了序列化(如加了 JSON 封装、自定义头)
常见陷阱与加固建议
生产环境中的失败往往源于“看似合理”的假设。
- 密钥硬编码或从字符串直接取
.getBytes()→ 导致平台默认编码不一致(如 Windows vs Linux),应统一用StandardCharsets.UTF_8编码后再摘要或派生 - 忽略 IV 传输机制 → 加密端必须把 IV(明文)和密文一起发送,常见做法是拼接(IV+密文)或分字段传输
- 未校验解密结果 → 可在明文前添加固定 magic bytes 或 HMAC 校验,避免被篡改后静默解密成功
- 复用 Cipher 实例 → 单个
Cipher对象不是线程安全的,高并发下应每次新建或使用 ThreadLocal 缓存
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











