aes.create() 不是“拿来就能用”的黑盒,它每次返回新实例都带随机 key 和随机 iv,不手动设置就加密,解密时必然失败——不是乱码,是直接抛 cryptographicexception。

直接说结论:Aes.Create() 不是“拿来就能用”的黑盒,它每次返回新实例都带随机 Key 和随机 IV,不手动设置就加密,解密时必然失败——不是乱码,是直接抛 CryptographicException。
为什么 Aes.Create() 返回的对象不能直接加解密
因为它的默认行为是自动生成 Key 和 IV,你根本拿不到、也留不住。加密完关掉程序,下次 Aes.Create() 又是一个全新随机对,等于换锁换钥匙。
- 不显式赋值
aes.Key,它就用自己生成的(你无法获取) - 不显式赋值
aes.IV,它也会随机生成,但下次调用就失效 - 硬编码
new byte[16]或字符串"1234567890123456"当IV:前者全零可预测,后者 UTF-8 编码后长度可能不是 16 字节,且无随机性
Aes.Create() 在旧环境返回 null 怎么办
在 .NET Framework 4.5 以下、Unity IL2CPP 或部分 AOT 场景中,Aes.Create() 确实可能返回 null,这不是你代码错,是运行时没加载实现。
- 稳妥写法:
var aes = Aes.Create() ?? new AesManaged(); -
AesManaged是纯托管实现,跨平台可用,.NET 6+ 仍支持(虽标[Obsolete],但无替代) -
AesCryptoServiceProvider在 Linux/macOS 会抛PlatformNotSupportedException,别无脑替换
IV 和 Key 必须怎么生成才安全
IV 可公开但必须每次唯一;Key 必须保密且长度严格匹配——AES-256 要 32 字节,差一个字节就报 "Specified key is not a valid size"。
- 生成
IV:aes.GenerateIV(),然后立刻取aes.IV使用(别用Encoding.UTF8.GetBytes("xxx")) - 生成
Key:用Rfc2898DeriveBytes派生,例如new Rfc2898DeriveBytes(password, salt, 100_000, HashAlgorithmName.SHA256).GetBytes(32) -
IV必须 16 字节;Key必须是 16 / 24 / 32 字节之一;二者都必须用byte[]传入,别传字符串再转
解密失败最该检查的三件事
看到 "Padding is invalid"、"Bad Data"、"Length of the data to decrypt is invalid",99% 是参数没对齐,不是算法问题。
- 两端
aes.Mode是否一致(比如都是CipherMode.CBC) - 两端
aes.Padding是否一致(推荐显式设为Pkcs7) - 解密时是否准确提取了前 16 字节作为
IV(不是重新生成,也不是截断或错位)
最容易被忽略的是:Base64 解码后字节数组长度必须是 16 的整数倍,否则说明 IV 拼接或读取逻辑出错;还有文件加解密时误把 UTF-8 BOM 当作密文一部分读入——这种错误不会报密钥错,但会直接卡在块校验上。










