AES加解密必须手动管理IV和Key:IV需每次唯一且16字节,Key须保密并严格匹配16/24/32字节;禁用ECB,推荐CBC或GCM;注意编码一致、填充自动处理、GCM的nonce为12字节及tag完整性校验。

AES加解密必须手动管理IV和Key,不能只靠Aes.Create()默认值
用Aes.Create()拿到的实例默认使用随机IV和随机Key,每次调用都不同——这意味着你加密后根本没法解密。生产环境里,IV可以公开但必须每次唯一(推荐用CryptographicRandomNumberGenerator生成),Key必须严格保密且固定复用。
- IV长度必须是16字节(AES-128/192/256都一样),
IV.Length != 16会直接抛CryptographicException - Key长度取决于AES模式:
Key.Length == 16(AES-128)、24(AES-192)或32(AES-256),错一个字节就报错 - 别把IV拼在密文开头再Base64——虽然常见,但得自己拆分;更稳妥的做法是用
MemoryStream写入IV+密文,解密时先读16字节当IV
ECB模式看着简单但绝对不能用
Aes.Mode = CipherMode.ECB会让相同明文块始终加密成相同密文块,攻击者能靠观察密文模式反推内容(比如银行卡号前6位固定,对应密文前两块永远一样)。所有合规场景都该用CipherMode.CBC或CipherMode.GCM。
- CBC需要IV且必须随机,解密时IV错一位整个明文就全乱
- GCM自带认证标签(
Tag),能防篡改,但.NET Core 3.0+才原生支持AesGcm类,旧版本得用BouncyCastle - 别手动实现PKCS#7填充——
Aes.Padding = PaddingMode.PKCS7就行,设成None会导致CryptographicException: Length of the data to encrypt is invalid
字符串编码不一致会导致解密后乱码或解密失败
加密操作处理的是byte[],不是字符串。从string转byte[]用Encoding.UTF8.GetBytes(),解密后还原也得用Encoding.UTF8.GetString()——如果加密用UTF8、解密用ASCII,中文直接变。
- 密钥字符串同样要编码:用
Convert.FromBase64String("...")或Encoding.UTF8.GetBytes("mykey123..."),但后者实际只有前16/24/32字节有效,多余部分被截断 - Base64编码密文时,记得用
Convert.ToBase64String(cipherBytes),别漏掉ToString()这种错误写法 - 空字符串
""加密后不是零长度——它会被填充成一块(PKCS#7下至少16字节),解密后还是"",这点容易误判逻辑
.NET 5+推荐直接用AesGcm,但要注意平台限制
AesGcm比AesCbc多一层完整性校验,解密时如果密文被篡改,Decrypt()会直接抛CryptographicException而不是返回垃圾数据。但它在Windows上依赖CNG,Linux/macOS需要OpenSSL 1.1.1+,.NET Framework完全不支持。
- 初始化向量(nonce)长度固定12字节,不是16字节,传错长度会崩
- 认证标签(tag)长度必须是16字节,
Encrypt()输出的tag必须和密文一起保存,缺一不可 - 同一个nonce绝不能重复用于不同明文,否则安全性归零——建议用
RandomNumberGenerator每次生成新nonce
加密本身不难,难的是IV怎么传、Key怎么存、编码怎么对、模式怎么选。尤其是跨服务或存数据库时,IV和密文的打包方式、Base64是否URL安全、时间戳要不要加进明文防重放——这些细节没对齐,两边就永远解不开。










