aes.create()易解密失败因默认填充、分组模式及密钥长度不一致,跨平台时更易出错;须显式设cbc模式与pkcs7填充,iv随机生成并同密文传输,密钥需合规长度且建议口令派生。

为什么直接用 Aes.Create() 容易解密失败
因为 Aes.Create() 返回的默认实例不保证填充模式、分组模式、密钥长度一致,尤其在跨平台或跨语言交互时,哪怕密钥和 IV 相同,也可能因默认值不同而解密乱码。.NET 6+ 默认用 Pkcs7 填充 + CBC 模式,但旧版本或某些配置下可能为 ECB(不安全且不推荐),导致加密端和解密端行为不一致。
实操建议:
- 显式设置
Mode = CipherMode.CBC和Padding = PaddingMode.PKCS7,避免依赖默认值 - IV 必须每次加密随机生成,并和密文一起传输(不能硬编码或复用)
- 密钥必须是 128/192/256 位(即 16/24/32 字节),不足需补足、超长需截断或哈希(如用
SHA256生成 32 字节密钥)
如何安全生成并复用 IV 和密钥
IV 不需要保密,但绝不能重复;密钥必须保密且长度合规。常见错误是把字符串密钥直接当字节数组用——比如 "mykey123" 转成 UTF8 后只有 8 字节,无法用于 AES-256。
实操建议:
- 用
RNGCryptoServiceProvider(.NET Framework)或RandomNumberGenerator(.NET Core+)生成随机 IV:var iv = new byte[16]; RandomNumberGenerator.Fill(iv); - 密钥建议从口令派生:
var key = new Rfc2898DeriveBytes(password, salt, 100_000, HashAlgorithmName.SHA256).GetBytes(32);(AES-256) - IV 和盐值(salt)应与密文一同存储或传输,例如拼接为
iv + ciphertext或用 JSON 封装
加密输出是字节数组,但常要转 Base64 传网络
直接返回 byte[] 在 HTTP 或日志中不可读,容易被截断或编码污染。常见错误是加密后调用 Encoding.UTF8.GetString(cipherBytes)——这是错的,二进制数据不是合法 UTF-8 序列,会损坏数据。
实操建议:
- 加密后立即用
Convert.ToBase64String(cipherBytes)编码;解密前先用Convert.FromBase64String(base64)还原 - 如果走 JSON API,字段值直接存 Base64 字符串,不要尝试“UTF8 转字符串”绕路
- 注意 Base64 字符串末尾可能含
=,URL 场景需用UrlTokenEncode(System.Web.HttpServerUtility)或手动替换
解密时 CryptographicException: Bad data 怎么快速定位
这个异常几乎总是因为:IV 不匹配、密钥长度不对、填充模式不一致、密文被截断或篡改、或用了错误的编码还原方式。
排查步骤:
- 确认解密用的 IV 和加密时完全一致(逐字节比对,不只是长度)
- 打印密钥长度:
key.Length,必须是 16 / 24 / 32;不是则重新生成或派生 - 检查密文是否完整:Base64 解码后长度是否为 16 的整数倍(CBC 模式下,PKCS7 填充后必然满足)
- 临时关闭填充验证:设
Padding = PaddingMode.None并手动处理,可判断是否填充逻辑出问题(仅调试用)
真正麻烦的是密钥派生时盐值(salt)没保存或 IV 被意外覆盖——这两个值一旦丢失,密文基本不可逆。别省那几字节存储空间。










