.NET 6升级后RijndaelManaged加密数据无法正常解密如何解决
故障根因
你遇到的解密失败问题和RijndaelManaged过时没有关系,核心原因是**.NET 6对Rfc2898DeriveBytes的默认哈希算法做了破坏性变更**:
- .NET 5及更早版本默认使用
HashAlgorithmName.SHA1生成密钥 - .NET 6+默认改为
HashAlgorithmName.SHA256,导致相同密码、盐值生成的密钥完全不一致,自然解密失败
另外纠正你的认知误区:AES是Rijndael算法的标准子集,你当前代码里RijndaelManaged设置的BlockSize=128、CipherMode.CBC、PaddingMode.PKCS7完全符合AES标准,使用Aes.Create()替换不会有任何历史数据兼容问题。
修复方案
按以下步骤修改代码即可同时解决过时警告+历史数据解密问题:
- 所有
Rfc2898DeriveBytes初始化时显式指定哈希算法为SHA1,和老版本逻辑对齐 - 用
Aes.Create()替换RijndaelManaged,参数保持不变 - 用更安全的
RandomNumberGenerator替代已过时的RNGCryptoServiceProvider
修改后的完整代码如下:
private const int Keysize = 128; private const int DerivationIterations = 10000; public string Encrypt(string plainText, string passPhrase) { var saltStringBytes = GenerateBitsOfRandomEntropy(16); var ivStringBytes = GenerateBitsOfRandomEntropy(16); var plainTextBytes = Encoding.UTF8.GetBytes(plainText); // 显式指定SHA1和.NET5逻辑对齐 using var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations, HashAlgorithmName.SHA1); var keyBytes = password.GetBytes(Keysize / 8); // 替换为Aes.Create,参数完全兼容原有RijndaelManaged配置 using var symmetricKey = Aes.Create(); symmetricKey.BlockSize = 128; symmetricKey.Mode = CipherMode.CBC; symmetricKey.Padding = PaddingMode.PKCS7; using var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes); using var memoryStream = new MemoryStream(); using var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write); cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); cryptoStream.FlushFinalBlock(); var cipherTextBytes = saltStringBytes.Concat(ivStringBytes).Concat(memoryStream.ToArray()).ToArray(); return Convert.ToBase64String(cipherTextBytes); } public string Decrypt(string cipherText, string passPhrase) { var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText); var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray(); var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray(); var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).ToArray(); // 显式指定SHA1和.NET5逻辑对齐 using var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations, HashAlgorithmName.SHA1); var keyBytes = password.GetBytes(Keysize / 8); // 替换为Aes.Create,参数完全兼容原有RijndaelManaged配置 using var symmetricKey = Aes.Create(); symmetricKey.BlockSize = 128; symmetricKey.Mode = CipherMode.CBC; symmetricKey.Padding = PaddingMode.PKCS7; using var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes); using var memoryStream = new MemoryStream(cipherTextBytes); using var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read); using var streamReader = new StreamReader(cryptoStream, Encoding.UTF8); // 用StreamReader更简单可靠,避免手动处理字节计数的问题 return streamReader.ReadToEnd(); } private static byte[] GenerateBitsOfRandomEntropy(int size) { var randomBytes = new byte[size]; // 替换过时的RNGCryptoServiceProvider RandomNumberGenerator.Fill(randomBytes); return randomBytes; }
验证说明
修改后:
- 所有.NET5时期加密的历史数据均可正常解密
- 新加密的数据逻辑和原有逻辑完全一致,无兼容性问题
- 所有过时API警告全部消除,符合.NET6+的编码规范
内容的提问来源于stack exchange,提问作者Arzu Suleymanov
相关产品推荐
相关产品推荐

