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

当我写入(压缩和加密)数据时,它可以完美工作,但是当我尝试读取数据(解压缩和解密)时,Read操作会中断-只需调用一次Read即可精确读取0字节,因为第一个Read始终返回0。像下面的代码中那样循环几乎可以工作,除了在特定点上,Read会停止返回大于0的任何值,即使仍然有要读取的数据也是如此。

最后几个字节之前的所有内容均经过完美解压缩和解密。

对于相同的明文,剩下的字节数保持不变。例如,某个字符串始终为9个字节,而另一个字符串始终为1个字节。

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

加密:

// 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();

如果您删除了该代码,则该代码将起作用。

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

因此,在您的代码中,会发生以下情况:
  • 您将所有数据Write()编码为DeflateStream,后者又将大多数数据写入底层的CryptoStream
  • 您调用csEncrypt.FlushFinalBlock(),它将关闭CryptoStream
  • 您将保留usingDeflateStream块,该块尝试将其余数据写入已经关闭的CryptoStream中。
  • 如果尚未调用using,则保留CryptoStreamFlushFinalBlock()块,它将调用Write()

  • 正确的事件顺序是:
  • 您将所有数据DeflateStream编码为CryptoStream,后者又将大多数数据写入基础using
  • 离开DeflateStreamCryptoStream块,该块将其余数据写入已经关闭的using中。
  • 您将离开CryptoStreamFlushFinalBlock()块,该块将调用ojit_code。

  • 尽管我希望写入封闭流会因异常而失败。我不确定为什么不会发生这种情况。

    关于c# - 读取时链接的GZipStream/DeflateStream和CryptoStream(AES)中断,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6802398/

    10-13 08:08