【问题标题】:Golang 1.2: Unzip password protected zip file?Golang 1.2:解压缩受密码保护的 zip 文件?
【发布时间】:2013-12-02 14:06:41
【问题描述】:

查看最新版本 (1.2) 压缩包 - 如何解压缩受密码保护的文件(使用 7zip、AES-256 编码)?我看不到在哪里/如何添加该信息。一个简单的例子就好了!

【问题讨论】:

  • 就我而言,作为 Go 标准库一部分的 ZIP 解压缩器尚不能解压缩加密的 ZIP 文件。
  • 7zip 提供了许多不同的压缩和格式。我建议直接使用 7zip(例如通过Commandfrom package os/exec)。
  • 如果您真的想在 Go 中执行此操作,相关信息位于 winzip.com/aes_info.htmzip, AES256 模式下的 7zip 应该生成兼容的文件(请参阅“WinZip 开发的 zip 文件 AES 加密标准也可用于 7-Zip 以使用 AES 256 位加密 ZIP 档案,但它不像 7z 档案那样提供文件名加密。 "en.wikipedia.org/wiki/7-Zip#Features)。

标签: go


【解决方案1】:

archive/zip 包似乎只提供基本的 zip 功能。 我会使用 7zip 解压缩使用 os/exec 包的受密码保护的 zip 文件。

在线7-zip user guide

了解 7zip 的最佳指南是 7-zip.chm,它位于 Windows 的 zip 文件中command line

以下代码不是最佳的,但它向您展示了如何完成工作。

使用 7zip 提取受密码保护的 zip 的代码

func extractZipWithPassword() {
    fmt.Printf("Unzipping `%s` to directory `%s`\n", zip_path, extract_path)
    commandString := fmt.Sprintf(`7za e %s -o%s -p"%s" -aoa`, zip_path, extract_path, zip_password)
    commandSlice := strings.Fields(commandString)
    fmt.Println(commandString)
    c := exec.Command(commandSlice[0], commandSlice[1:]...)
    e := c.Run()
    checkError(e)
}

示例程序

// Shows how to extract an passsword encrypted zip file using 7zip.
// By Larry Battle <https://github.com/LarryBattle>
// Answer to http://*.com/questions/20330210/golang-1-2-unzip-password-protected-zip-file
// 7-zip.chm - http://sevenzip.sourceforge.jp/chm/cmdline/switches/index.htm
// Effective Golang - http://golang.org/doc/effective_go.html
package main

import (
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "strings"
)

var (
    txt_content     = "Sample file created."
    txt_filename    = "name.txt"
    zip_filename    = "sample.zip"
    zip_password    = "42"
    zip_encryptType = "AES256"
    base_path       = "./"

    test_path          = filepath.Join(base_path, "test")
    src_path           = filepath.Join(test_path, "src")
    extract_path       = filepath.Join(test_path, "extracted")
    extracted_txt_path = filepath.Join(extract_path, txt_filename)
    txt_path           = filepath.Join(src_path, txt_filename)
    zip_path           = filepath.Join(src_path, zip_filename)
)
var txt_fileSize int64

func checkError(e error) {
    if e != nil {
        panic(e)
    }
}
func setupTestDir() {
    fmt.Printf("Removing `%s`\n", test_path)
    var e error
    os.Remove(test_path)
    fmt.Printf("Creating `%s`,`%s`\n", extract_path, src_path)
    e = os.MkdirAll(src_path, os.ModeDir|os.ModePerm)
    checkError(e)
    e = os.MkdirAll(extract_path, os.ModeDir|os.ModePerm)
    checkError(e)
}
func createSampleFile() {
    fmt.Println("Creating", txt_path)
    file, e := os.Create(txt_path)
    checkError(e)
    defer file.Close()
    _, e = file.WriteString(txt_content)
    checkError(e)
    fi, e := file.Stat()
    txt_fileSize = fi.Size()
}
func createZipWithPassword() {
    fmt.Println("Creating", zip_path)
    commandString := fmt.Sprintf(`7za a %s %s -p"%s" -mem=%s`, zip_path, txt_path, zip_password, zip_encryptType)
    commandSlice := strings.Fields(commandString)
    fmt.Println(commandString)
    c := exec.Command(commandSlice[0], commandSlice[1:]...)
    e := c.Run()
    checkError(e)
}
func extractZipWithPassword() {
    fmt.Printf("Unzipping `%s` to directory `%s`\n", zip_path, extract_path)
    commandString := fmt.Sprintf(`7za e %s -o%s -p"%s" -aoa`, zip_path, extract_path, zip_password)
    commandSlice := strings.Fields(commandString)
    fmt.Println(commandString)
    c := exec.Command(commandSlice[0], commandSlice[1:]...)
    e := c.Run()
    checkError(e)
}
func checkFor7Zip() {
    _, e := exec.LookPath("7za")
    if e != nil {
        fmt.Println("Make sure 7zip is install and include your path.")
    }
    checkError(e)
}
func checkExtractedFile() {
    fmt.Println("Reading", extracted_txt_path)
    file, e := os.Open(extracted_txt_path)
    checkError(e)
    defer file.Close()
    buf := make([]byte, txt_fileSize)
    n, e := file.Read(buf)
    checkError(e)
    if !strings.Contains(string(buf[:n]), strings.Fields(txt_content)[0]) {
        panic(fmt.Sprintf("File`%s` is corrupted.\n", extracted_txt_path))
    }
}
func main() {
    fmt.Println("# Setup")
    checkFor7Zip()
    setupTestDir()
    createSampleFile()
    createZipWithPassword()
    fmt.Println("# Answer to question...")
    extractZipWithPassword()
    checkExtractedFile()
    fmt.Println("Done.")
}

输出

# Setup
Removing `test`
Creating `test/extracted`,`test/src`
Creating test/src/name.txt
Creating test/src/sample.zip
7za a test/src/sample.zip test/src/name.txt -p"42" -mem=AES256
# Answer to question...
Unzipping `test/src/sample.zip` to directory `test/extracted`
7za e test/src/sample.zip -otest/extracted -p"42" -aoa
Reading test/extracted/name.txt
Done.

【讨论】:

  • 太棒了拉里!适用于我的用例。谢谢
  • @user2644113:如果这个答案解决了您的问题,请accept it 奖励作者并为未来的访问者提供标记。也许也接受您的其他一些答案的答案。谢谢!
  • 虽然这种方法可能有效并且是用 Go 编写的,但我认为它不符合问题的精神。这可以直接在 shell 脚本中实现,而不是直接使用 7zip。我个人会受益于静态链接的 go 应用程序,该应用程序将在 SCRATCH docker 容器中运行。因此,我不认为这是答案。 this 更有趣一点。
【解决方案2】:

https://github.com/yeka/zip 提供提取受密码保护的 zip 文件(AES 和 Zip 标准加密,又名 ZipCrypto)的功能。

以下是如何使用它的示例:

package main

import (
    "os"
    "io"
    "github.com/yeka/zip"
)

func main() {
    file := "file.zip"
    password := "password"
    r, err := zip.OpenReader(file)
    if nil != err {
        panic(err)
    }
    defer r.Close()

    for _, f := range r.File {
        f.SetPassword(password)
        w, err := os.Create(f.Name)
        if nil != err {
            panic(err)
        }
        io.Copy(w, f)
        w.Close()
    }
}

这项工作是来自 https://github.com/alexmullins/zip 的一个分支,它仅添加了对 AES 的支持。

【讨论】:

  • 你的建议不是解决方案,因为在io.Copy(w, f)这一行,f是*zip.File,io.Copy需要src Reader作为第二个参数。
  • Reader 是一个接口,而 *zip.File 实现了该接口。这就是它的工作原理。
【解决方案3】:

如果其他人遇到这种提取失败并出现密码错误的情况,请尝试删除引号。在我的情况下,他们被 go 逃脱并导致提取失败。

【讨论】:

    最近更新 更多