将 AES 加密的 zip 提取到 MemoryStream

Extracting AES encrypted zip to MemoryStream

我正在开发一个过程来压缩和加密我的桌面应用程序中的字节数组,并通过 WebMethod 将它发送到我的 Web 应用程序,然后 uncompress/unencrypt 它返回到字节数组。我目前正在尝试使用 SharpZipLib 执行此操作。文件的压缩似乎按预期工作。我能够将文件保存到磁盘并使用 7zip 毫无问题地解压缩它。

我遇到的问题是当我在网络服务器上收到字节数组并尝试提取它时。

我在桌面端使用CompressData方式压缩数据

private byte[] CompressData(byte[] data, string password)
{
    MemoryStream input = new MemoryStream(data);
    MemoryStream ms = new MemoryStream();
    ZipOutputStream os = new ZipOutputStream(ms);
    os.SetLevel(9);
    if (!string.IsNullOrEmpty(password)) os.Password = password;
    ZipEntry entry = new ZipEntry("data")
    {
        DateTime = DateTime.Now
    };
    if (!string.IsNullOrEmpty(password)) entry.AESKeySize = 256;
    os.PutNextEntry(entry);
    StreamUtils.Copy(input, os, new byte[4096]);
    os.CloseEntry();
    os.IsStreamOwner = false;
    os.Close();
    ms.Position = 0;
    return ms.ToArray();
}

我正在使用以下代码在服务器端提取数据(几乎是从 SharpZipLib 示例中逐字提取的):

    private byte[] DoRebuildData(byte[] data, string password)
    {
        MemoryStream inStream = new MemoryStream(data);

        MemoryStream outputMemStream = new MemoryStream();
        ZipOutputStream zipOut = new ZipOutputStream(outputMemStream)
        {
            IsStreamOwner = false  // False stops the Close also Closing the underlying stream.
        };

        zipOut.SetLevel(3);
        zipOut.Password = password;        // optional

        RecursiveExtractRebuild(inStream, zipOut);
        inStream.Close();

        // Must finish the ZipOutputStream to finalise output before using outputMemStream.
        zipOut.Close();

        outputMemStream.Position = 0;
        return outputMemStream.ToArray();
    }

    // Calls itself recursively if embedded zip
    //
    private void RecursiveExtractRebuild(Stream str, ZipOutputStream os)
    {

        ZipFile zipFile = new ZipFile(str)
        {
            IsStreamOwner = false
        };

        foreach (ZipEntry zipEntry in zipFile)
        {
            if (!zipEntry.IsFile)
                continue;
            String entryFileName = zipEntry.Name; // or Path.GetFileName(zipEntry.Name) to omit folder
                                                  // Specify any other filtering here.

            Stream zipStream = zipFile.GetInputStream(zipEntry);
            // Zips-within-zips are extracted. If you don't want this and wish to keep embedded zips as-is, just delete these 3 lines. 
            if (entryFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
            {
                RecursiveExtractRebuild(zipStream, os);
            }
            else
            {
                ZipEntry newEntry = new ZipEntry(entryFileName);
                newEntry.DateTime = zipEntry.DateTime;
                newEntry.Size = zipEntry.Size;
                // Setting the Size will allow the zip to be unpacked by XP's built-in extractor and other older code.

                os.PutNextEntry(newEntry);

                StreamUtils.Copy(zipStream, os, new byte[4096]);
                os.CloseEntry();
            }
        }
    }

预期的结果是在服务器上取回我原来的字节数组。

在服务器上,当涉及到行时:

Stream zipStream = zipFile.GetInputStream(zipEntry);

我收到错误 'No password available for AES encrypted stream.'

我唯一看到设置密码的地方是在 ZipOutputStream 对象中,我在运行时检查过,这个设置正确。

解包时,密码必须赋给ZipFile-实例的password-属性,即必须在RecursiveExtractRebuild-方法中设置(为此必须将密码添加为附加参数):

zipFile.Password = password;

如图this example.

需要注意的是,目前的DoRebuildData-方法实际上并没有解压数据,而是re-packs it into a new zipDoRebuildData-方法中的(可选)行:

zipOut.Password = password;

指定解压密码(即旧 zip),但定义 zip 的密码。