Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 链式GZipStream/deflatestStream和加密流(AES)在读取时中断_C#_.net_Encryption_C# 4.0_Compression - Fatal编程技术网

C# 链式GZipStream/deflatestStream和加密流(AES)在读取时中断

C# 链式GZipStream/deflatestStream和加密流(AES)在读取时中断,c#,.net,encryption,c#-4.0,compression,C#,.net,Encryption,C# 4.0,Compression,我想压缩然后加密我的数据,为了提高速度(不必写入字节数组并返回),我决定将用于压缩和加密的流链接在一起 当我写入(压缩和加密)数据时,它工作得很好,但当我尝试读取数据(解压缩和解密)时,读取操作中断-只需调用read one读取0个字节,因为第一次读取总是返回0。下面代码中的循环几乎可以工作,除了在某一点上,Read停止返回大于0的任何内容,即使仍有数据要读取 最后几个字节之前的所有内容都得到了完美的解压缩和解密 对于相同的纯文本,发生这种情况时剩余的字节数保持不变;例如,某个字符串总是9个字节

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

当我写入(压缩和加密)数据时,它工作得很好,但当我尝试读取数据(解压缩和解密)时,读取操作中断-只需调用read one读取0个字节,因为第一次读取总是返回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();
解密:

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

我最近在从远程流读取数据时遇到了类似的问题

对我来说,解决方案是将在单个调用中读取整个流的行更改为while循环:


远程流并不总是能够返回请求的数据量,因此请在读取足够字节的同时尝试读取流。

问题在于以下几行:

csEncrypt.FlushFinalBlock();
如果删除该选项,代码将正常工作

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

因此,在您的代码中,会发生以下情况:

  • 您可以
    Write()
    将所有数据写入
    DeflateStream
    ,而DeflateStream又将大部分数据写入底层
    加密流
  • 您可以调用
    csEncrypt.FlushFinalBlock()
    ,这将关闭
    加密流
  • 您使用
    DeflateStream
    块离开
    ,该块尝试将其余数据写入已关闭的
    加密流
  • 您可以使用
    加密流的
    块离开
    ,该块将调用
    FlushFinalBlock()
    ,如果它尚未调用的话
  • 正确的事件顺序是:

  • 您可以
    Write()
    将所有数据写入
    DeflateStream
    ,而DeflateStream又将大部分数据写入底层
    加密流
  • 您可以使用
    DeflateStream
    块离开
    ,该块将其余数据写入已关闭的
    加密流
  • 您可以使用调用
    FlushFinalBlock()
    加密流的
    块离开

  • 尽管我预计写入一个封闭流会失败,但会出现异常。我不确定为什么不会发生这种情况。

    每次都会从字节0覆盖。您需要添加一个偏移量变量,该变量从0开始,每次读取的字节数都会增加,否则您会一直覆盖缓冲区的开始部分;你说得对-我用以下内容替换了循环:
    intoffset=0;而(offset
    不幸的是,这并没有解决问题;我还剩下1个字节,它挂起了。(回想起来,如果错误的循环是罪魁祸首的话,解密后的数据就不完美了)。是的,当我看到它无法解决挂起字节的问题时,我将其作为答案删除,并将其作为注释添加。我只是想这可能会让你省去第二轮的挠头,不知道为什么缓冲区坏了:)这可能很滑稽。。。是否可以尝试添加一个
    bytesRead
    变量,该变量捕获Read的值,然后仅在该值为正时运行逻辑etc?我想知道它是否在结尾处返回负数(iirc这将是一个有效的终止符,因为从内存中它只是声明非正数是数据的结尾,尽管我最近没有检查关于这一点的文档)尝试过,而且它从不返回负值:<当前文档似乎表明它只返回读取的字节数或0以完成-尽管这有点奇怪,因为我在第一次读取调用时总是得到0(后续调用在挂起之前返回正值)。相反,这一行似乎是写入所有底层数据所必需的。当我删除它时,加密数据会变小,读取时会得到System.Security.Cryptography.CryptographyException,这无疑是因为加密数据无效。@cervellous,对我来说就是这样。例外说明了什么?尝试的一个选项是在处理
    DeflateStream
    之后,但在处理
    加密流之前调用
    FlushFinalBlock()
    。好吧,您的建议(在处理DeflateStream之后移动刷新/数据处理部分)奏效了!不知道为什么。很抱歉,我在先前的评论中不屑一顾。