.NET 6 Stream 读取中断更改或错误?

.NET 6 Stream reading breaking change or bug?

我目前正在从 .NET Core 3.1 升级到 .NET 6,我遇到了重大变化或奇怪的行为。

这是我的代码,在 .NET Core 3.1 中完美运行:

public static byte[] Decrypt<SymmetricAlgorithmType>(byte[] securedData, SymmetricEncryptionOptions symetricEncryptionOptions)
    where SymmetricAlgorithmType : SymmetricAlgorithm, new()
{

    SymmetricAlgorithm symetric = new SymmetricAlgorithmType
    {
        Key = symetricEncryptionOptions.Key,
        IV = symetricEncryptionOptions.InitializationVector
    };

    byte[] bytes = new byte[securedData.Length];

    MemoryStream? memoryStream = new MemoryStream(securedData);
    CryptoStream encryptionStream = new CryptoStream(memoryStream, symetric.CreateDecryptor(), CryptoStreamMode.Read);
    int realBytes = encryptionStream.Read(bytes, 0, bytes.Length);
    encryptionStream.Close();
    byte[] realByteArray = new byte[realBytes];
    Array.Copy(bytes, realByteArray, realBytes);
    return realByteArray;

}

当运行在我的单元测试中,使用一些示例数据,securedData的大小是32。实际读取的字节数是23(也可以在realBytes中看到变量)并将它们放入正确大小的 realByteArray 中。

运行 .NET 6 中的代码完全相同,我现在得到 16 而不是 23,这会裁剪内容。

所以我想,我重写了代码以创建一个 while 循环,该循环在读取到 0 个字节之前中断:

MemoryStream? memoryStream = new MemoryStream(securedData);
CryptoStream encryptionStream = new CryptoStream(memoryStream, symetric.CreateDecryptor(), CryptoStreamMode.Read);

byte[] buffer = new byte[securedData.Length];
int totalRead = 0;
while (totalRead < buffer.Length)
{
    int bytesRead = encryptionStream.Read(buffer, totalRead, 16);
    if (bytesRead == 0)
    {
        break;
    }

    totalRead += bytesRead;
}
return buffer;

所以在第一个 运行 上,我得到 16 个字节,第二个 运行 returns 7 个字节,但是一旦第三次循环 运行s ,我得到异常:

System.ArgumentOutOfRangeException: 'Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. (Parameter 'count')'

上面看到的代码是根据下面的文章,其中提到了 .NET 6 中的重大变化: https://docs.microsoft.com/en-US/dotnet/core/compatibility/core-libraries/6.0/partial-byte-reads-in-streams

到目前为止,我唯一的解决方法是逐字节读取它。所以相同的代码,如上所示,但使用:1 而不是 16encryptionStream.Read(buffer, totalRead, 1);

请注意,我将 System.Security.Cryptography.RijndaelManaged 用作 SymmetricAlgorithm,将 16 字节数组用作键,将 16 字节数组用作 IV,并且 CryptoStream 不支持 SeekSlice.

所以我想知道这是 .NET 6 中的错误还是我现在做的事情完全错误,但在 .NET Core 3 中没问题?

错误是你的。

从任何 Read 调用返回的字节数是一个实现细节 - 它必须是 somethingnothing(结束语)。所以数字 changing: 很好。然而,问题就在这里:

int bytesRead = encryptionStream.Read(buffer, totalRead, 16);

参数仍然需要有效,但当您接近缓冲区末尾时它们不是有效的。考虑一下:

int bytesRead = encryptionStream.Read(buffer, totalRead, buffer.Length - totalRead);

现在它总是说“尽可能多地填充缓冲区”,而不是“最多读取 16 个字节,无论缓冲区中还剩多少 space”。