AES C# 文件加密 - 流只写入 16 字节

4

这是我的一段代码,旨在加密文件并将密文写入新文件。代码与微软MSDN网页上的示例相似。

byte[] inputBuffer = new byte[InputFileStream.Length];
byte[] outputBuffer = new byte[InputFileStream.Length];

InputFileStream.Read(inputBuffer, 0, (int)InputFileStream.Length);

ICryptoTransform encryptor = AesInstance.CreateEncryptor(AesInstance.Key, AesInstance.IV);


            using (MemoryStream memoryStream = new MemoryStream())
            {

                using (CryptoStream stream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter encrypted = new StreamWriter(stream))
                    {

                        encrypted.Write(inputBuffer);

                    }

                    outputBuffer = memoryStream.ToArray();

                    OutputFileStream.Write(outputBuffer, 0, (int)outputBuffer.Length);


                }

            }

OutputFileStream.Close();
InputFileStream.Close();`

问题在于输入缓冲区从文件中正确读取字节,但输出缓冲区似乎只有16个字节的数据。结果是输出文件只有16个字节,即使输入文件很大。哪里出了问题?问题存在于各种模式下,例如ECB、CBC等。

不用担心,这在程序逻辑中已经得到保证。 - Anna Skarpińska
4个回答

2
这个问题很古老,但是它值得更好的解释。问题隐藏在StreamWriter类中。该类应该用于向流中写入文本。然而,inputBuffer并不是文本,它是一个字节数组!

encrypted.Write(inputBuffer);

等同于

encrypted.Write(inputBuffer.ToString());

根据MSDN StreamWriter.Write(object)描述:

通过调用该对象上的ToString方法,将对象的文本表示形式写入文本字符串或流。

正确的解决方案是直接将输入缓冲区写入CryptoStream
using (MemoryStream msEncrypt = new MemoryStream(outputBuffer))
{
    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
    {
         csEncrypt.Write(inputBuffer, 0, inputBuffer.Length);
    }
    return msEncrypt.ToArray();
} 

0

我相信当你使用

encrypted.Write(inputBuffer);

你没有给写入者指定缓冲区的大小。


inputBuffer 是一个 byte[] 类型,所以我认为不需要给出缓冲区的大小,对吗? - Anna Skarpińska
1
主要问题在于 StreamWriterTextStream 的子类,而你无法将 byte[] 缓冲区写入其中。请改用 MemoryStream,并为 Write 函数指定缓冲区大小,这样就可以了! - Pooyan Arab

0
很多流都会进行缓冲,特别是加密和压缩流。在关闭/释放加密流之前,请勿对MemoryStream调用ToArray方法。
            using (CryptoStream stream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter encrypted = new StreamWriter(stream))
                {
                    encrypted.Write(inputBuffer);
                }
            }
            OutputFileStream.Write(memoryStream.GetBuffer(),
                0, (int)memoryStream.Length);
        }

更加清晰明了的做法是,完全放弃MemoryStream,直接在OutputFileStream上创建Crypto Stream - 即使处理大量数据也能很好地工作。

感谢您的回复。不幸的是,在具有memoryStream.Length的行处,我遇到了未处理的异常“无法访问已关闭的流”。此外,当我丢弃了memoryStream并仅使用CryptoStream时,输出仍然只有16个字节。 - Anna Skarpińska
@Anna 嗯... crypto-stream 构造函数有一个选项来拥有 / 不拥有内部流吗? - Marc Gravell
据我所知,cryptoStream构造函数只接受一个流作为参数,“用于执行加密转换的流”。 我认为在使用文件时,可能会出现刷新流的问题,但我不知道如何解决它... - Anna Skarpińska

0

好的,现在已经修复了。感谢Marc的回应,我弄清楚了它应该如何工作。 这是可行的代码,如果以后有人需要:

            InputFileStream.Read(inputBuffer, 0, (int)InputFileStream.Length);
            InputFileStream.Flush();
            InputFileStream.Close();

            using (MemoryStream msEncrypt = new MemoryStream(outputBuffer))
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        swEncrypt.Write(inputBuffer);
                        swEncrypt.Flush();
                        swEncrypt.Close();
                    }
                    csEncrypt.Flush();
                    csEncrypt.Close();
                }
                OutputFileStream.Write(outputBuffer, 0, (int)outputBuffer.Length);
                OutputFileStream.Flush();
                OutputFileStream.Close();
            }

也许这不是完美的代码(我知道它可能有冗余),但即使对于大型文件,它也能正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接