cer*_*ous 6 .net c# compression encryption c#-4.0
我想压缩然后加密我的数据,并且为了提高速度(不必写入字节数组并返回),决定将用于压缩和加密的流链接在一起.
它在我写入(压缩和加密)数据时工作得很好,但是当我尝试读取数据(解压缩和解密)时,Read操作中断 - 简单地调用Read一次读取0字节,因为第一个Read总是返回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();
Run Code Online (Sandbox Code Playgroud)
解密:
// 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);
*/
Run Code Online (Sandbox Code Playgroud)
解决方案(加密修改):
// 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();
Run Code Online (Sandbox Code Playgroud)
问题出在下面一行:
csEncrypt.FlushFinalBlock();
Run Code Online (Sandbox Code Playgroud)
如果删除它,代码就可以工作。
原因是当您写入 时DeflateStream,并非所有数据都会写入底层流。仅当您通过离开块显式或隐式调用时才会发生Close()这种Dispose()情况using。
所以在你的代码中,会发生这种情况:
Write()所有数据写入DeflateStream,然后将大部分数据写入底层CryptoStream。csEncrypt.FlushFinalBlock(),这会关闭CryptoStream.using的块DeflateStream,它尝试将其余数据写入已经关闭的CryptoStream。using的块CryptoStream,FlushFinalBlock()如果尚未调用它,它将调用 。正确的事件顺序是:
Write()将所有数据写入DeflateStream,然后将大部分数据写入底层CryptoStream。using的块DeflateStream,它将其余数据写入已经关闭的CryptoStream。using的块CryptoStream,该块调用了FlushFinalBlock()。尽管我预计写入关闭的流会因异常而失败。我不知道为什么这种情况没有发生。