加密必须规范密钥管理、模式选择与编码处理:禁用硬编码密钥和ECB模式,生产用CNG或Azure Key Vault,开发可用ProtectedData;密钥派生用PBKDF2并随机盐值;推荐GCM模式,CBC需随机IV并PKCS7填充;数据库加密应Base64编码后存varchar/varbinary;解密失败多因KeySize、IV或编码不一致。

加密前必须确认密钥管理方式
硬编码密钥或把密钥写进配置文件是常见错误,Aes.Create() 生成的随机密钥一旦丢失就无法解密。生产环境必须用 Windows CNG(如 CngKey)或 Azure Key Vault 管理主密钥,本地开发可临时用 ProtectedData(仅 Windows)封装对称密钥:
-
ProtectedData.Protect()只能在同一用户、同一机器解密,适合单机桌面应用 - 不要用
MD5或SHA1衍生密钥——它们不是密钥派生函数,改用Rfc2898DeriveBytes(PBKDF2) - 盐值(salt)必须每次加密时随机生成并和密文一起存储,不能复用
选对 AES 模式和填充:别用 ECB,慎用 CBC
AesCryptoServiceProvider 默认是 CBC 模式,但需要手动管理 IV(初始化向量)。ECB 模式绝对禁用——相同明文块加密后完全一致,会暴露数据模式。
- IV 必须随机生成(
Aes.GenerateIV()),且和密文一起持久化(比如拼在密文前或存单独字段) - 推荐用
GCM模式(AesGcm类,.NET Core 3.0+ / .NET 5+),它自带认证标签,能防篡改,无需额外 HMAC - 如果必须用 CBC,填充必须设为
PaddingMode.PKCS7(.NET 默认),别用None——否则解密会抛CryptographicException: Padding is invalid
数据库字段加密:避免直接加密整个字段
直接加密 string 再存进 nvarchar 字段,容易因编码/截断出错。更稳妥的做法是:
- 加密后用
Convert.ToBase64String()转成 ASCII 字符串,存进varchar或varbinary字段(后者更省空间) - 敏感字段如密码、身份证号,优先走哈希(
HashAlgorithmName.SHA256+Rfc2898DeriveBytes),而非可逆加密 - 若需模糊查询(如手机号前缀匹配),不能加密完整字段,得用
detached encryption或字段级加盐哈希,或引入可信执行环境(TEE)方案
解密失败的三个高频原因
解密报错常被归为“密钥不对”,其实更多是上下文不一致:
- 加密和解密用的
KeySize不同(如一个用 128,一个用 256)→ 抛CryptographicException: The specified key is not a valid size - IV 被截断或 Base64 解码失败 → 解密后乱码或长度异常
- 加密时用了 UTF-8 编码字符串,解密后却按 UTF-16 解析字节数组 → 出现
符号或ArgumentException: Illegal characters in path
最保险的做法:加密时把 key、iv、plaintext 的编码方式、PaddingMode 全部记录日志(脱敏后),出问题时比对上下文。










