Change README to include example

This commit is contained in:
yeka 2018-02-23 12:32:53 +07:00
parent d851e4060f
commit 6c433e67d3
5 changed files with 100 additions and 121 deletions

91
README.md Normal file
View File

@ -0,0 +1,91 @@
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"
"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))
}
}
```

View File

@ -1,112 +0,0 @@
This fork add support for Standard Zip Encryption.
https://github.com/yeka/zip
This is a fork of the Go archive/zip package to add support
for reading/writing password protected .zip files.
Only supports Winzip's AES extension: http://www.winzip.com/aes_info.htm.
This package DOES NOT intend to implement the encryption methods
mentioned in the original PKWARE spec (sections 6.0 and 7.0):
https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
Status - Alpha. More tests and code clean up next.
Documentation -
https://godoc.org/github.com/alexmullins/zip
Roadmap
========
Reading - Done.
Writing - Done.
Testing - Needs more.
The process
============
1. hello.txt -> compressed -> encrypted -> .zip
2. .zip -> decrypted -> decompressed -> hello.txt
Example Encrypt zip
==========
```
package main
import (
"bytes"
"log"
"os"
"github.com/alexmullins/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`)
if err != nil {
log.Fatal(err)
}
_, err = io.Copy(w, bytes.NewReader(contents))
if err != nil {
log.Fatal(err)
}
zipw.Flush()
}
```
WinZip AES specifies
=====================
1. Encryption-Decryption w/ AES-CTR (128, 192, or 256 bits)
2. Key generation with PBKDF2-HMAC-SHA1 (1000 iteration count) that
generates a master key broken into the following:
a. First m bytes is for the encryption key
b. Next n bytes is for the authentication key
c. Last 2 bytes is the password verification value.
3. Following salt lengths are used w/ password during keygen:
------------------------------
AES Key Size | Salt Size
------------------------------
128bit(16bytes) | 8 bytes
192bit(24bytes) | 12 bytes
256bit(32bytes) | 16 bytes
-------------------------------
4. Master key len = AESKeyLen + AuthKeyLen + PWVLen:
a. AES 128 = 16 + 16 + 2 = 34 bytes of key material
b. AES 192 = 24 + 24 + 2 = 50 bytes of key material
c. AES 256 = 32 + 32 + 2 = 66 bytes of key material
5. Authentication Key is same size as AES key.
6. Authentication with HMAC-SHA1-80 (truncated to 80bits).
7. A new master key is generated for every file.
8. The file header and directory header compression method will
be 99 (decimal) indicating Winzip AES encryption. The actual
compression method will be in the extra's payload at the end
of the headers.
9. A extra field will be added to the file header and directory
header identified by the ID 0x9901 and contains the following info:
a. Header ID (2 bytes)
b. Data Size (2 bytes)
c. Vendor Version (2 bytes)
d. Vendor ID (2 bytes)
e. AES Strength (1 byte)
f. Compression Method (2 bytes)
10. The Data Size is always 7.
11. The Vendor Version can be either 0x0001 (AE-1) or
0x0002 (AE-2).
12. Vendor ID is ASCII "AE"
13. AES Strength:
a. 0x01 - AES-128
b. 0x02 - AES-192
c. 0x03 - AES-256
14. Compression Method is the actual compression method
used that was replaced by the encryption process mentioned in #8.
15. AE-1 keeps the CRC and should be verified after decompression.
AE-2 removes the CRC and shouldn't be verified after decompression.
Refer to http://www.winzip.com/aes_info.htm#winzip11 for the reasoning.
16. Storage Format (file data payload totals CompressedSize64 bytes):
a. Salt - 8, 12, or 16 bytes depending on keysize
b. Password Verification Value - 2 bytes
c. Encrypted Data - compressed size - salt - pwv - auth code lengths
d. Authentication code - 10 bytes

View File

@ -22,7 +22,7 @@ import (
type EncryptionMethod int type EncryptionMethod int
const ( const (
ZipStandardEncryption EncryptionMethod = 1 StandardEncryption EncryptionMethod = 1
AES128Encryption EncryptionMethod = 2 AES128Encryption EncryptionMethod = 2
AES192Encryption EncryptionMethod = 3 AES192Encryption EncryptionMethod = 3
AES256Encryption EncryptionMethod = 4 AES256Encryption EncryptionMethod = 4

View File

@ -175,7 +175,7 @@ func TestPasswordWriteSimple(t *testing.T) {
contents := []byte("Hello World") contents := []byte("Hello World")
conLen := len(contents) conLen := len(contents)
for _, enc := range []EncryptionMethod{ZipStandardEncryption, AES128Encryption, AES192Encryption, AES256Encryption} { for _, enc := range []EncryptionMethod{StandardEncryption, AES128Encryption, AES192Encryption, AES256Encryption} {
raw := new(bytes.Buffer) raw := new(bytes.Buffer)
zipw := NewWriter(raw) zipw := NewWriter(raw)
w, err := zipw.Encrypt("hello.txt", "golang", enc) w, err := zipw.Encrypt("hello.txt", "golang", enc)
@ -223,7 +223,7 @@ func TestZipCrypto(t *testing.T) {
raw := new(bytes.Buffer) raw := new(bytes.Buffer)
zipw := NewWriter(raw) zipw := NewWriter(raw)
w, err := zipw.Encrypt("hello.txt", "golang", ZipStandardEncryption) w, err := zipw.Encrypt("hello.txt", "golang", StandardEncryption)
if err != nil { if err != nil {
t.Errorf("Expected to create a new FileHeader") t.Errorf("Expected to create a new FileHeader")
} }

View File

@ -229,7 +229,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
// check for password // check for password
var sw io.Writer = fw.compCount var sw io.Writer = fw.compCount
if fh.password != nil { if fh.password != nil {
if fh.encryption == ZipStandardEncryption { if fh.encryption == StandardEncryption {
ew, err := ZipCryptoEncryptor(sw, fh.password, fw) ew, err := ZipCryptoEncryptor(sw, fh.password, fw)
if err != nil { if err != nil {
return nil, err return nil, err
@ -321,7 +321,7 @@ func (w *fileWriter) close() error {
return err return err
} }
// if encrypted grab the hmac and write it out // if encrypted grab the hmac and write it out
if w.header.IsEncrypted() && w.header.encryption != ZipStandardEncryption { if w.header.IsEncrypted() && w.header.encryption != StandardEncryption {
authCode := w.hmac.Sum(nil) authCode := w.hmac.Sum(nil)
authCode = authCode[:10] authCode = authCode[:10]
_, err := w.compCount.Write(authCode) _, err := w.compCount.Write(authCode)
@ -332,7 +332,7 @@ func (w *fileWriter) close() error {
// update FileHeader // update FileHeader
fh := w.header.FileHeader fh := w.header.FileHeader
// ae-2 we don't write out CRC // ae-2 we don't write out CRC
if !fh.IsEncrypted() || fh.encryption == ZipStandardEncryption { if !fh.IsEncrypted() || fh.encryption == StandardEncryption {
fh.CRC32 = w.crc32.Sum32() fh.CRC32 = w.crc32.Sum32()
} }
fh.CompressedSize64 = uint64(w.compCount.count) fh.CompressedSize64 = uint64(w.compCount.count)