You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级至.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 15:15:07