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

.NET Core6/7中UniversalCryptoDecryptor解密密码截断问题求助

RijndaelManaged解密在.NET Core 6/7中仅返回前16字节的修复方案

问题背景

我们的RijndaelManaged解密代码在.NET Core 5中运行正常,但升级到.NET Core 6或7后,解密结果出现截断,只能获取前16字节的明文。相关细节:

  • .NET 5使用Internal.Cryptography.UniversalCryptoDecryptor,.NET 6/7改用System.Security.Cryptography.UniversalCryptoDecryptor后出现解密截断问题。
  • 观察到新版本中Rfc2898DeriveBytes._salt内部缓冲区从16字节扩展到20字节,.NET 5中填充[0 0 0 1],.NET 7中填充[0 0 0 0],但这属于内部实现细节。
  • 密钥派生使用HMAC-SHA1算法。
  • 由于Azure已停止支持.NET 5,问题修复非常紧急。

问题根源

代码中依赖CryptoStream.Read()一次性读取所有解密字节的方式存在隐患。在.NET 6+的UniversalCryptoDecryptor实现中,Read()方法不会单次返回全部解密数据——尤其是当块大小为256位(32字节)时,仅返回第一个块的16字节是因为读取逻辑的变化,必须循环读取直到流结束,不能依赖单次调用获取完整结果。

另外,RijndaelManaged在.NET 6+中已被标记为过时,若块大小为128位,推荐改用Aes类;如果必须保留Rijndael的256位块大小,需确保读取流的方式正确。

修复后的解密代码

public static string Decrypt(string cipherText, int BLOCKSIZE, int KeySize) 
{
    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);
        
        // 若块大小为128,推荐改用Aes.Create(),更符合.NET 6+最佳实践
        using (var rijndael = new RijndaelManaged())
        {
            rijndael.BlockSize = BLOCKSIZE;
            rijndael.Mode = CipherMode.CBC;
            rijndael.Padding = PaddingMode.PKCS7;

            using (var decryptor = rijndael.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读取完整解密流,避免单次Read的截断问题
                return streamReader.ReadToEnd();
            }
        }
    }
}

关键修复点

  • 替换CryptoStream.Read()单次调用为StreamReader.ReadToEnd(),确保读取完整的解密流,适配.NET 6+的解密器逻辑。
  • 简化cipherTextBytes提取逻辑,直接Skip后ToArray()即可,无需额外Take。
  • 移除不必要的Close()调用,using语句会自动释放资源。

如果必须手动处理字节流(而非用StreamReader),可改用循环读取方式:

using (var memoryStream = new MemoryStream(cipherTextBytes))
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
{
    List<byte> plainTextBytes = new List<byte>();
    int readBytes;
    byte[] buffer = new byte[1024];
    while ((readBytes = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        plainTextBytes.AddRange(buffer.Take(readBytes));
    }
    return Encoding.UTF8.GetString(plainTextBytes.ToArray());
}

内容的提问来源于stack exchange,提问作者jakob gaardsted

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 18:35:08