Looking at the latest release (1.2) zip package - how can I unzip a file that was password protected (using 7zip, AES-256 encoding)? I don't see where/how to add in that information. A simple example would be great!
-
As far as I am concerned, the ZIP decompressor that is part of the Go standard library is not yet capable of decompressing encrypted ZIP files. – fuz Dec 02 '13 at 14:13
-
17zip offers a lot of different compressions and formats. I would suggest to use 7zip (e.g. via `Command`from package os/exec) directly. – Volker Dec 02 '13 at 14:28
-
If you *really* want to do this in Go, the relevant info is at http://www.winzip.com/aes_info.htm . 7zip in `zip, AES256` mode should produce compatible files (See "WinZip-developed zip file AES encryption standard is also available in 7-Zip to encrypt ZIP archives with AES 256-bit, but it does not offer filename encryption as in 7z archives." at http://en.wikipedia.org/wiki/7-Zip#Features) . – Intermernet Dec 02 '13 at 15:11
3 Answers
The archive/zip
package seems to only provide basic zip functionality.
I would use 7zip to unzip password protected zip files using the os/exec
package.
Online 7-zip user guide
The best guide for understanding 7zip is 7-zip.chm, which is in the zip file for the windows command line.
The following code isn't optimal but it shows you how to get the job done.
Code for extracting a password protected zip using 7zip
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)
}
Example Program
// Shows how to extract an passsword encrypted zip file using 7zip.
// By Larry Battle <https://github.com/LarryBattle>
// Answer to http://stackoverflow.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.")
}
Output
# 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.

- 9,008
- 4
- 41
- 55
-
-
@user2644113: If this answer solved you problem please [accept it](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) to reward the author and and provide a marker for future visitors. Maybe also accept answers to some of your other answers. Thanks! – DarkDust Dec 12 '14 at 08:03
-
3While this method probably works and is written in Go I do not think it meets the spirit of the question. This could have been implemented in shell script directly instead of shelling out to 7zip. I personally would have benefited from a statically linked go application that would run in a SCRATCH docker container. Therefore I do not think this is answered. [this](https://godoc.org/github.com/alexmullins/zip#example-Writer-Encrypt) is a little more interesting. – Richard Jan 21 '16 at 00:06
https://github.com/yeka/zip provides functionality to extract password protected zip file (AES & Zip Standard Encryption aka ZipCrypto).
Below is an example how to use it:
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()
}
}
The work is a fork from https://github.com/alexmullins/zip which add support for AES only.

- 341
- 3
- 2
-
Your proposal is not a solution, because in the line io.Copy(w, f), f is *zip.File and io.Copy requires src Reader as the second parameter. – Hugo L.M Oct 05 '18 at 09:16
-
1Reader is an interface, and *zip.File implement that interface. That's how it works. – yeka Feb 15 '19 at 04:38
If anyone else runs into this the extraction failing with a password error, try removing the quotes. In my case they were being escaped by go and was causing the extraction to fail.

- 1,555
- 11
- 22