AES 解密时的空输出流。原因?

Empty output stream at AES decrypt. Reason?

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

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...
                    }
                }
            }

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

如果删除了 FlushFinalBlock() 调用,则会生成 CryptographicException: Padding is invalid and cannot be removed,指示解密过程中的错误(例如,通常在使用与用于生成密文的密钥不同的密钥)。

padding异常的直接原因是解密产生了错误的明文(由无意义的字节组成,因此产生了无效的PKCS7 padding at the end. If the decryption would be done without padding (PaddingMode.None),不会产生这个异常,结果是确实是无意义的字节。

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

只是为了完整性:发布的代码使用了一个缓冲区(temp_buf),该缓冲区是根据评论为测试目的而实现的。使用 CryptoStream#Read(). The rest is read with StreamReader#ReadToEnd() 将数据写入此 1024 字节缓冲区。如果数据完全适合缓冲区,则第二部分不再 return 数据,因此 return 是一个空字符串,即使在成功解密的情况下,这也不会失败(与关于注释 //string is empty... 在发布的代码中)。