cnb.cool/svn/zip 是面向生产交付的 Go archive/zip 增强分支,支持密码保护、WinZip AES、ZipCrypto 兼容、LZMA、Zstandard、fs.FS、原始数据复制 API,以及更严格的路径与加密配置校验。
StandardEncryption 用于兼容 Info-ZIP zip / unzip 等遗留工具。SetPassword 且未显式指定方法时,默认使用 AES-256。DefaultPBKDF2Iterations = 100000 用于新写出的 AES 文件。MinPBKDF2Iterations = 1000,写入与读取私有元数据时都会校验。LegacyPBKDF2Iterations = 1000 用于严格兼容 WinZip AES / 7-Zip。| 方法 | ID | 说明 |
|---|---|---|
Store | 0 | 不压缩 |
Deflate | 8 | 标准 ZIP 默认压缩 |
LZMA | 14 | 压缩率更高,速度较慢 |
Zstandard | 93 | 速度快,压缩率良好 |
LZMA 与 Zstandard 可由本库读写;外部 ZIP 工具是否支持取决于具体工具能力。
Reader.Files() 与 Reader.EncryptedFiles()。fs.FS:通过 Reader.Open 集成标准文件系统接口。File.OpenRaw、Writer.CreateRaw、Writer.Copy。Writer.AddFS。FileHeader.Modified 支持扩展时间戳。go get cnb.cool/svn/zip
要求:
github.com/ulikunitz/xz 用于 LZMAgithub.com/klauspost/compress 用于 Zstandardgolang.org/x/crypto/pbkdf2 用于 AES 密钥派生package main
import (
"log"
"os"
"cnb.cool/svn/zip"
)
func main() {
f, err := os.Create("secret.zip")
if err != nil {
log.Fatal(err)
}
defer f.Close()
zw := zip.NewWriter(f)
defer zw.Close()
w, err := zw.Encrypt("secret.txt", "strong-password", zip.AES256Encryption)
if err != nil {
log.Fatal(err)
}
if _, err := w.Write([]byte("confidential data")); err != nil {
log.Fatal(err)
}
}
fh := &zip.FileHeader{
Name: "confidential.txt",
Method: zip.Deflate,
PBKDF2Iterations: 100000,
}
fh.SetPassword("strong-password")
fh.SetEncryptionMethod(zip.AES256Encryption)
w, err := zw.CreateHeader(fh)
if err != nil {
log.Fatal(err)
}
w.Write([]byte("secret"))
新写出的 AES 文件若未设置 PBKDF2Iterations,cnb.cool/svn/zip 会使用 DefaultPBKDF2Iterations 并自动写入私有元数据。读取没有该元数据的第三方 AES 归档时,会回退到 LegacyPBKDF2Iterations。
fh := &zip.FileHeader{Name: "legacy.txt", Method: zip.Deflate}
fh.SetPassword("password")
fh.SetEncryptionMethod(zip.StandardEncryption)
w, err := zw.CreateHeader(fh)
if err != nil {
log.Fatal(err)
}
w.Write([]byte("compatible with Info-ZIP unzip"))
StandardEncryption 只应在必须兼容旧工具时使用。
r, err := zip.OpenReader("secret.zip")
if err != nil {
log.Fatal(err)
}
defer r.Close()
for _, f := range r.File {
if f.IsEncrypted() {
f.SetPassword("strong-password")
// 对没有 cnb.cool/svn/zip 元数据、但使用非标准迭代次数的第三方 AES 文件,
// 如果已知迭代次数,可显式设置 f.PBKDF2Iterations。
}
rc, err := f.Open()
if err != nil {
log.Fatal(err)
}
data, err := io.ReadAll(rc)
rc.Close()
if err != nil {
log.Fatal(err)
}
_ = data
}
r, _ := zip.OpenReader("archive.zip")
defer r.Close()
for f := range r.Files() {
fmt.Println(f.Name)
}
for f := range r.EncryptedFiles() {
f.SetPassword("password")
}
r, _ := zip.OpenReader("archive.zip")
defer r.Close()
var fsys fs.FS = &r.Reader
fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error {
fmt.Println(path)
return err
})
src, _ := zip.OpenReader("source.zip")
defer src.Close()
dstFile, _ := os.Create("copy.zip")
defer dstFile.Close()
zw := zip.NewWriter(dstFile)
defer zw.Close()
for _, f := range src.File {
if err := zw.Copy(f); err != nil {
log.Fatal(err)
}
}
zw := zip.NewWriter(file)
defer zw.Close()
if err := zw.AddFS(os.DirFS("./myproject")); err != nil {
log.Fatal(err)
}
const CustomMethod = 99
type nopWriteCloser struct{ io.Writer }
func (nopWriteCloser) Close() error { return nil }
zw := zip.NewWriter(file)
zw.RegisterCompressor(CustomMethod, func(w io.Writer) (io.WriteCloser, error) {
return nopWriteCloser{w}, nil
})
r, _ := zip.OpenReader("archive.zip")
r.RegisterDecompressor(CustomMethod, func(r io.Reader) io.ReadCloser {
return io.NopCloser(r)
})
本库会对不安全或不一致的输入尽早失败:
ErrInsecurePath。ErrPassword。ErrEncryption。MinPBKDF2Iterations 返回 ErrWeakPBKDF2。ErrInvalidPBKDF2。ErrAuthentication。ErrAlgorithm。条目名必须是相对路径、使用 / 分隔。空名称、绝对路径、..、反斜杠和 Windows 盘符路径都会被拒绝。
| 工具 | ZipCrypto / StandardEncryption | 使用 LegacyPBKDF2Iterations 的 AES | cnb.cool/svn/zip 高迭代 AES |
|---|---|---|---|
| cnb.cool/svn/zip | ✅ | ✅ | ✅ |
Info-ZIP zip / unzip | ✅ | ❌ | ❌ |
| 7-Zip | ✅ | ✅ | ❌ |
| WinZip | ✅ | ✅ | ❌ |
| Windows 资源管理器 | ✅ | ❌ | ❌ |
| macOS Archive Utility | ✅ | ❌ | ❌ |
当前代码已使用本机 zip / unzip 做过双向验证:
unzip 测试与解压。StandardEncryption 归档可被 unzip -P 解密。SetPassword 读取。StandardEncryption / ZipCrypto 已不具备现代密码学安全性,只用于遗留互通。DefaultPBKDF2Iterations 或更高迭代次数。LegacyPBKDF2Iterations。DeferAuth 默认值 false。BSD 3-Clause License。见 LICENSE。