升级至.NET 6后自定义字符串加解密类解密结果被截断问题求助
问题根因
该问题由.NET 6中CryptoStream.Read方法的行为变更导致:
- .NET 5及更早版本中,
CryptoStream.Read会一次性返回所有解密完成的字节,单次调用即可读取全部明文 - .NET 6开始,
CryptoStream遵循标准流的语义规范,Read方法仅保证至少返回1个字节,不保证一次返回全部可用数据。原代码仅调用了一次Read,因此只拿到了第一个AES块(128位=16字节)对应的明文,后续剩余数据未被读取,最终出现截断。
修复方案
修改Decrypt方法中的解密读取逻辑,确保读取完CryptoStream中的全部数据即可,推荐以下两种实现方式:
方案1:使用CopyTo简化读取(代码更简洁)
public static 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(); using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) { var keyBytes = password.GetBytes(Keysize / 8); 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 resultStream = new MemoryStream()) { cryptoStream.CopyTo(resultStream); return Encoding.UTF8.GetString(resultStream.ToArray()); } } } } } } }
方案2:循环调用Read直到无数据返回
如果需要手动控制读取过程,可循环调用Read直到返回值为0:
public static 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(); using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations)) { var keyBytes = password.GetBytes(Keysize / 8); 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)) { var plainTextBytes = new byte[cipherTextBytes.Length]; int totalDecryptedBytes = 0; int decryptedByteCount; // 循环读取直到没有更多数据 while ((decryptedByteCount = cryptoStream.Read(plainTextBytes, totalDecryptedBytes, plainTextBytes.Length - totalDecryptedBytes)) > 0) { totalDecryptedBytes += decryptedByteCount; } return Encoding.UTF8.GetString(plainTextBytes, 0, totalDecryptedBytes); } } } } } }
两种方案修改后,.NET 5和.NET 6下的解密结果就会完全一致,不会再出现截断问题。
内容的提问来源于stack exchange,提问作者Optim
相关产品推荐
相关产品推荐

