【问题标题】:Empty output stream at AES decrypt. Reason?AES 解密时的空输出流。原因?
【发布时间】:2020-09-29 18:18:05
【问题描述】:

我试图解密一些东西,但不明白为什么我得到空结果。我没有收到任何错误。我觉得这很奇怪。即使密钥无效,解密的垃圾也应该是无意义的字节,但不能为空。我做了最小的例子。

Aes aes = Aes.Create();
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            aes.KeySize = 128;
            aes.Key = new byte[] { 0x5f, 0x4d, 0xcc, 0x3b, 0x5a, 0xa7, 0x65, 0xd6, 0x1d, 0x83, 0x27, 0xde, 0xb8, 0x82, 0xcf, 0x99 };
            aes.IV = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

            // Create a decryptor to perform the stream transform.
            ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

            // Create the streams used for decryption.
            string encrypted_str_b64 = "E1UinhOTTy8Sj/IxCPEM+UNhIpTXIXnOAUtPgA35erJmvRc22gsdvIgcMZORZ2SY";
            byte[] ecrypted_junk = Convert.FromBase64String(encrypted_str_b64);

            string plaintext = string.Empty;

            using (MemoryStream memoryStream = new MemoryStream(ecrypted_junk))
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(cryptoStream))
                    {
                        cryptoStream.FlushFinalBlock();
                        byte[] temp_buf = new byte[1024];
                        int read_bytes = cryptoStream.Read(temp_buf, 0, temp_buf.Length); //read_bytes = 0...
                        
                        plaintext = srDecrypt.ReadToEnd(); //string is empty...
                    }
                }
            }

【问题讨论】:

  • FlushFinalBlock()清空流,还要写什么?如果你删除它,你会得到一个CryptographicException: Padding is invalid and cannot be removed,因为数据和密钥显然不匹配。顺便说一句,你使用了一个奇怪的结构(当然,这可能是有原因的):你首先写入一个 1024 字节的缓冲区(temp_buf),然后(如果还有一些东西)读取其余部分ReadToEnd()。因此,如果数据完全放入缓冲区,则ReadToEnd() 不会读取任何内容,即使解密成功也是如此。
  • @Topaco - 用那个buf 我刚刚测试了我是否可以从流中读取一些东西......是的,我一开始遇到了Padding is invalid and cannot be removed 异常,所以添加了FlushFinalBlock() 以避免它,但从不知道它会清除流...我不明白data and key don't match 的意思。在这种情况下我不应该得到无意义的字节输出而不是异常吗?
  • Data and key don't match 应该只是表示密文是用不同的密钥生成的(否则解密会成功)。如果使用 PKCS7 填充并且解密失败(例如因为数据和密钥不匹配),通常会在最后产生与 PKCS7 不兼容的数据,从而导致观察到的异常。如果你例如解密时不要使用填充 (PaddingMode.None) 你会得到无意义的字节。
  • @Topaco - 我认为这足以成为一个答案。做了。谢谢。
  • 不客气。我已经发布了答案。

标签: c# encryption aes


【解决方案1】:

没有数据被解密,因为在解密数据时CryptoStream 为空。这是因为它在实际读取之前被FlushFinalBlock() 清除。根据评论,实现FlushFinalBlock()是因为否则会发生填充异常,但这不是问题的解决方案。

如果FlushFinalBlock() 调用被删除,CryptographicException: Padding is invalid and cannot be removed 会生成,指示解密期间出错(例如,通常在使用与用于生成密文的密钥)。

填充异常的直接原因是解密产生了错误的明文(由无意义的字节组成),因此最后产生了无效的PKCS7 padding。如果解密不用填充(PaddingMode.None),就不会产生这个异常,结果确实是无意义的字节。

所以真正的解决问题的方法是使用正确的密钥,即创建密文的密钥。否则解密几乎是不可能的。

仅出于完整性考虑:发布的代码使用了一个缓冲区 (temp_buf),该缓冲区是根据评论为测试目的而实现的。数据使用CryptoStream#Read() 写入这个 1024 字节缓冲区。其余部分使用StreamReader#ReadToEnd() 读取。如果数据完全适合缓冲区,则第二部分不再返回任何数据,因此返回一个空字符串,即使在成功解密的情况下,也不会失败(关于注释 //字符串为空... 在发布的代码中)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-07
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    相关资源
    最近更新 更多