.NET 7解密加密字符串时出现内容截断问题求助
问题
将.NET Core 3.1中的字符串对称加解密代码迁移到.NET 7后,加密功能正常,但解密加密后的JSON字符串时,结果末尾会丢失6-8个字符;.NET Core 3.1中解密则能返回完整内容。加密结果在两个版本中一致,但解密结果存在差异。
原解密实现代码:
#region Settings private int _iterations = 2; private static int _keySize = 256; private string _hash = "SHA1"; private string _salt = "xxx"; // Random private string _vector = "xxx"; // Random #endregion public string Run(string data, string key) { var jsonstring = Decrypt(data, key); return jsonstring; } private string Decrypt(string value, string password) { return Decrypt<AesManaged>(value, password); } private string Decrypt<T>(string value, string password) where T : SymmetricAlgorithm, new() { byte[] vectorBytes = Encoding.UTF8.GetBytes(_vector); byte[] saltBytes = Encoding.UTF8.GetBytes(_salt); byte[] valueBytes = Convert.FromBase64String(value); byte[] decrypted; int decryptedByteCount = 0; using (T cipher = new T()) { PasswordDeriveBytes _passwordBytes = new PasswordDeriveBytes(password, saltBytes, _hash, _iterations); byte[] keyBytes = _passwordBytes.GetBytes(_keySize / 8); cipher.Mode = CipherMode.CBC; try { using (ICryptoTransform decryptor = cipher.CreateDecryptor(keyBytes, vectorBytes)) { using (MemoryStream from = new MemoryStream(valueBytes)) { using (CryptoStream reader = new CryptoStream(from, decryptor, CryptoStreamMode.Read)) { decrypted = new byte[valueBytes.Length]; decryptedByteCount = reader.Read(decrypted, 0, decrypted.Length); } } } } catch (Exception ex) { return String.Empty; } cipher.Clear(); } var decrypt = Encoding.UTF8.GetString(decrypted, 0, decryptedByteCount); return decrypt; }
原因分析
PasswordDeriveBytes跨版本行为差异:该类已被标记为过时,.NET 7与.NET Core 3.1中的实现存在细微差异,导致生成的密钥不完全一致,间接影响解密完整性。CryptoStream.Read单次调用的局限性:Read方法无法保证一次读取所有解密后的数据,.NET 7中CryptoStream的读取逻辑更严格,单次调用会导致部分末尾数据未被读取。
修复方案
1. 替换过时的密钥派生类
用Rfc2898DeriveBytes替代PasswordDeriveBytes,该类遵循PBKDF2标准,跨.NET版本行为一致,安全性更高。
2. 循环读取所有解密数据
不再依赖单次Read调用,改用CopyTo方法循环读取CryptoStream中的所有数据,确保解密内容完整。
修复后的解密方法代码:
private string Decrypt<T>(string value, string password) where T : SymmetricAlgorithm, new() { byte[] vectorBytes = Encoding.UTF8.GetBytes(_vector); byte[] saltBytes = Encoding.UTF8.GetBytes(_salt); byte[] valueBytes = Convert.FromBase64String(value); using (T cipher = new T()) { // 替换为Rfc2898DeriveBytes,参数与原逻辑对齐 var deriveBytes = new Rfc2898DeriveBytes(password, saltBytes, _iterations, HashAlgorithmName.SHA1); byte[] keyBytes = deriveBytes.GetBytes(_keySize / 8); cipher.Mode = CipherMode.CBC; try { using (ICryptoTransform decryptor = cipher.CreateDecryptor(keyBytes, vectorBytes)) using (MemoryStream from = new MemoryStream(valueBytes)) using (CryptoStream reader = new CryptoStream(from, decryptor, CryptoStreamMode.Read)) using (MemoryStream to = new MemoryStream()) { // 读取所有解密后的数据 reader.CopyTo(to); return Encoding.UTF8.GetString(to.ToArray()); } } catch (Exception ex) { return string.Empty; } } }
额外优化建议
- 同步更新加密逻辑中的密钥派生类为
Rfc2898DeriveBytes,确保新旧加密数据的密钥生成逻辑一致。 - 替换
AesManaged为Aes.Create(),AesManaged已过时,Aes.Create()能提供更好的跨版本兼容性与安全性。
内容的提问来源于stack exchange,提问作者Stefan
相关产品推荐
相关产品推荐

