AES CBC 128位加密后解密无法返回原始值,代码哪里出错了?
你的代码存在以下几个核心问题:
- Aes实例被提前释放:
GetAes方法中你给创建的Aes实例加了using声明,当方法返回时该实例就会被自动销毁,后续调用加密解密方法时访问已释放对象就会抛出异常,这是你去掉PaddingMode.Zeros配置后程序直接崩溃的根因。 - 加密结果读取时机错误:加密逻辑中你在
CryptoStream的using块内部就调用MemoryStream.ToArray(),此时CryptoStream还未完成最终块的刷新写入,拿到的加密数据是不完整的,自然无法正确解密。 - IV处理逻辑不严谨:AES-CBC模式要求IV长度必须等于AES块大小(16字节),你加密时传入空字节数组虽然会让Aes自动生成合法IV,但逻辑上存在隐患,且如果后续传入长度不符合要求的IV会直接报错。
PaddingMode.Zeros的固有缺陷:零填充不会在解密后自动移除填充的0字节,解密结果末尾会多出多余的空字符,同时如果明文长度刚好是块大小的整数倍,零填充不会追加额外块,也容易引发解析异常,默认的PaddingMode.PKCS7才是更通用、更安全的选择。- 编码逻辑不明确:代码中
keyText.ToByteArray()以及StreamWriter/StreamReader都没有显式指定编码,如果依赖系统默认编码,跨环境运行时可能出现密钥不匹配、明文乱码的问题。
修正方案
1. 修正GetAes方法
private static Aes GetAes(string keyText, byte[] iv) { // 显式指定UTF8编码转密钥字节,避免编码不一致问题 var key = Encoding.UTF8.GetBytes(keyText); // 移除错误的using声明,避免对象提前释放 var result = Aes.Create(); result.Mode = CipherMode.CBC; // 改用PKCS7填充,和官方标准实现对齐 result.Padding = PaddingMode.PKCS7; result.KeySize = 128; result.BlockSize = 128; result.Key = key; // 仅传入合法长度IV时才赋值,否则使用自动生成的安全IV if (iv.Length == result.BlockSize / 8) { result.IV = iv; } return result; }
2. 修正加密解密逻辑
public static AesEncryptionInfo EncryptWithAes(this string plainText, string keyText) { // 转移using声明到当前方法,Aes使用完成后再释放 using var aesAlg = GetAes(keyText, Array.Empty<byte>()); var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV); byte[] encrypted; using (var msEncrypt = new MemoryStream()) { using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { // 显式指定UTF8编码写入明文,和解密逻辑对齐 using (var swEncrypt = new StreamWriter(csEncrypt, Encoding.UTF8)) { swEncrypt.Write(plainText); } } // 移动ToArray到CryptoStream释放后,确保已写入完整加密数据 encrypted = msEncrypt.ToArray(); } return new AesEncryptionInfo(encrypted, aesAlg.IV); } public static string DecryptFromAes(this byte[] cipherText, string keyText, byte[] iv) { using var aesAlg = GetAes(keyText, iv); var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV); using (var msDecrypt = new MemoryStream(cipherText)) { using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) { // 显式指定UTF8编码读取明文,和加密逻辑对齐 using (var srDecrypt = new StreamReader(csDecrypt, Encoding.UTF8)) { return srDecrypt.ReadToEnd().TrimEnd('\0'); } } } }
修正后你原有调用代码可以直接运行,解密可以正常得到原始明文,也可以正常移除自定义的PaddingMode.Zeros配置不会触发崩溃。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

