Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#fix: Support for standard encryption and AES #6

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
This fork add support for Standard Zip Encryption.

The work is based on https://github.com/alexmullins/zip

Available encryption:
```
zip.StandardEncryption
zip.AES128Encryption
zip.AES192Encryption
zip.AES256Encryption
```

## Warning

Zip Standard Encryption isn't actually secure.
Unless you have to work with it, please use AES encryption instead.

## Example Encrypt Zip

```
package main

import (
"bytes"
"io"
"log"
"os"

"github.com/yeka/zip"
)

func main() {
contents := []byte("Hello World")
fzip, err := os.Create(`./test.zip`)
if err != nil {
log.Fatalln(err)
}
zipw := zip.NewWriter(fzip)
defer zipw.Close()
w, err := zipw.Encrypt(`test.txt`, `golang`, zip.AES256Encryption)
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(w, bytes.NewReader(contents))
if err != nil {
log.Fatal(err)
}
zipw.Flush()
}
```

## Example Decrypt Zip

```
package main

import (
"fmt"
"io/ioutil"
"log"

"github.com/yeka/zip"
)

func main() {
r, err := zip.OpenReader("encrypted.zip")
if err != nil {
log.Fatal(err)
}
defer r.Close()

for _, f := range r.File {
if f.IsEncrypted() {
f.SetPassword("12345")
}

r, err := f.Open()
if err != nil {
log.Fatal(err)
}

buf, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
defer r.Close()

fmt.Printf("Size of %v: %v byte(s)\n", f.Name, len(buf))
}
}
```

### fileheader 设置文件的编码格式

```

func StepDealZip(tmpFilesForZip []string, zipFilePath string, job YellowDogJob) (err error) {
archive, err := os.Create(zipFilePath)
if err != nil {
return err
}
defer archive.Close()
zipWriter := zip.NewWriter(archive)
for _, file := range tmpFilesForZip {
fileInfo, err := os.Stat(file)
if err != nil {
return err
}
body, err := ioutil.ReadFile(file)
if err != nil {
return err
}
var filename string
fileNameSplit := strings.Split(fileInfo.Name(), ".")
if fileNameSplit[2] == `pdf` {
filename = "报表_" + fileNameSplit[1] + `.pdf`
} else {
for _, values := range job.RptTableDict {
if values.Dish == fileNameSplit[0] {
filename = fileNameSplit[1] + `_` + values.DishHuman + `.xlsx`
}
}
}
header := &zip.FileHeader{
Name: filename,
Flags: 1 << 11, // 使用utf8编码
Method: zip.Deflate,
}
if job.RptPwd != `` {
header.SetPassword(job.RptPwd)
header.SetEncryptionMethod(zip.StandardEncryption)
}
f, err := zipWriter.CreateHeader(header)
if err != nil {
return err
}
_, err = f.Write([]byte(body))
if err != nil {
return err
}
}
if err = zipWriter.Close(); err != nil {
return err
}
return nil
}

```

77 changes: 0 additions & 77 deletions README.txt

This file was deleted.

32 changes: 27 additions & 5 deletions crypto.go
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ import (
"golang.org/x/crypto/pbkdf2"
)

type EncryptionMethod int

const (
StandardEncryption EncryptionMethod = 1
AES128Encryption EncryptionMethod = 2
AES192Encryption EncryptionMethod = 3
AES256Encryption EncryptionMethod = 4

// AES key lengths
aes128 = 16
aes192 = 24
Expand Down Expand Up @@ -379,18 +386,20 @@ func encryptStream(key []byte, w io.Writer) (io.Writer, error) {
// newEncryptionWriter returns an io.Writer that when written to, 1. writes
// out the salt, 2. writes out pwv, and 3. writes out authenticated, encrypted
// data. The authcode will be written out in fileWriter.close().
func newEncryptionWriter(w io.Writer, password passwordFn, fw *fileWriter) (io.Writer, error) {
var salt [16]byte
func newEncryptionWriter(w io.Writer, password passwordFn, fw *fileWriter, aesstrength byte) (io.Writer, error) {
keysize := aesKeyLen(aesstrength)
salt := make([]byte, keysize/2)
_, err := rand.Read(salt[:])
if err != nil {
return nil, errors.New("zip: unable to generate random salt")
}
ekey, akey, pwv := generateKeys(password(), salt[:], aes256)
ekey, akey, pwv := generateKeys(password(), salt[:], keysize)
fw.hmac = hmac.New(sha1.New, akey)
aw := &authWriter{
hmac: fw.hmac,
w: w,
}

es, err := encryptStream(ekey, aw)
if err != nil {
return nil, err
Expand Down Expand Up @@ -424,11 +433,23 @@ func (h *FileHeader) writeWinZipExtra() {
eb.uint16(7) // following data size is 7
eb.uint16(2) // ae 2
eb.uint16(0x4541) // "AE"
eb.uint8(3) // aes256
eb.uint8(h.aesStrength) // aes256
eb.uint16(h.Method) // original compression method
h.Extra = append(h.Extra, buf[:]...)
}

func (h *FileHeader) SetEncryptionMethod(enc EncryptionMethod) {
h.encryption = enc
switch enc {
case AES128Encryption:
h.aesStrength = 1
case AES192Encryption:
h.aesStrength = 2
case AES256Encryption:
h.aesStrength = 3
}
}

func (h *FileHeader) setEncryptionBit() {
h.Flags |= 0x1
}
Expand All @@ -452,11 +473,12 @@ type passwordFn func() []byte
// contents will be encrypted with AES-256 using the given password. The
// file's contents must be written to the io.Writer before the next call
// to Create, CreateHeader, or Close.
func (w *Writer) Encrypt(name string, password string) (io.Writer, error) {
func (w *Writer) Encrypt(name string, password string, enc EncryptionMethod) (io.Writer, error) {
fh := &FileHeader{
Name: name,
Method: Deflate,
}
fh.SetPassword(password)
fh.SetEncryptionMethod(enc)
return w.CreateHeader(fh)
}
Loading