读取时链接的GZipStream/DeflateStream和CryptoStream(AES)中断 [英] Chained GZipStream/DeflateStream and CryptoStream (AES) breaks when reading

查看:64
本文介绍了读取时链接的GZipStream/DeflateStream和CryptoStream(AES)中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想压缩然后加密我的数据,并且为了提高速度(不必写字节数组并返回),决定将用于压缩和加密的流链接在一起.

I want to compress and then encrypt my data, and for improved speed (by not having to write to byte arrays and back) decided to chain the streams used for compression and encryption together.

当我写入(压缩和加密)数据时,它可以完美工作,但是当我尝试读取数据(解压缩和解密)时,Read操作会中断–只需调用一次Read即可精确读取0字节,因为第一个Read总是返回0.如下所示,循环几乎可以正常工作,除了在特定时刻,Read停止返回大于0的任何值,即使仍有数据需要读取.

It works perfectly when I write (compress and encrypt) the data, but when I try to read the data (decompress and decrypt), the Read operation breaks - simply calling Read once reads exactly 0 bytes, because the first Read always returns 0. Looping as in the below code almost works, except that at a certain point, Read stops returning anything > 0 even though there's still data to be read.

将最后几个字节之前的所有内容都解压缩并完美解密.

Everything before those last few bytes are decompressed and decrypted perfectly.

对于相同的明文,发生这种情况时剩下的字节数保持不变;例如,某个字符串始终为9个字节,而另一个字符串始终为1个字节.

The number of bytes left when that happens remains the same for the same plaintext; for example, it's always 9 bytes for a certain string, but always 1 byte for another.

以下是相关的加密和解密代码;关于可能出什么问题的任何想法?

The following is the relevant encryption and decryption code; any ideas as to what could be going wrong?

加密:

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
    using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
    using (DeflateStream zip = new DeflateStream(csEncrypt, CompressionMode.Compress, true))
    {
        zip.Write(stringBytes, 0, stringBytes.Length);
        csEncrypt.FlushFinalBlock();

解密:

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream())
{
    // Writes the actual data (sans prepended headers) to the stream
    msDecrypt.Write(stringBytes, prependLength, stringBytes.Length - prependLength);
    // Reset position to prepare for read
    msDecrypt.Position = 0;
    // init buffer to read to
    byte[] buffer = new byte[originalSize];

    using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
    using (DeflateStream zip = new DeflateStream(csDecrypt, CompressionMode.Decompress))
    {
        // Hangs with "offset" at a small, deterministic number away from originalSize (I've gotten 9 less and 1 less for different strings)
        // Loop fixed as per advice
        int offset = 0;
        while (offset < originalSize)
        {
            int read = zip.Read(buffer, offset, originalSize - offset);
            if (read > 0)
                offset += read;
            else if (read < 0)
                Console.WriteLine(read); // Catch it if it happens.
        }
        // Hangs with "left" at a small, deterministic number (I've gotten 9 and 1 for different strings)
        /*
        for (int left = buffer.Length; left > 0; )
            left -= zip.Read(buffer, 0, left);
        */

解决方案(对加密的修改):

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
    using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
    {
        using (DeflateStream zip = new DeflateStream(csEncrypt, CompressionMode.Compress, true))
            zip.Write(stringBytes, 0, stringBytes.Length);
        //Flush after DeflateStream is disposed.
        csEncrypt.FlushFinalBlock();

推荐答案

问题出在以下几行:

csEncrypt.FlushFinalBlock();

如果删除它,代码将起作用.

If you remove that, the code will work.

原因是,当您写入 DeflateStream 时,并非所有数据都被写入基础流.仅当您通过离开 using 块来显式或隐式调用 Close() Dispose()时,才会发生这种情况.

The reason is that when you write to DeflateStream, not all data is written to the underlying stream. That happens only when you call Close() or Dispose() explicitly or implicitly by leaving the using block.

所以在您的代码中,会发生这种情况:

So in your code, this happens:

  1. Write()将所有数据写入 DeflateStream ,后者又将大部分数据写入基础的CryptoStream .
  2. 您调用 csEncrypt.FlushFinalBlock(),它会关闭 CryptoStream .
  3. 您将保留 DeflateStream using 块,该块尝试将其余数据写入已关闭的 CryptoStream 中.
  4. li>
  5. 您将离开 CryptoStream using 块,如果尚未调用,它将调用 FlushFinalBlock().
  6. li>
  1. You Write() all of the data to the DeflateStream, which in turn writes most of the data to the underlying CryptoStream.
  2. You call csEncrypt.FlushFinalBlock(), which closes the CryptoStream.
  3. You leave the using block of the DeflateStream, which tries to write the rest of the data to the already closed CryptoStream.
  4. You leave the using block of the CryptoStream, which would call FlushFinalBlock(), if it wasn't called already.

正确的事件顺序是:

  1. Write()将所有数据写入 DeflateStream ,然后依次将大部分数据写入基础 CryptoStream .
  2. 您将保留 DeflateStream using 块,该块会将其余数据写入已关闭的 CryptoStream .
  3. 您离开 CryptoStream using 块,该块调用 FlushFinalBlock().
  1. You Write() all of the data to the DeflateStream, which in turn writes most of the data to to the underlying CryptoStream.
  2. You leave the using block of the DeflateStream, which writes the rest of the data to the already closed CryptoStream.
  3. You leave the using block of the CryptoStream, which calls FlushFinalBlock().

尽管我希望写入封闭流会失败,但会出现异常.我不确定为什么不会发生这种情况.

Although I would expect that writing to a closed stream would fail with an exception. I'm not sure why that doesn't happen.

这篇关于读取时链接的GZipStream/DeflateStream和CryptoStream(AES)中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆