.NET Core 6与.NET 4.5上ASP.NET MVC的加解密差异及适配问题
.NET 6与.NET 4.5解密结果不一致的修复方案
问题根源
- PasswordDeriveBytes实现差异:.NET Framework 4.5中的
PasswordDeriveBytes默认使用PBKDF1算法,而.NET 6中该类已过时且内部改用PBKDF2,导致生成的密钥字节数组完全不同。 - CryptoStream.Read行为变化:.NET 6中
CryptoStream.Read不会一次性返回所有解密数据,单次调用仅读取部分字节,直接导致解密内容不完整。 - RijndaelManaged已过时:.NET 6中
RijndaelManaged被标记为过时,官方推荐使用标准Aes算法实现,避免潜在的兼容性问题。
具体修改步骤
1. 替换PasswordDeriveBytes为兼容的PBKDF1实现
由于.NET 6不再原生支持PBKDF1的密钥生成逻辑,需要手动实现匹配.NET 4.5的PBKDF1流程:
// 替换原PasswordDeriveBytes代码段 byte[] salt = Array.Empty<byte>(); // 对应原代码salt为null的情况 int iterations = 100; // .NET 4.5 PasswordDeriveBytes默认迭代次数 using (HashAlgorithm hashAlgorithm = SHA1.Create()) { byte[] passPhraseBytes = Encoding.UTF8.GetBytes(passPhrase); byte[] combinedBytes = new byte[passPhraseBytes.Length + salt.Length]; passPhraseBytes.CopyTo(combinedBytes, 0); salt.CopyTo(combinedBytes, passPhraseBytes.Length); byte[] hash = hashAlgorithm.ComputeHash(combinedBytes); for (int i = 1; i < iterations; i++) { hash = hashAlgorithm.ComputeHash(hash); } byte[] keyBytes = new byte[keysize / 8]; Array.Copy(hash, keyBytes, keyBytes.Length); // 后续密钥使用逻辑不变 }
2. 修复CryptoStream.Read的读取逻辑
将单次读取改为循环读取或使用CopyTo方法,确保获取全部解密字节:
// 替换原CryptoStream内的读取代码段 using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes)) using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) using (MemoryStream plainStream = new MemoryStream()) { cryptoStream.CopyTo(plainStream); decryptedArray.Add(Encoding.UTF8.GetString(plainStream.ToArray())); }
或者使用循环读取的方式:
byte[] plainTextBytes = new byte[cipherTextBytes.Length]; int totalBytesRead = 0; int bytesRead; while ((bytesRead = cryptoStream.Read(plainTextBytes, totalBytesRead, plainTextBytes.Length - totalBytesRead)) > 0) { totalBytesRead += bytesRead; } decryptedArray.Add(Encoding.UTF8.GetString(plainTextBytes, 0, totalBytesRead));
3. 替换RijndaelManaged为Aes算法
使用.NET 6推荐的Aes.Create()替代过时的RijndaelManaged,保持参数配置与原代码一致:
// 替换原RijndaelManaged代码段 using (Aes symmetricKey = Aes.Create()) { symmetricKey.Mode = CipherMode.CBC; symmetricKey.Key = keyBytes; symmetricKey.IV = initVectorBytes; symmetricKey.Padding = PaddingMode.PKCS7; // 匹配RijndaelManaged默认填充模式 // 后续解密逻辑不变 }
完整修改后的Decrypt方法
public static Dictionary<string, string> Decrypt(string[] cipherTexts, string passPhrase) { var decryptedValues = new Dictionary<string, string>(); if (cipherTexts == null || cipherTexts.Length == 0 || string.IsNullOrEmpty(passPhrase)) { return decryptedValues; } cipherTexts = cipherTexts.Where(q => !string.IsNullOrEmpty(q)) .Distinct().ToArray(); byte[] salt = Array.Empty<byte>(); int iterations = 100; using (HashAlgorithm hashAlgorithm = SHA1.Create()) { byte[] passPhraseBytes = Encoding.UTF8.GetBytes(passPhrase); byte[] combinedBytes = new byte[passPhraseBytes.Length + salt.Length]; passPhraseBytes.CopyTo(combinedBytes, 0); salt.CopyTo(combinedBytes, passPhraseBytes.Length); byte[] hash = hashAlgorithm.ComputeHash(combinedBytes); for (int i = 1; i < iterations; i++) { hash = hashAlgorithm.ComputeHash(hash); } byte[] keyBytes = new byte[keysize / 8]; Array.Copy(hash, keyBytes, keyBytes.Length); using (Aes symmetricKey = Aes.Create()) { symmetricKey.Mode = CipherMode.CBC; symmetricKey.Key = keyBytes; symmetricKey.IV = initVectorBytes; symmetricKey.Padding = PaddingMode.PKCS7; using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor()) { foreach (var cipherTextOrig in cipherTexts) { var cipherTextFixed = cipherTextOrig.Trim(',').Replace("-", "+").Replace("_", "/"); var decryptedArray = new List<string>(); foreach (var cipherText in cipherTextFixed.Split(',')) { byte[] cipherTextBytes = Convert.FromBase64String(cipherText); using (MemoryStream memoryStream = new MemoryStream(cipherTextBytes)) using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)) using (MemoryStream plainStream = new MemoryStream()) { cryptoStream.CopyTo(plainStream); decryptedArray.Add(Encoding.UTF8.GetString(plainStream.ToArray())); } } decryptedValues.Add(cipherTextOrig, string.Join(",", decryptedArray)); } } } } return decryptedValues; }
注意:需确保keysize和initVectorBytes的定义与原.NET 4.5代码完全一致,否则仍会出现解密结果差异。
内容的提问来源于stack exchange,提问作者pikk
相关产品推荐
相关产品推荐

