C#中AES加密解密需用Aes类配CBC模式和PKCS7填充,密钥长16/24/32字节、IV固定16字节且须随机生成并随密文保存;推荐Rfc2898DeriveBytes派生密钥,严禁重用IV或使用ECB模式。

在C#中使用AES加密和解密字符串,核心是利用 Aes 类(推荐)或已过时但仍可用的 RijndaelManaged,配合合适的模式(如CBC)、填充方式(如PKCS7)和密钥派生方法(如Rfc2898DeriveBytes)。关键不是“写个算法”,而是安全地配置参数、管理密钥与IV,并正确处理字节数组与字符串编码。
准备密钥和初始化向量(IV)
AES要求密钥长度为128、192或256位(即16、24、32字节),IV长度固定为16字节。不建议硬编码或重复使用同一IV。推荐用随机生成 + 与密文一起保存的方式:
- 加密前调用
Aes.GenerateKey()和Aes.GenerateIV()获取安全随机值 - IV无需保密,通常与密文拼接(如前16字节是IV,后面是密文),解密时先拆分再使用
- 若需从口令派生密钥(如用户输入密码),用
Rfc2898DeriveBytes迭代10万次以上,盐值也应随机生成并保存
使用AES进行加密(CBC + PKCS7)
以下是一个简洁可靠的加密方法示例(UTF-8编码,Base64输出):
public static string Encrypt(string plainText, byte[] key, byte[] iv)
{
using var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using var encryptor = aes.CreateEncryptor();
var plainBytes = Encoding.UTF8.GetBytes(plainText);
var cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
// 将 IV 和密文合并,转为 Base64
return Convert.ToBase64String(iv.Concat(cipherBytes).ToArray());
}
对应解密逻辑(必须用相同key/iv/模式/填充)
解密时先从Base64还原字节数组,提取前16字节为IV,剩余为密文:
public static string Decrypt(string encryptedBase64, byte[] key)
{
var fullBytes = Convert.FromBase64String(encryptedBase64);
var iv = fullBytes.Take(16).ToArray();
var cipherBytes = fullBytes.Skip(16).ToArray();
using var aes = Aes.Create();
aes.Key = key;
aes.IV = iv;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
using var decryptor = aes.CreateDecryptor();
var plainBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
return Encoding.UTF8.GetString(plainBytes);
}
安全提醒与常见坑
实际项目中容易忽略但至关重要的点:
- 永远不要重用IV:同一密钥下重复IV会严重削弱安全性,尤其在CBC模式中
-
密钥不能直接用字符串当字节数组:比如
"mykey123"转成字节只有8字节,不满足AES-128最低要求;应通过PBKDF2派生或使用密码生成器生成合规密钥 - 避免使用ECB模式:它不加IV、不隐藏数据模式,已不被推荐
- 注意编码一致性:加密用UTF-8,解密也必须用UTF-8,否则中文等字符会乱码
基本上就这些。AES本身不难,难点在于参数配置合理、密钥生命周期管理得当、以及把二进制操作和字符串转换做对。










