You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#/.NET Framework 4.6.1中无外部库创建带密码Zip文件

在.NET Framework 4.6.1中创建密码保护的Zip文件(无外部库)

.NET Framework 4.6.1自带的System.IO.Compression系列类不原生支持创建符合PKZIP标准的密码保护Zip文件,但可以通过以下两种实用方案实现需求:

方案一:对整个Zip流进行对称加密(推荐,实现简单)

这种方式将生成的无密码Zip字节流用AES算法加密,解密时需先还原出原始Zip流再解压。虽非标准加密Zip,但能满足"需指定密码才能获取内容"的核心需求,完全基于.NET原生类实现。

代码实现

using System;
using System.IO;
using System.Security.Cryptography;
using System.IO.Compression;

// 生成带密码保护的加密Zip字节流
public byte[] CreatePasswordProtectedZip(string password, InlineContent[] reports)
{
    // 1. 生成无密码Zip字节流(复用你的原有逻辑,优化二进制写入方式)
    byte[] rawZipBytes;
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive zipFile = new ZipArchive(zipStream, ZipArchiveMode.Create, false))
        {
            foreach (InlineContent report in reports)
            {
                ZipArchiveEntry entry = zipFile.CreateEntry(report.FileName, CompressionLevel.Optimal);
                using (Stream entryStream = entry.Open())
                {
                    // 直接复制二进制内容,避免StreamWriter的编码问题
                    new MemoryStream(report.Content.ToArray()).CopyTo(entryStream);
                }
            }
        }
        rawZipBytes = zipStream.ToArray();
    }

    // 2. 用AES-256加密Zip字节流
    using (Aes aes = Aes.Create())
    {
        // 生成随机盐值,用于派生密钥(解密时需相同盐值)
        byte[] salt = new byte[16];
        RandomNumberGenerator.Create().GetBytes(salt);

        // 从密码和盐值派生密钥与IV
        var keyDeriver = new Rfc2898DeriveBytes(password, salt, 10000);
        aes.Key = keyDeriver.GetBytes(32);
        aes.IV = keyDeriver.GetBytes(16);

        // 写入加密后的流(先存盐值,解密时读取)
        using (MemoryStream encryptedStream = new MemoryStream())
        {
            encryptedStream.Write(salt, 0, salt.Length);
            using (CryptoStream cryptoStream = new CryptoStream(encryptedStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cryptoStream.Write(rawZipBytes, 0, rawZipBytes.Length);
            }
            return encryptedStream.ToArray();
        }
    }
}

// 配套解密方法(供参考)
public byte[] DecryptZip(string password, byte[] encryptedBytes)
{
    using (Aes aes = Aes.Create())
    {
        // 读取盐值
        byte[] salt = new byte[16];
        Array.Copy(encryptedBytes, 0, salt, 0, salt.Length);

        // 派生密钥与IV
        var keyDeriver = new Rfc2898DeriveBytes(password, salt, 10000);
        aes.Key = keyDeriver.GetBytes(32);
        aes.IV = keyDeriver.GetBytes(16);

        // 解密得到原始Zip字节流
        using (MemoryStream decryptedStream = new MemoryStream())
        {
            using (MemoryStream encryptedStream = new MemoryStream(encryptedBytes, salt.Length, encryptedBytes.Length - salt.Length))
            {
                using (CryptoStream cryptoStream = new CryptoStream(encryptedStream, aes.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    cryptoStream.CopyTo(decryptedStream);
                }
            }
            return decryptedStream.ToArray();
        }
    }
}

注意事项

  • 生成的文件无法被WinRAR、系统自带解压工具直接识别解密,需用上述解密代码还原出原始Zip流后再解压。
  • 原代码中使用StreamWriter写入二进制内容可能引发编码异常,已改为Stream.CopyTo处理。

方案二:调用Windows Shell COM组件(生成标准加密Zip)

Windows系统自带的Shell组件支持创建符合PKZIP标准的加密Zip,但需通过COM互操作调用,且无法自动传入密码(会弹出系统密码输入框),适合交互式场景。

代码实现

using System;
using System.IO;
using Shell32; // 添加COM引用:Microsoft Shell Controls And Automation

public void CreateStandardEncryptedZip(string outputPath, InlineContent[] reports)
{
    // 1. 生成临时无密码Zip文件
    string tempZipPath = Path.GetTempFileName() + ".zip";
    using (FileStream fs = new FileStream(tempZipPath, FileMode.Create))
    using (ZipArchive zipFile = new ZipArchive(fs, ZipArchiveMode.Create, false))
    {
        foreach (InlineContent report in reports)
        {
            ZipArchiveEntry entry = zipFile.CreateEntry(report.FileName, CompressionLevel.Optimal);
            using (Stream entryStream = entry.Open())
            {
                new MemoryStream(report.Content.ToArray()).CopyTo(entryStream);
            }
        }
    }

    // 2. 创建空的目标加密Zip文件
    File.Create(outputPath).Dispose();

    // 3. 调用Shell组件完成加密(会弹出系统密码输入框)
    Shell shell = new Shell();
    Folder tempFolder = shell.NameSpace(Path.GetDirectoryName(tempZipPath));
    Folder targetFolder = shell.NameSpace(Path.GetDirectoryName(outputPath));
    FolderItem tempZipItem = tempFolder.ParseName(Path.GetFileName(tempZipPath));

    // 复制并加密:FOF_WANTPASSWORD触发密码输入框,FOF_NOCONFIRMATION自动覆盖现有文件
    const int FOF_WANTPASSWORD = 0x0010;
    const int FOF_NOCONFIRMATION = 0x0002;
    targetFolder.CopyHere(tempZipItem, FOF_WANTPASSWORD | FOF_NOCONFIRMATION);

    // 等待Shell操作完成(需根据实际情况调整延迟)
    System.Threading.Thread.Sleep(2000);
    File.Delete(tempZipPath);
}

注意事项

  • 需添加对Microsoft Shell Controls And Automation的COM引用。
  • 无法在后台自动传入密码,必须用户手动输入,适合交互式场景。

内容的提问来源于stack exchange,提问作者Bruno Gonzalez Torres

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 20:40:57