Golang实现带密码的文件压缩功能

Golang实现带密码的文件压缩功能 我需要帮助创建一个受密码保护的zip文件。我目前正在使用标准库来创建zip文件,但它不提供任何保护功能。

4 回复

9年的仓库!好的,谢谢。 为什么Go项目不把这个添加到标准包中呢?你怎么看?

更多关于Golang实现带密码的文件压缩功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在大多数环境下,我会建议如果你需要加密数据,可以使用 ccrypt 或类似的工具。如果我没记错的话,加密ZIP文件的标准五花八门,其中流行的一个是WinZip的AES加密。如果你想了解更多关于为什么标准库中没有包含此功能的原因,请看这里:

proposal: archive/zip: support for encrypted archives

Go的标准库是我用过的最强大的(在大多数其他生态系统中,你可能不会直接获得 archive/zip 这样的库)。我认为,对于像WinZip AES加密这样的非标准功能,依赖开源社区是明智之举。

在Go语言中,有一个常见的关注点分离理念。压缩和加密这类任务被视为不同的功能:

  • 压缩旨在减小文件大小。
  • 加密旨在保护数据的机密性。

你可以自行使用加密功能来包装标准库。有大量简单的示例,展示了如何在zip之外使用crypto包。

类似这样:

import (
	"archive/zip"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"io"
	"os"
)

// 生成一个指定大小的随机AES密钥(32字节对应AES-256)
func generateKey() ([]byte, error) {
	key := make([]byte, 32) // 32字节对应AES-256
	_, err := rand.Read(key)
	if err != nil {
		return nil, err
	}
	return key, nil
}

// 使用AES-GCM加密内容
func encrypt(content []byte, key []byte) ([]byte, []byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return nil, nil, err
	}

	nonce := make([]byte, gcm.NonceSize())
	_, err = io.ReadFull(rand.Reader, nonce)
	if err != nil {
		return nil, nil, err
	}

	ciphertext := gcm.Seal(nonce, nonce, content, nil)
	return ciphertext, nonce, nil
}

// 向zip归档中添加一个加密文件
func addEncryptedFileToZip(zipWriter *zip.Writer, filename string, key []byte) error {
	file, err := os.ReadFile(filename)
	if err != nil {
		return err
	}

	encryptedContent, _, err := encrypt(file, key)
	if err != nil {
		return err
	}

	zipFileWriter, err := zipWriter.Create(filename)
	if err != nil {
		return err
	}

	_, err = zipFileWriter.Write(encryptedContent)
	if err != nil {
		return err
	}

	return nil
}

在Golang中实现带密码的zip压缩,标准库确实不直接支持。以下是使用第三方库github.com/alexmullins/zip的解决方案:

package main

import (
    "archive/zip"
    "bytes"
    "io"
    "os"

    "github.com/alexmullins/zip"
)

func createPasswordProtectedZip(filename, password string, files map[string][]byte) error {
    // 创建zip文件
    zipFile, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer zipFile.Close()

    // 创建带密码的zip写入器
    zipWriter := zip.NewWriter(zipFile)
    defer zipWriter.Close()

    for name, content := range files {
        // 为每个文件设置密码
        writer, err := zipWriter.Encrypt(name, password, zip.AES256Encryption)
        if err != nil {
            return err
        }

        // 写入文件内容
        _, err = io.Copy(writer, bytes.NewReader(content))
        if err != nil {
            return err
        }
    }

    return nil
}

func main() {
    files := map[string][]byte{
        "secret.txt": []byte("这是敏感数据"),
        "config.json": []byte(`{"key": "value"}`),
    }

    err := createPasswordProtectedZip("protected.zip", "myPassword123", files)
    if err != nil {
        panic(err)
    }
}

如果需要从磁盘文件创建加密zip:

func encryptFilesToZip(zipPath, password string, filePaths []string) error {
    zipFile, err := os.Create(zipPath)
    if err != nil {
        return err
    }
    defer zipFile.Close()

    zipWriter := zip.NewWriter(zipFile)
    defer zipWriter.Close()

    for _, filePath := range filePaths {
        // 打开源文件
        file, err := os.Open(filePath)
        if err != nil {
            return err
        }
        defer file.Close()

        // 获取文件信息用于zip头
        info, err := file.Stat()
        if err != nil {
            return err
        }

        // 创建加密的zip条目
        header, err := zip.FileInfoHeader(info)
        if err != nil {
            return err
        }
        header.Name = filepath.Base(filePath)
        header.Method = zip.Deflate

        writer, err := zipWriter.Encrypt(header.Name, password, zip.AES256Encryption)
        if err != nil {
            return err
        }

        // 写入文件内容
        _, err = io.Copy(writer, file)
        if err != nil {
            return err
        }
    }

    return nil
}

该库支持多种加密方式:

  • zip.StandardEncryption:传统PKZIP加密(较弱)
  • zip.AES128Encryption:AES-128加密
  • zip.AES192Encryption:AES-192加密
  • zip.AES256Encryption:AES-256加密(推荐)

解压时需要使用相同的库和密码:

func extractPasswordProtectedZip(zipPath, password, outputDir string) error {
    reader, err := zip.OpenReader(zipPath)
    if err != nil {
        return err
    }
    defer reader.Close()

    for _, file := range reader.File {
        // 设置密码
        file.SetPassword(password)
        
        // 打开加密文件
        rc, err := file.Open()
        if err != nil {
            return err
        }
        defer rc.Close()

        // 创建输出文件
        outPath := filepath.Join(outputDir, file.Name)
        outFile, err := os.Create(outPath)
        if err != nil {
            return err
        }
        defer outFile.Close()

        // 复制内容
        _, err = io.Copy(outFile, rc)
        if err != nil {
            return err
        }
    }
    
    return nil
}
回到顶部