简体   繁体   English

Zip 然后将多个文件加密到一个存档中

[英]Zip then encrypt multiple files into a single archive

As per the title I am wanting to take multiple files, zip them up and encrypt them using AES256 in to a single archive in a single pass.根据标题,我想要获取多个文件,将它们压缩并使用 AES256 一次将它们加密到单个存档中。 Is this possible?这可能吗?

I have managed to achieve a single file in to a single archive using the following code:我设法使用以下代码将单个文件放入单个存档中:

internal static void Encrypt(string filePath, string zipPath, byte[] key)
{
    // Create the streams used for encryption.
    using (var outputStream = new FileStream(zipPath, FileMode.Create, FileAccess.Write))
    {
        using (var aes = Aes.Create())
        {
            aes.BlockSize = 128;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = 256;

            aes.Key = key;
            aes.GenerateIV();

            // Write the IV in to the start of the file first.
            outputStream.Write(aes.IV, 0, aes.IV.Length);

            using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
            using (CryptoStream csEncrypt = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write))
            {
                using (DeflateStream zip = new DeflateStream(csEncrypt, CompressionMode.Compress, true))
                {
                    byte[] buffer = new byte[8192];

                    using (var dataStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    {
                        int bytesRead = dataStream.Read(buffer, 0, buffer.Length);

                        // Read the data in to a buffer to limit memory usage.
                        while (bytesRead > 0)
                        {
                            zip.Write(buffer, 0, bytesRead);

                            bytesRead = dataStream.Read(buffer, 0, buffer.Length);
                        }
                    }
                }

                //Flush after DeflateStream is disposed.
                csEncrypt.FlushFinalBlock();
            }
        }
    }
}

I have then tried to take this further using ZipArchive to include multiple files using the following:然后我尝试使用ZipArchive进一步使用以下方法包含多个文件:

internal static void EncryptArchive(string filePath, string zipPath, byte[] key)
{
    // Create the streams used for encryption.
    using (var outputStream = new FileStream(zipPath, FileMode.Create, FileAccess.Write))
    {
        using (var aes = Aes.Create())
        {
            aes.BlockSize = 128;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = 256;

            aes.Key = key;
            aes.GenerateIV();

            // Write the IV in to the start of the file first.
            outputStream.Write(aes.IV, 0, aes.IV.Length);

            using (ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
            using (CryptoStream csEncrypt = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write))
            {
                using (var zip = new ZipArchive(csEncrypt, ZipArchiveMode.Create, false))
                {
                    byte[] buffer = new byte[8192];

                    var entry = zip.CreateEntry(Path.GetFileName(filePath));

                    using (var dataStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                    using (var entryStream = entry.Open())
                    {
                        int bytesRead = dataStream.Read(buffer, 0, buffer.Length);

                        // Read the data in to a buffer to limit memory usage.
                        while (bytesRead > 0)
                        {
                            entryStream.Write(buffer, 0, bytesRead);

                            bytesRead = dataStream.Read(buffer, 0, buffer.Length);
                        }
                    }
                }

                //Flush after DeflateStream is disposed.
                csEncrypt.FlushFinalBlock();
            }
        }
    }
}

Now although the method is not set up to handle multiple files yet it currently can't even handle 1. As soon as I try to write to entryStream an exception is thrown stating that the stream does not support CanSeek .现在,虽然该方法未设置为处理多个文件,但它目前甚至无法处理 1。一旦我尝试写入entryStream ,就会抛出异常,指出该流不支持CanSeek

I assume ZIPs need to support seeking in order to store whatever positional metadata available for applications like Explorer to display their contents.我认为 ZIP 需要支持搜索,以便存储可供 Explorer 等应用程序显示其内容的任何位置元数据。 This requirement does not fit in to our use case so I am happy to workaround it if needed.这个要求不适合我们的用例,所以我很乐意在需要时解决它。

I have looked in to other libraries however DotNetZip seems to have some rather bad reviews more recently and not a lot of activity on it.我已经查看了其他库,但是DotNetZip 最近似乎有一些相当糟糕的评论,并且没有很多活动。 SharpZipLib does support AES 256 but looking at the source code it is built around using ECB which we all know is pretty much useless. SharpZipLib确实支持 AES 256,但查看它围绕使用 ECB 构建的源代码,我们都知道这几乎毫无用处。 This has currently left me believing that my only choice may be to write the multiple files in to the zip along with some metadata that identifies where in the stream they are positioned (I obviously won't be able to Seek to find these but that is not an issue).这个目前已经离开我相信我唯一的选择可能是在对拉链的多个文件编写以及一些元数据是,当流在它们被定位识别(我显然不会能够Seek找到这些但那是不是问题)。

To hopefully help clarify what I want to achieve:希望有助于澄清我想要实现的目标:

I have multiple files (A, B, C), I want to create a zip archive (D) and then encrypt it in the same pass (De).我有多个文件(A、B、C),我想创建一个 zip 存档(D),然后在同一个通道(De)中对其进行加密。 All this should be done without storing D on disk.所有这些都应该在将 D 存储在磁盘上的情况下完成。 I am currently using FileStream s as a test, it is most likely that these will be MemoryStream s later on to prevent unencrypted data touching the file system.我目前正在使用FileStream s 作为测试,很可能这些稍后将成为MemoryStream s,以防止未加密的数据接触文件系统。

Have I missed anything?我错过了什么吗? Is this possible?这可能吗?

To provide an answer I have in fact gone with @JamesKPolks suggestion of writing my own library to do the zipping and encryption of multiple files.为了提供答案,我实际上采纳了@JamesKPolks 的建议,即编写我自己的库来对多个文件进行压缩和加密。

I am not at liberty to provide the actual code based solution plus it has been built tailored to our specific needs so might not be the most useful to others.我不能随意提供基于实际代码的解决方案,而且它是根据我们的特定需求量身定制的,因此对其他人可能不是最有用的。 However in short the following approach was taken.然而,简而言之,采取了以下方法。

The file is split into 2 main parts:该文件分为两个主要部分:

1. Plaintext 1. 明文

IV

2. Encrypted 2. 加密

This is then split in to 2 parts:然后将其分为两部分:

2.1. 2.1. Metadata元数据

Names of the entries to be stored, padded at the end to aid the reading based on fixed block sizes.要存储的条目的名称,在末尾填充以帮助基于固定块大小的读取。

2.2. 2.2. Contents内容

The data entries themselves marked at the start by a hash of the name entry in 2.1 Metadata.数据条目本身在开始时由 2.1 元数据中的名称条目的哈希标记。 The contents are also written in a fixed block size with padding.内容也以带有填充的固定块大小写入。

Summary总结

The resulting library has been fairly trivial to write, however it has taken a fair amount of thought upfront.由此产生的库编写起来相当简单,但它预先考虑了相当多的想法。 That being said there is still a little bit left to finish off with allowing streaming out of the archive.话虽如此,在允许流式传输存档方面还有一点需要完成。

I would hope to have released the code but I am not at liberty at present.我希望已经发布了代码,但我目前没有自由。 Should anyone need assistance with a similar task I would be more than happy to offer help.如果有人在类似任务上需要帮助,我将非常乐意提供帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM