aes加密需严格管控iv、key、mode、padding四要素;aes.create()每次生成随机key/iv,必须手动设置或保存;iv须16字节唯一且拼接于密文前;key须16/24/32字节,推荐rfc2898derivebytes派生;解密失败优先核对mode、padding、blocksize及base64解码后长度。

AES加密在C#里不是调个函数就能用的,关键得管住IV、Key、Mode、Padding四样东西——漏一个,解密就直接抛CryptographicException。
为什么Aes.Create()返回的对象不能直接加密后解密
因为Aes.Create()每次返回的新实例都自带随机Key和随机IV,你加密完根本记不住它用了啥。生产环境必须自己控制这两个值:Key保密复用,IV每次随机但要保存下来。
- 不显式设置
aes.Key,.NET会自动生成一个(但你拿不到) - 不显式设置
aes.IV,它也会随机生成,但下次Aes.Create()又换一套 - 所以必须手动赋值
aes.Key和aes.IV,或调用aes.GenerateIV()后立刻存走aes.IV - .NET 6+建议写成:
var aes = Aes.Create() ?? new AesManaged();,防旧环境返回null
CipherMode.CBC下IV怎么生成和拼接才不出错
IV必须是16字节、每次加密唯一、可明文传输——但绝不能硬编码或重复用。常见错误是把"1234567890123456"这种字符串当IV,它UTF8编码后长度可能不对,且毫无随机性。
- 正确做法:
aes.GenerateIV(),然后立刻用aes.IV参与加密 - 密文输出时,把16字节IV拼在密文最前面,再一起Base64:
Convert.ToBase64String(iv.Concat(cipherBytes).ToArray()) - 解密时先Base64解码,取前16字节为IV,剩下的是密文
- 别用
Encoding.UTF8.GetBytes("my_iv")——长度难控,也不够随机
Key长度和派生方式直接影响能否加密成功
Key字节数不对,CryptographicException: Specified key is not a valid size for this algorithm立马报给你看。AES-128要16字节,AES-256要32字节,差一个字节都不行。
- 禁用
Encoding.UTF8.GetBytes("mykey123")这种硬编码——它只有9字节,补零或截断都不可靠 - 推荐用
Rfc2898DeriveBytes从口令派生Key:new Rfc2898DeriveBytes(password, salt, 100_000, HashAlgorithmName.SHA256) - 派生后调
rd.GetBytes(32)拿32字节(对应AES-256),别忘了salt也得存/传 - 如果直接给定原始密钥字节数组,确保
key.Length == 16 || 24 || 32
解密失败时最该检查的三件事
“Bad Data”、“Padding is invalid”、“Length of the data to decrypt is invalid”这些异常,99%不是算法问题,而是两端参数没对齐。
- 打印并比对两端的
aes.Mode(必须都是CipherMode.CBC)、aes.Padding(推荐Pkcs7)、aes.BlockSize(固定128) - 确认Base64解码后字节数组长度是16的整数倍——如果不是,说明IV没拆对,或密文被截断/损坏
- 检查字符串编码:加密用
Encoding.UTF8.GetBytes(),解密后就得用Encoding.UTF8.GetString(),混用ASCII会崩中文
IV和Key的生命周期管理比算法本身更关键:IV可以扔在密文里,Key必须进密钥库或环境变量;GCM模式虽好,但.NET Core 3.0以前得靠BouncyCastle,老项目慎上。











