forked from mirror/zip
Change README to include example
This commit is contained in:
parent
d851e4060f
commit
6c433e67d3
|
@ -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))
|
||||
}
|
||||
}
|
||||
```
|
112
README.txt
112
README.txt
|
@ -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
|
|
@ -22,10 +22,10 @@ import (
|
|||
type EncryptionMethod int
|
||||
|
||||
const (
|
||||
ZipStandardEncryption EncryptionMethod = 1
|
||||
AES128Encryption EncryptionMethod = 2
|
||||
AES192Encryption EncryptionMethod = 3
|
||||
AES256Encryption EncryptionMethod = 4
|
||||
StandardEncryption EncryptionMethod = 1
|
||||
AES128Encryption EncryptionMethod = 2
|
||||
AES192Encryption EncryptionMethod = 3
|
||||
AES256Encryption EncryptionMethod = 4
|
||||
|
||||
// AES key lengths
|
||||
aes128 = 16
|
||||
|
|
|
@ -175,7 +175,7 @@ func TestPasswordWriteSimple(t *testing.T) {
|
|||
contents := []byte("Hello World")
|
||||
conLen := len(contents)
|
||||
|
||||
for _, enc := range []EncryptionMethod{ZipStandardEncryption, AES128Encryption, AES192Encryption, AES256Encryption} {
|
||||
for _, enc := range []EncryptionMethod{StandardEncryption, AES128Encryption, AES192Encryption, AES256Encryption} {
|
||||
raw := new(bytes.Buffer)
|
||||
zipw := NewWriter(raw)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang", enc)
|
||||
|
@ -223,7 +223,7 @@ func TestZipCrypto(t *testing.T) {
|
|||
|
||||
raw := new(bytes.Buffer)
|
||||
zipw := NewWriter(raw)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang", ZipStandardEncryption)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang", StandardEncryption)
|
||||
if err != nil {
|
||||
t.Errorf("Expected to create a new FileHeader")
|
||||
}
|
||||
|
|
|
@ -229,7 +229,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
|||
// check for password
|
||||
var sw io.Writer = fw.compCount
|
||||
if fh.password != nil {
|
||||
if fh.encryption == ZipStandardEncryption {
|
||||
if fh.encryption == StandardEncryption {
|
||||
ew, err := ZipCryptoEncryptor(sw, fh.password, fw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -321,7 +321,7 @@ func (w *fileWriter) close() error {
|
|||
return err
|
||||
}
|
||||
// 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 = authCode[:10]
|
||||
_, err := w.compCount.Write(authCode)
|
||||
|
@ -332,7 +332,7 @@ func (w *fileWriter) close() error {
|
|||
// update FileHeader
|
||||
fh := w.header.FileHeader
|
||||
// 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.CompressedSize64 = uint64(w.compCount.count)
|
||||
|
|
Loading…
Reference in New Issue