代码之家  ›  专栏  ›  技术社区  ›  Harald Coppoolse

解密时:填充无效,如果未读取任何内容,则无法删除。

  •  1
  • Harald Coppoolse  · 技术社区  · 6 年前

    看来 THIS question is related, 但事实并非如此。
    在我的例子中,当 正在解密 ,在相关问题中,它是何时 加密

    人们问的第一个问题是:你试过什么?我试过很多次了。所以,即使删除了所有多余的文本,我的描述也相当长。对不起。

    我的结论是,在 CryptoSteam.FlushFinalBlock ,由调用 CryptoStream.Dispose() . 如果没有从流中读取任何内容,则会发生这种情况。

    Reference source CryptoStream.FlushFinalBlock

    如果我在解密过程中读取所有数据或至少一个字节,一切都会正常工作。

    如果我什么也没读,我会得到一个密码例外。 填充无效,无法删除。

    • 以下是完整的加密/解密周期。工作正常,没有异常,不需要更改默认填充,不需要FlushFinalBlock。读取的数据等于原始数据
    • 如果我只读取一个字节:也没有异常,不需要更改默认填充,不需要FlushFinalBlock。正确的dispose()处理此问题
    • 如果我什么都没读,我就会得到上面提到的例外。
    • 释放前的额外FlushFinalBlock没有帮助

    下面的代码显示了一个完整的正确工作的加密/解密测试过程。解密的字节等于原始字节:

    数据:

    byte[] key;
    byte[] iv;
    byte[] testData = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    byte[] encryptedData;
    byte[] decryptedData;
    

    数据加密:

    using (Stream testStream = new MemoryStream(testData))
    {
        using (RijndaelManaged rijndael = new RijndaelManaged())
        {   // Generate and remember keys:
            rijndael.GenerateKey();
            rijndael.GenerateIV();
            key = rijndael.Key;
            iv = rijndael.IV;
    
            using (var encryptor = rijndael.CreateEncryptor())
            {
                using (var cryptoStream = new CryptoStream(testStream, encryptor,
                       CryptoStreamMode.Read))
                {   // read all bytes from the cryptoStream and put in a EncryptedData
                    using (BinaryReader reader = new BinaryReader(cryptoStream))
                    {
                        encryptedData = reader.ReadBytes(10000);
                        // expect no bytes anymore
                    }
                }
            }
        }
    }
    

    所有测试字节都加密在EncryptedData中。键和四是已知的

    using (Stream encryptedStream = new MemoryStream(encryptedData))
    {
        using (var rijnDael = new RijndaelManaged())
        {
            rijnDael.Key = key;
            rijnDael.IV = iv;
            using (var decryptor = rijnDael.CreateDecryptor())
            {
                using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
                       CryptoStreamMode.Read))
                {
                    using (BinaryReader reader = new BinaryReader(decryptedStream))
                    {
                        decryptedData = reader.ReadBytes(1000);
                        // expect no bytes anymore
                    }
                }
            }
        }
    }
    
    // Check that the decrypted data equals the original data:
    Debug.Assert(testData.SequenceEqual(decryptedData));
    

    这个很好用。如果我只读取一个解密的字节,则没有例外:

    using (BinaryReader reader = new BinaryReader(decryptedStream))
    {
        byte b = reader.ReadByte();
    }
    

    但是,如果我什么也没读到,异常就会发生:

    using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
           CryptoStreamMode.Read))
    {
        using (BinaryReader reader = new BinaryReader(decryptedStream))
        {
        } // exception during Dispose()
    }
    

    在开头提到的相关问题中的一个答案包括一个侥幸的结局。这没有如预期的那样有帮助,因为CrypteStream.Dispose已经调用了此

    using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
           CryptoStreamMode.Read))
    {
        using (BinaryReader reader = new BinaryReader(decryptedStream))
        {
            if (!decryptedStream.HasFlushedFinalBlock)
            { 
                decryptedStream.FlushFinalBlock();
                // even though it hasn't flushed the final bloc
                // I get the same Exception during Flush
             }
        } 
    }
    

    所以现在我们知道异常的发生是因为 CryptoStream.FlushFinalBlock ,也可以在 CryptoStream.Dispose()。

    这个问题与二进制阅读器无关。如果我直接读取一个字节,那么就没有异常,如果不读取任何内容,我将在释放密码流期间获取异常。

    using (Stream decryptedStream = new CryptoStream(encryptedStream, decryptor,
           CryptoStreamMode.Read))
    {
        int b = decryptedStream.ReadByte();
    } // exception during Dispose()
    

    那么,我应该怎么做来防止这个异常呢?读取一个虚拟字节?看起来有点傻,不是吗?

    0 回复  |  直到 6 年前