forked from mirror/zip
Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
yeka | 9a620c6cd3 |
20
LICENSE
20
LICENSE
|
@ -1,20 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (C) 2015 Alex Mullins
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
92
README.md
92
README.md
|
@ -1,92 +0,0 @@
|
|||
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"
|
||||
|
||||
"git.internal/re/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"
|
||||
|
||||
"git.internal/re/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))
|
||||
}
|
||||
}
|
||||
```
|
|
@ -0,0 +1,77 @@
|
|||
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
|
||||
|
||||
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
|
39
crypto.go
39
crypto.go
|
@ -19,14 +19,7 @@ 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
|
||||
|
@ -386,14 +379,13 @@ 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, aesstrength byte) (io.Writer, error) {
|
||||
keysize := aesKeyLen(aesstrength)
|
||||
salt := make([]byte, keysize / 2)
|
||||
func newEncryptionWriter(w io.Writer, password passwordFn, fw *fileWriter) (io.Writer, error) {
|
||||
var salt [16]byte
|
||||
_, err := rand.Read(salt[:])
|
||||
if err != nil {
|
||||
return nil, errors.New("zip: unable to generate random salt")
|
||||
}
|
||||
ekey, akey, pwv := generateKeys(password(), salt[:], keysize)
|
||||
ekey, akey, pwv := generateKeys(password(), salt[:], aes256)
|
||||
fw.hmac = hmac.New(sha1.New, akey)
|
||||
aw := &authWriter{
|
||||
hmac: fw.hmac,
|
||||
|
@ -432,23 +424,11 @@ func (h *FileHeader) writeWinZipExtra() {
|
|||
eb.uint16(7) // following data size is 7
|
||||
eb.uint16(2) // ae 2
|
||||
eb.uint16(0x4541) // "AE"
|
||||
eb.uint8(h.aesStrength) // aes256
|
||||
eb.uint8(3) // 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
|
||||
}
|
||||
|
@ -463,6 +443,12 @@ func (h *FileHeader) SetPassword(password string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (h *FileHeader) SetDecryptionPassword(password string) {
|
||||
h.password = func() []byte {
|
||||
return []byte(password)
|
||||
}
|
||||
}
|
||||
|
||||
// PasswordFn is a function that returns the password
|
||||
// as a byte slice
|
||||
type passwordFn func() []byte
|
||||
|
@ -472,12 +458,11 @@ 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, enc EncryptionMethod) (io.Writer, error) {
|
||||
func (w *Writer) Encrypt(name string, password string) (io.Writer, error) {
|
||||
fh := &FileHeader{
|
||||
Name: name,
|
||||
Method: Deflate,
|
||||
}
|
||||
fh.SetPassword(password)
|
||||
fh.setEncryptionMethod(enc)
|
||||
fh.SetDecryptionPassword(password)
|
||||
return w.CreateHeader(fh)
|
||||
}
|
||||
|
|
|
@ -175,10 +175,9 @@ func TestPasswordWriteSimple(t *testing.T) {
|
|||
contents := []byte("Hello World")
|
||||
conLen := len(contents)
|
||||
|
||||
for _, enc := range []EncryptionMethod{StandardEncryption, AES128Encryption, AES192Encryption, AES256Encryption} {
|
||||
raw := new(bytes.Buffer)
|
||||
zipw := NewWriter(raw)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang", enc)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang")
|
||||
if err != nil {
|
||||
t.Errorf("Expected to create a new FileHeader")
|
||||
}
|
||||
|
@ -214,33 +213,4 @@ func TestPasswordWriteSimple(t *testing.T) {
|
|||
if !bytes.Equal(contents, buf.Bytes()) {
|
||||
t.Errorf("Expected the unzipped contents to equal '%s', but was '%s' instead", contents, buf.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestZipCrypto(t *testing.T) {
|
||||
contents := []byte("Hello World")
|
||||
conLen := len(contents)
|
||||
|
||||
raw := new(bytes.Buffer)
|
||||
zipw := NewWriter(raw)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang", StandardEncryption)
|
||||
if err != nil {
|
||||
t.Errorf("Expected to create a new FileHeader")
|
||||
}
|
||||
n, err := io.Copy(w, bytes.NewReader(contents))
|
||||
if err != nil || n != int64(conLen) {
|
||||
t.Errorf("Expected to write the full contents to the writer.")
|
||||
}
|
||||
zipw.Close()
|
||||
|
||||
zipr, _ := NewReader(bytes.NewReader(raw.Bytes()), int64(raw.Len()))
|
||||
zipr.File[0].SetPassword("golang")
|
||||
r, _ := zipr.File[0].Open()
|
||||
res := new(bytes.Buffer)
|
||||
io.Copy(res, r)
|
||||
r.Close()
|
||||
|
||||
if !bytes.Equal(contents, res.Bytes()) {
|
||||
t.Errorf("Expected the unzipped contents to equal '%s', but was '%s' instead", contents, res.Bytes())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"git.internal/re/zip"
|
||||
"github.com/alexmullins/zip"
|
||||
)
|
||||
|
||||
func ExampleWriter() {
|
||||
|
@ -22,7 +22,7 @@ func ExampleWriter() {
|
|||
w := zip.NewWriter(buf)
|
||||
|
||||
// Add some files to the archive.
|
||||
files := []struct {
|
||||
var files = []struct {
|
||||
Name, Body string
|
||||
}{
|
||||
{"readme.txt", "This archive contains some text files."},
|
||||
|
@ -81,7 +81,7 @@ func ExampleWriter_Encrypt() {
|
|||
// write a password zip
|
||||
raw := new(bytes.Buffer)
|
||||
zipw := zip.NewWriter(raw)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang", zip.AES256Encryption)
|
||||
w, err := zipw.Encrypt("hello.txt", "golang")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
11
reader.go
11
reader.go
|
@ -143,10 +143,11 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
|
|||
size := int64(f.CompressedSize64)
|
||||
var r io.Reader
|
||||
rr := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
|
||||
|
||||
// check for encryption
|
||||
if f.IsEncrypted() {
|
||||
|
||||
if f.ae == 0 {
|
||||
fmt.Printf("CRC32: %X ---- %v\n", f.CRC32, f.CRC32)
|
||||
if r, err = ZipCryptoDecryptor(rr, f.password()); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -156,6 +157,7 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
|
|||
} else {
|
||||
r = rr
|
||||
}
|
||||
|
||||
dcomp := decompressor(f.Method)
|
||||
if dcomp == nil {
|
||||
err = ErrAlgorithm
|
||||
|
@ -259,14 +261,21 @@ func readDirectoryHeader(f *File, r io.Reader) error {
|
|||
f.CreatorVersion = b.uint16()
|
||||
f.ReaderVersion = b.uint16()
|
||||
f.Flags = b.uint16()
|
||||
fmt.Printf("FLAG: %X\n", f.Flags)
|
||||
f.Method = b.uint16()
|
||||
fmt.Printf("METHOD: %X\n", f.Method)
|
||||
f.ModifiedTime = b.uint16()
|
||||
f.ModifiedDate = b.uint16()
|
||||
f.CRC32 = b.uint32()
|
||||
fmt.Printf("Directory CRC: %X\n", f.CRC32)
|
||||
f.CompressedSize = b.uint32()
|
||||
f.UncompressedSize = b.uint32()
|
||||
f.CompressedSize64 = uint64(f.CompressedSize)
|
||||
f.UncompressedSize64 = uint64(f.UncompressedSize)
|
||||
fmt.Printf("ZIP Size 1: %v\n", f.CompressedSize)
|
||||
fmt.Printf("ZIP Size 2: %v\n", f.CompressedSize64)
|
||||
fmt.Printf("File Size 1: %v\n", f.UncompressedSize)
|
||||
fmt.Printf("File Size 2: %v\n", f.UncompressedSize64)
|
||||
filenameLen := int(b.uint16())
|
||||
extraLen := int(b.uint16())
|
||||
commentLen := int(b.uint16())
|
||||
|
|
|
@ -101,7 +101,6 @@ type FileHeader struct {
|
|||
// https://www.imperialviolet.org/2015/05/16/aeads.html
|
||||
DeferAuth bool
|
||||
|
||||
encryption EncryptionMethod
|
||||
password passwordFn // Returns the password to use when reading/writing
|
||||
ae uint16
|
||||
aesStrength byte
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Int int
|
||||
|
||||
func (i *Int) Incr(n int) Int {
|
||||
*i = (*i) + Int(n)
|
||||
return *i
|
||||
}
|
||||
|
||||
|
||||
func main() {
|
||||
i := Int(10)
|
||||
i.Incr(12)
|
||||
fmt.Println(i)
|
||||
|
||||
b := &Bytes{b: []byte{1, 2, 3, 4, 5}, i: 0}
|
||||
c := b.Get(0, 3)
|
||||
c[1] = 11
|
||||
fmt.Println(b)
|
||||
fmt.Println(c)
|
||||
|
||||
j := &Bytes{b: []byte{1, 2, 3, 4, 5}, i: 0}
|
||||
k := j.IGet(3)
|
||||
l := j.IGet(2)
|
||||
k[0] = 10
|
||||
l[0] = 11
|
||||
fmt.Println(j)
|
||||
fmt.Println(k)
|
||||
fmt.Println(l)
|
||||
}
|
|
@ -0,0 +1,544 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
zip2 "github.com/yeka/zip"
|
||||
"bytes"
|
||||
"os"
|
||||
"io"
|
||||
"fmt"
|
||||
"archive/zip"
|
||||
"log"
|
||||
"hash/crc32"
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//fmt.Printf("%X\n", crc32.Update(0, crc32.IEEETable, []byte{0}))
|
||||
//return
|
||||
|
||||
password := "zipcrypto"
|
||||
new(ZipReader).FromBytes(createzip(password), password)
|
||||
new(ZipReader).Open("java2.zip", password) // FA176C7F
|
||||
|
||||
os.Remove("myzip/test1.zip")
|
||||
ioutil.WriteFile("myzip/test1.zip", createzip(password), os.ModePerm)
|
||||
return
|
||||
//z.Open("java2.zip", "zipcrypto") // FA176C7F
|
||||
//z.Open("java.zip", "123")
|
||||
|
||||
//z.Open("a.zip")
|
||||
//z.Open("test.zip")
|
||||
fmt.Println("=======================================")
|
||||
return
|
||||
//unknown1()
|
||||
//show("java.zip", "zipcrypto")
|
||||
zipunzip()
|
||||
return
|
||||
fmt.Printf("%X\n", 878082192)
|
||||
show("banyak.zip", "123")
|
||||
//show("pass.zip", "zipcrypto")
|
||||
//show("java.zip", "zipcrypto")
|
||||
//show("a.zip", "aa") // Incorrect password
|
||||
//show("test.zip", "")
|
||||
|
||||
fmt.Printf("%b\n", zip2.Crc32update(0, 0))
|
||||
h := crc32.NewIEEE()
|
||||
h.Write([]byte{0})
|
||||
fmt.Printf("%b\n", h.Sum32())
|
||||
fmt.Printf("%b\n", crc32.Update(0, crc32.IEEETable, []byte{0}))
|
||||
|
||||
}
|
||||
|
||||
func play1() {
|
||||
de := []byte("hello")
|
||||
//e := zip.NewZipCrypto([]byte("Passwordnya panjang banget kk"))
|
||||
//en := e.EncryptMessage([]byte("Hello Worlds Muahaha"))
|
||||
//d := zip.NewZipCrypto([]byte("Passwordnya panjang banget kk"))
|
||||
//de = d.DecryptMessage(en)
|
||||
fmt.Println(string(de))
|
||||
|
||||
os.Exit(0)
|
||||
buf := new(bytes.Buffer)
|
||||
//a := zip.NewWriter(buf)
|
||||
//w, _ := a.Create("a.txt")
|
||||
//w.Write([]byte(`Hello World`))
|
||||
//a.Close()
|
||||
|
||||
f, _ := os.Create("temp/test.zip")
|
||||
io.Copy(f, buf)
|
||||
f.Close()
|
||||
|
||||
_ = zip.Deflate
|
||||
}
|
||||
|
||||
func show(filename string, password string) {
|
||||
r, err := zip2.OpenReader(filename)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
for _, f := range r.File {
|
||||
fmt.Printf("------ %s ------\n", f.Name)
|
||||
|
||||
f.SetDecryptionPassword(password)
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
fmt.Println("Opening error")
|
||||
log.Print(err)
|
||||
continue
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
if _, err = io.Copy(buf, rc); err != nil {
|
||||
fmt.Println("buffering error")
|
||||
log.Print(err)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("Size: %d\nContent:\n", buf.Len())
|
||||
fmt.Println(string(buf.Bytes()))
|
||||
//fmt.Println(buf.Bytes())
|
||||
rc.Close()
|
||||
fmt.Println()
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
func createzip(password string) []byte {
|
||||
fmt.Printf("\n\n========================== Writing ========================== \n\n")
|
||||
mydata, _ := ioutil.ReadFile("a.java")
|
||||
b := new(bytes.Buffer)
|
||||
z := zip2.NewWriter(b)
|
||||
//w, _ := z.Create("a.java")
|
||||
w, _ := z.Encrypt("a.java", password)
|
||||
fmt.Println(w.Write(mydata))
|
||||
z.Close()
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func zipunzip() {
|
||||
fmt.Printf("\n\n========================== Writing ========================== \n\n")
|
||||
mydata := []byte(`Hello World`)
|
||||
password := "golang"
|
||||
b := new(bytes.Buffer)
|
||||
z := zip2.NewWriter(b)
|
||||
//w, _ := z.Create("a.txt")
|
||||
w, _ := z.Encrypt("a.txt", password)
|
||||
fmt.Println(w.Write(mydata))
|
||||
z.Close()
|
||||
|
||||
fmt.Printf("\n\n========================== Reading ========================== \n\n")
|
||||
rz, _ := zip2.NewReader(bytes.NewReader(b.Bytes()), int64(b.Len()))
|
||||
rz.File[0].SetDecryptionPassword(password)
|
||||
r, _ := rz.File[0].Open()
|
||||
myresult := new(bytes.Buffer)
|
||||
io.Copy(myresult, r)
|
||||
r.Close()
|
||||
|
||||
fmt.Println(mydata)
|
||||
fmt.Println(myresult.Bytes())
|
||||
fmt.Println(0 == bytes.Compare(mydata, myresult.Bytes()))
|
||||
}
|
||||
|
||||
func unknown1() {
|
||||
hello := []byte("Hello world\n")
|
||||
b := new(bytes.Buffer)
|
||||
|
||||
l := &zipwriterboongan{b}
|
||||
c := &zipwriterboongan{l}
|
||||
//m := &minues{l}
|
||||
//c := &minues2{m}
|
||||
//
|
||||
////i := io.MultiWriter(b, m, l, c)
|
||||
//c.Write(hello)
|
||||
c.Write(hello)
|
||||
fmt.Println(string(b.Bytes()))
|
||||
}
|
||||
|
||||
type zipwriterboongan struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (m *zipwriterboongan) Write(p []byte) (i int, err error) {
|
||||
temp := make([]byte, len(p))
|
||||
for i, b := range p {
|
||||
temp[i] = b ^ 0xFF
|
||||
}
|
||||
m.w.Write(temp)
|
||||
return
|
||||
}
|
||||
|
||||
type ftpwriterboongan struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (m *ftpwriterboongan) Write(p []byte) (i int, err error) {
|
||||
temp := make([]byte, len(p))
|
||||
for i, b := range p {
|
||||
temp[i] = b ^ 0xFF
|
||||
}
|
||||
m.w.Write(temp)
|
||||
return
|
||||
}
|
||||
|
||||
type ZipReader struct {
|
||||
b *Bytes
|
||||
password []byte
|
||||
files []*ZipFile
|
||||
central_dir []*ZipCentralDirectory
|
||||
dir_end *ZipDirectoryEnd
|
||||
}
|
||||
|
||||
type ZipFile struct {
|
||||
zip *ZipReader
|
||||
header *ZipFileHeader
|
||||
data *ZipFileData
|
||||
descriptor *ZipFileDescriptor
|
||||
}
|
||||
|
||||
func (zf *ZipFile) init(offset, datasize uint64) {
|
||||
h := &ZipFileHeader{file: zf}
|
||||
h.init(offset)
|
||||
|
||||
f := &ZipFileData{file: zf}
|
||||
f.content = zf.zip.b.IGet(datasize)
|
||||
|
||||
e := &ZipFileDescriptor{file: zf}
|
||||
if u16x(h.general_purpose_bit_flag) & 8 > 0 {
|
||||
e.init(zf.zip.b.Pos())
|
||||
}
|
||||
|
||||
zf.header = h
|
||||
zf.data = f
|
||||
zf.descriptor = e
|
||||
}
|
||||
|
||||
type ZipFileHeader struct {
|
||||
file *ZipFile
|
||||
local_file_header_signature []byte
|
||||
version_needed_to_extract []byte
|
||||
general_purpose_bit_flag []byte
|
||||
compression_method []byte
|
||||
last_mod_file_time []byte
|
||||
last_mod_file_date []byte
|
||||
crc_32 []byte
|
||||
compressed_size []byte
|
||||
uncompressed_size []byte
|
||||
filename_length []byte
|
||||
extra_field_length []byte
|
||||
filename []byte
|
||||
extra_field []byte
|
||||
}
|
||||
|
||||
func (fh *ZipFileHeader) init(offset uint64) {
|
||||
b := fh.file.zip.b
|
||||
b.Offset(offset)
|
||||
fh.local_file_header_signature = b.IGet(4)
|
||||
fh.version_needed_to_extract = b.IGet(2)
|
||||
fh.general_purpose_bit_flag = b.IGet(2)
|
||||
fh.compression_method = b.IGet(2)
|
||||
fh.last_mod_file_time = b.IGet(2)
|
||||
fh.last_mod_file_date = b.IGet(2)
|
||||
fh.crc_32 = b.IGet(4)
|
||||
fh.compressed_size = b.IGet(4)
|
||||
fh.uncompressed_size = b.IGet(4)
|
||||
fh.filename_length = b.IGet(2)
|
||||
fh.extra_field_length = b.IGet(2)
|
||||
fh.filename = b.IGet(u16x(fh.filename_length))
|
||||
fh.extra_field = b.IGet(u16x(fh.extra_field_length))
|
||||
}
|
||||
|
||||
type ZipFileData struct {
|
||||
file *ZipFile
|
||||
content []byte
|
||||
}
|
||||
|
||||
type ZipFileDescriptor struct {
|
||||
file *ZipFile
|
||||
signature []byte
|
||||
crc_32 []byte
|
||||
compressed_size []byte
|
||||
uncompressed_size []byte
|
||||
}
|
||||
|
||||
func (fd *ZipFileDescriptor) init(offset uint64) {
|
||||
b := fd.file.zip.b
|
||||
b.Offset(offset)
|
||||
sig := b.IGet(4)
|
||||
if u32x(sig) == 0x08074b50 {
|
||||
fd.signature = sig
|
||||
fd.crc_32 = b.IGet(4)
|
||||
} else {
|
||||
fd.crc_32 = sig
|
||||
}
|
||||
fd.compressed_size = b.IGet(4)
|
||||
fd.uncompressed_size = b.IGet(4)
|
||||
}
|
||||
|
||||
type ZipCentralDirectory struct {
|
||||
zip *ZipReader
|
||||
central_file_header_signature []byte
|
||||
version_made_by []byte
|
||||
version_needed_to_extrac []byte
|
||||
general_purpose_bit_flag []byte
|
||||
compression_method []byte
|
||||
last_mod_file_time []byte
|
||||
last_mod_file_date []byte
|
||||
crc_32 []byte
|
||||
compressed_size []byte
|
||||
uncompressed_size []byte
|
||||
filename_length []byte
|
||||
extra_field_length []byte
|
||||
file_comment_length []byte
|
||||
disk_num_start []byte
|
||||
internal_file_attr []byte
|
||||
external_file_attr []byte
|
||||
local_header_relative_offset []byte
|
||||
filename []byte
|
||||
extra_field []byte
|
||||
file_comment []byte
|
||||
}
|
||||
|
||||
func (cd *ZipCentralDirectory) init(offset uint64) (size uint64) {
|
||||
cd.zip.b.Offset(offset)
|
||||
cd.central_file_header_signature = cd.zip.b.IGet(4)
|
||||
cd.version_made_by = cd.zip.b.IGet(2)
|
||||
cd.version_needed_to_extrac = cd.zip.b.IGet(2)
|
||||
cd.general_purpose_bit_flag = cd.zip.b.IGet(2)
|
||||
cd.compression_method = cd.zip.b.IGet(2)
|
||||
cd.last_mod_file_time = cd.zip.b.IGet(2)
|
||||
cd.last_mod_file_date = cd.zip.b.IGet(2)
|
||||
cd.crc_32 = cd.zip.b.IGet(4)
|
||||
cd.compressed_size = cd.zip.b.IGet(4)
|
||||
cd.uncompressed_size = cd.zip.b.IGet(4)
|
||||
cd.filename_length = cd.zip.b.IGet(2)
|
||||
cd.extra_field_length = cd.zip.b.IGet(2)
|
||||
cd.file_comment_length = cd.zip.b.IGet(2)
|
||||
cd.disk_num_start = cd.zip.b.IGet(2)
|
||||
cd.internal_file_attr = cd.zip.b.IGet(2)
|
||||
cd.external_file_attr = cd.zip.b.IGet(4)
|
||||
cd.local_header_relative_offset = cd.zip.b.IGet(4)
|
||||
cd.filename = cd.zip.b.IGet(u16x(cd.filename_length))
|
||||
cd.extra_field = cd.zip.b.IGet(u16x(cd.extra_field_length))
|
||||
cd.file_comment = cd.zip.b.IGet(u16x(cd.file_comment_length))
|
||||
size = 46 + u16x(cd.filename_length) + u16x(cd.extra_field_length) + u16x(cd.file_comment_length)
|
||||
return
|
||||
}
|
||||
|
||||
type ZipDirectoryEnd struct {
|
||||
zip *ZipReader
|
||||
signature []byte
|
||||
disknum []byte
|
||||
disknum_start_of_central_directory []byte
|
||||
entries_in_this_disk []byte
|
||||
num_of_entries []byte
|
||||
size_of_central_dir []byte
|
||||
offset_of_central_dir []byte
|
||||
zipfile_comment_length []byte
|
||||
zipfile_comment []byte
|
||||
}
|
||||
|
||||
func (zde *ZipDirectoryEnd) init(offset uint64) {
|
||||
zde.zip.b.Offset(offset)
|
||||
zde.signature = zde.zip.b.IGet(4)
|
||||
zde.disknum = zde.zip.b.IGet(2)
|
||||
zde.disknum_start_of_central_directory = zde.zip.b.IGet(2)
|
||||
zde.entries_in_this_disk = zde.zip.b.IGet(2)
|
||||
zde.num_of_entries = zde.zip.b.IGet(2)
|
||||
zde.size_of_central_dir = zde.zip.b.IGet(4)
|
||||
zde.offset_of_central_dir = zde.zip.b.IGet(4)
|
||||
zde.zipfile_comment_length = zde.zip.b.IGet(2)
|
||||
zde.zipfile_comment = zde.zip.b.IGet(u16x(zde.zipfile_comment_length))
|
||||
}
|
||||
|
||||
func (z *ZipReader) FromBytes(buf []byte, password string) {
|
||||
z.b = &Bytes{buf, 0}
|
||||
z.password = []byte(password)
|
||||
z.Init()
|
||||
}
|
||||
|
||||
func (z *ZipReader) Open(filename string, password string) {
|
||||
buf, _ := ioutil.ReadFile(filename)
|
||||
z.FromBytes(buf, password)
|
||||
}
|
||||
|
||||
func (z *ZipReader) Init() {
|
||||
// First find Directory End
|
||||
var i uint64
|
||||
for i = uint64(len(z.b.b)) - 22; i >= 0; i-- {
|
||||
if z.b.BGet(i, 4).I64() == 0x06054b50 {
|
||||
z.dir_end = &ZipDirectoryEnd{zip: z}
|
||||
z.dir_end.init(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Read all Central Directory Header
|
||||
central_dir_offset := u16x(z.dir_end.offset_of_central_dir)
|
||||
for i = 0; i < u16x(z.dir_end.num_of_entries); i++ {
|
||||
cdfh := &ZipCentralDirectory{zip: z}
|
||||
central_dir_offset += cdfh.init(central_dir_offset)
|
||||
z.central_dir = append(z.central_dir, cdfh)
|
||||
}
|
||||
|
||||
for i = 0; i < u16x(z.dir_end.num_of_entries); i++ {
|
||||
zf := &ZipFile{zip: z}
|
||||
zf.init(u32x(z.central_dir[i].local_header_relative_offset), u32x(z.central_dir[i].compressed_size))
|
||||
z.files = append(z.files, zf)
|
||||
}
|
||||
|
||||
fmt.Printf("%0 X\n", z.files[0].header)
|
||||
fmt.Printf("%0 X\n", z.files[0].descriptor)
|
||||
// PlayGround
|
||||
//fmt.Printf("%v\n", z.files[0].data.content)
|
||||
//zc := zip2.NewZipCrypto(z.password)
|
||||
//buf := zc.DecryptMessage(z.files[0].data.content)
|
||||
////fmt.Printf("%v\n", buf)
|
||||
//rc := flate.NewReader(bytes.NewBuffer(buf[12:]))
|
||||
//defer rc.Close()
|
||||
//res, err := ioutil.ReadAll(rc)
|
||||
//if err != nil {
|
||||
// fmt.Println(err.Error())
|
||||
//}
|
||||
//fmt.Printf("%v\n", string(res))
|
||||
|
||||
//fmt.Printf("---------------- %v ----------------\n", string(h.filename))
|
||||
//fmt.Printf("Signature: %02X\n", h.local_file_header_signature)
|
||||
//fmt.Printf("Version: %v\n", h.version_needed_to_extract)
|
||||
//fmt.Printf("General Purpose Bit Flag: %08b\n", h.general_purpose_bit_flag)
|
||||
//fmt.Printf("Compression Method: %v\n", h.compression_method)
|
||||
//fmt.Printf("CRC32: %0 X, Compressed: %v, Uncompressed: %v\n", h.crc_32, u16x(h.compressed_size), u16x(h.uncompressed_size))
|
||||
//fmt.Printf("FileName Length: %v\n", u16x(h.filename_length))
|
||||
//fmt.Printf("ExtraField Length: %v\n", u16x(h.extra_field_length))
|
||||
//fmt.Printf("ExtraField: %0 X\n", h.extra_field)
|
||||
//if u16x(h.general_purpose_bit_flag) & 8 > 0 {
|
||||
// crc32 := z.b.IGet(4)
|
||||
// if u32x(crc32) == 0x08074b50 {
|
||||
// // Signature may or may not be there
|
||||
// crc32 = z.b.IGet(4)
|
||||
// }
|
||||
// csize := z.b.IGet(4)
|
||||
// usize := z.b.IGet(4)
|
||||
// fmt.Printf("DataDescriptor:\nCRC32: %0 X, Compressed: %v, Uncompressed: %v, Next Signature: %X\n", crc32, u16x(csize), u16x(usize), z.b.IGet(4))
|
||||
//}
|
||||
//
|
||||
//crcbuf := make([]byte, 4)
|
||||
//crcbuf[3] = h.crc_32[3]
|
||||
//crcbuf[2] = (h.crc_32[3] >> 8)
|
||||
//crcbuf[1] = (h.crc_32[3] >> 16)
|
||||
//crcbuf[0] = (h.crc_32[3] >> 24)
|
||||
//
|
||||
////fmt.Printf("CRC BUF: %x %v\n", crcbuf, crcbuf)
|
||||
//
|
||||
////fmt.Printf("% X\n", file_data)
|
||||
//if u16x(h.general_purpose_bit_flag) & 1 > 0 {
|
||||
// fmt.Println("Encrypted")
|
||||
// zc := zip2.NewZipCrypto(z.password)
|
||||
//
|
||||
// //result := file_data[0]
|
||||
// //for i := 0; i < 12; i++ {
|
||||
// // if i == 11 {
|
||||
// // //fmt.Printf("HASH MAGIC: %X %v\n", result ^ zc.MagicByte(), result ^ zc.MagicByte())
|
||||
// // }
|
||||
// // zc.UpdateKeys(result ^ zc.MagicByte())
|
||||
// // if i < 12 {
|
||||
// // result = file_data[i + 1]
|
||||
// // }
|
||||
// //}
|
||||
// file_header := zc.DecryptMessage(file_data[0:12])
|
||||
// //fmt.Printf("Magic Byte: %X\n", zc.MagicByte())
|
||||
// file_data = zc.DecryptMessage(file_data[12:])
|
||||
// fmt.Printf("%0 X : %0 X\n", file_header, file_data)
|
||||
// //fmt.Printf("%v %v\n", string(file_data[0:12]), string(file_data[12:]))
|
||||
// //file_data = file_data[12:]
|
||||
//}
|
||||
//if u16x(h.compression_method) == 8 {
|
||||
// //fmt.Printf("Compressed: %v\n", len(file_data))
|
||||
// rc := flate.NewReader(bytes.NewBuffer(file_data))
|
||||
// defer rc.Close()
|
||||
// res, err := ioutil.ReadAll(rc)
|
||||
// file_data = res
|
||||
// if err != nil {
|
||||
// fmt.Println(err.Error())
|
||||
// }
|
||||
//}
|
||||
//crc := crc32.NewIEEE()
|
||||
//crc.Write(file_data)
|
||||
//fmt.Printf("GO CRC: %X\n", crc.Sum32())
|
||||
//fmt.Printf("\n%v\n", string(file_data))
|
||||
//}
|
||||
}
|
||||
|
||||
func (z *ZipReader) DirectoryStructure() {
|
||||
|
||||
}
|
||||
|
||||
func u16(b []byte) uint16 {
|
||||
return binary.LittleEndian.Uint16(b)
|
||||
}
|
||||
|
||||
func u32(b []byte) uint32 {
|
||||
return binary.LittleEndian.Uint32(b)
|
||||
}
|
||||
|
||||
func u16x(b []byte) uint64 {
|
||||
return uint64(u16(b))
|
||||
}
|
||||
|
||||
func u32x(b []byte) uint64 {
|
||||
return uint64(u32(b))
|
||||
}
|
||||
|
||||
func u64x(b []byte) uint64 {
|
||||
return uint64(u32(b))
|
||||
}
|
||||
|
||||
|
||||
type Bytes struct {
|
||||
b []byte
|
||||
i uint64
|
||||
}
|
||||
|
||||
// Get slice of byte
|
||||
func (b *Bytes) Get(offset, size uint64) []byte {
|
||||
return b.b[offset : offset + size]
|
||||
}
|
||||
|
||||
func (b *Bytes) BGet(offset, size uint64) *Bytes {
|
||||
return &Bytes{b.Get(offset, size), 0}
|
||||
}
|
||||
|
||||
// Incremental Get
|
||||
func (b *Bytes) IGet(size uint64) []byte {
|
||||
i := b.i
|
||||
b.i = i + size
|
||||
return b.b[i : b.i]
|
||||
}
|
||||
|
||||
// Incremental Get
|
||||
func (b *Bytes) IBGet(size uint64) *Bytes {
|
||||
return &Bytes{b.IGet(size), 0}
|
||||
}
|
||||
|
||||
func (b *Bytes) I64() uint64 {
|
||||
switch len(b.b) {
|
||||
case 1:
|
||||
return uint64(b.b[0])
|
||||
case 2:
|
||||
return u16x(b.b)
|
||||
case 4:
|
||||
return u32x(b.b)
|
||||
case 8:
|
||||
return u64x(b.b)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
// Set offset
|
||||
func (b *Bytes) Offset(i uint64) {
|
||||
b.i = i
|
||||
}
|
||||
|
||||
func (b *Bytes) Pos() uint64 {
|
||||
return b.i
|
||||
}
|
61
writer.go
61
writer.go
|
@ -11,10 +11,10 @@ import (
|
|||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// TODO(adg): support zip file comments
|
||||
// TODO(adg): support specifying deflate level
|
||||
|
||||
// Writer implements a zip file writer.
|
||||
type Writer struct {
|
||||
|
@ -22,6 +22,7 @@ type Writer struct {
|
|||
dir []*header
|
||||
last *fileWriter
|
||||
closed bool
|
||||
compressors map[uint16]Compressor
|
||||
}
|
||||
|
||||
type header struct {
|
||||
|
@ -52,7 +53,7 @@ func (w *Writer) Flush() error {
|
|||
}
|
||||
|
||||
// Close finishes writing the zip file by writing the central directory.
|
||||
// It does not (and can not) close the underlying writer.
|
||||
// It does not (and cannot) close the underlying writer.
|
||||
func (w *Writer) Close() error {
|
||||
if w.last != nil && !w.last.closed {
|
||||
if err := w.last.close(); err != nil {
|
||||
|
@ -78,7 +79,8 @@ func (w *Writer) Close() error {
|
|||
b.uint16(h.ModifiedTime)
|
||||
b.uint16(h.ModifiedDate)
|
||||
b.uint32(h.CRC32)
|
||||
if h.isZip64() || h.offset > uint32max {
|
||||
|
||||
if h.isZip64() || h.offset >= uint32max {
|
||||
// the file needs a zip64 header. store maxint in both
|
||||
// 32 bit size fields (and offset later) to signal that the
|
||||
// zip64 extra header should be used.
|
||||
|
@ -98,6 +100,7 @@ func (w *Writer) Close() error {
|
|||
b.uint32(h.CompressedSize)
|
||||
b.uint32(h.UncompressedSize)
|
||||
}
|
||||
|
||||
b.uint16(uint16(len(h.Name)))
|
||||
b.uint16(uint16(len(h.Extra)))
|
||||
b.uint16(uint16(len(h.Comment)))
|
||||
|
@ -211,8 +214,7 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
|||
}
|
||||
|
||||
fh.Flags |= 0x8 // we will write a data descriptor
|
||||
// TODO(alex): Look at spec and see if these need to be changed
|
||||
// when using encryption.
|
||||
|
||||
fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
|
||||
fh.ReaderVersion = zipVersion20
|
||||
|
||||
|
@ -221,30 +223,21 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
|||
compCount: &countWriter{w: w.cw},
|
||||
crc32: crc32.NewIEEE(),
|
||||
}
|
||||
// Get the compressor before possibly changing Method to 99 due to password
|
||||
comp := compressor(fh.Method)
|
||||
comp := w.compressor(fh.Method)
|
||||
if comp == nil {
|
||||
return nil, ErrAlgorithm
|
||||
}
|
||||
// check for password
|
||||
var sw io.Writer = fw.compCount
|
||||
if fh.password != nil {
|
||||
if fh.encryption == StandardEncryption {
|
||||
if !fh.IsEncrypted() {
|
||||
fh.setEncryptionBit()
|
||||
}
|
||||
ew, err := ZipCryptoEncryptor(sw, fh.password, fw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sw = ew
|
||||
} else {
|
||||
// we have a password and need to encrypt.
|
||||
fh.writeWinZipExtra()
|
||||
fh.Method = 99 // ok to change, we've gotten the comp and wrote extra
|
||||
ew, err := newEncryptionWriter(sw, fh.password, fw, fh.aesStrength)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sw = ew
|
||||
}
|
||||
}
|
||||
var err error
|
||||
fw.comp, err = comp(sw)
|
||||
|
@ -280,6 +273,7 @@ func writeHeader(w io.Writer, h *FileHeader) error {
|
|||
b.uint32(0) // since we are writing a data descriptor crc32,
|
||||
b.uint32(0) // compressed size,
|
||||
b.uint32(0) // and uncompressed size should be zero
|
||||
fmt.Printf("File HEader Wring %0 X, %v, %v\n", h.CRC32, h.CompressedSize, h.UncompressedSize)
|
||||
b.uint16(uint16(len(h.Name)))
|
||||
b.uint16(uint16(len(h.Extra)))
|
||||
if _, err := w.Write(buf[:]); err != nil {
|
||||
|
@ -292,6 +286,24 @@ func writeHeader(w io.Writer, h *FileHeader) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// RegisterCompressor registers or overrides a custom compressor for a specific
|
||||
// method ID. If a compressor for a given method is not found, Writer will
|
||||
// default to looking up the compressor at the package level.
|
||||
func (w *Writer) RegisterCompressor(method uint16, comp Compressor) {
|
||||
if w.compressors == nil {
|
||||
w.compressors = make(map[uint16]Compressor)
|
||||
}
|
||||
w.compressors[method] = comp
|
||||
}
|
||||
|
||||
func (w *Writer) compressor(method uint16) Compressor {
|
||||
comp := w.compressors[method]
|
||||
if comp == nil {
|
||||
comp = compressor(method)
|
||||
}
|
||||
return comp
|
||||
}
|
||||
|
||||
type fileWriter struct {
|
||||
*header
|
||||
zipw io.Writer
|
||||
|
@ -320,21 +332,10 @@ func (w *fileWriter) close() error {
|
|||
if err := w.comp.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
// if encrypted grab the hmac and write it out
|
||||
if w.header.IsEncrypted() && w.header.encryption != StandardEncryption {
|
||||
authCode := w.hmac.Sum(nil)
|
||||
authCode = authCode[:10]
|
||||
_, err := w.compCount.Write(authCode)
|
||||
if err != nil {
|
||||
return errors.New("zip: error writing authcode")
|
||||
}
|
||||
}
|
||||
|
||||
// update FileHeader
|
||||
fh := w.header.FileHeader
|
||||
// ae-2 we don't write out CRC
|
||||
if !fh.IsEncrypted() || fh.encryption == StandardEncryption {
|
||||
fh.CRC32 = w.crc32.Sum32()
|
||||
}
|
||||
fh.CompressedSize64 = uint64(w.compCount.count)
|
||||
fh.UncompressedSize64 = uint64(w.rawCount.count)
|
||||
|
||||
|
|
70
zipcrypto.go
70
zipcrypto.go
|
@ -3,6 +3,7 @@ package zip
|
|||
import (
|
||||
"io"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
)
|
||||
|
||||
|
@ -14,65 +15,74 @@ type ZipCrypto struct {
|
|||
func NewZipCrypto(passphrase []byte) *ZipCrypto {
|
||||
z := &ZipCrypto{}
|
||||
z.password = passphrase
|
||||
z.init()
|
||||
z.Init()
|
||||
return z
|
||||
}
|
||||
|
||||
func (z *ZipCrypto) init() {
|
||||
func (z *ZipCrypto) Init() {
|
||||
z.Keys[0] = 0x12345678
|
||||
z.Keys[1] = 0x23456789
|
||||
z.Keys[2] = 0x34567890
|
||||
|
||||
for i := 0; i < len(z.password); i++ {
|
||||
z.updateKeys(z.password[i])
|
||||
z.UpdateKeys(z.password[i])
|
||||
}
|
||||
}
|
||||
|
||||
func (z *ZipCrypto) updateKeys(byteValue byte) {
|
||||
z.Keys[0] = crc32update(z.Keys[0], byteValue);
|
||||
func (z *ZipCrypto) UpdateKeys(byteValue byte) {
|
||||
z.Keys[0] = Crc32update(z.Keys[0], byteValue);
|
||||
z.Keys[1] += z.Keys[0] & 0xff;
|
||||
z.Keys[1] = z.Keys[1] * 134775813 + 1;
|
||||
z.Keys[2] = crc32update(z.Keys[2], (byte) (z.Keys[1] >> 24));
|
||||
z.Keys[2] = Crc32update(z.Keys[2], (byte) (z.Keys[1] >> 24));
|
||||
}
|
||||
|
||||
func (z *ZipCrypto) magicByte() byte {
|
||||
func (z *ZipCrypto) MagicByte() byte {
|
||||
var t uint32 = z.Keys[2] | 2
|
||||
return byte((t * (t ^ 1)) >> 8)
|
||||
}
|
||||
|
||||
func (z *ZipCrypto) Encrypt(data []byte) []byte {
|
||||
length := len(data)
|
||||
chiper := make([]byte, length)
|
||||
func (z *ZipCrypto) EncryptMessage(plaintext []byte) []byte {
|
||||
length := len(plaintext)
|
||||
CipherText := make([]byte, length)
|
||||
for i := 0; i < length; i++ {
|
||||
v := data[i]
|
||||
chiper[i] = v ^ z.magicByte()
|
||||
z.updateKeys(v)
|
||||
C := plaintext[i]
|
||||
CipherText[i] = plaintext[i] ^ z.MagicByte()
|
||||
z.UpdateKeys(C)
|
||||
}
|
||||
return chiper
|
||||
return CipherText
|
||||
}
|
||||
|
||||
func (z *ZipCrypto) Decrypt(chiper []byte) []byte {
|
||||
length := len(chiper)
|
||||
plain := make([]byte, length)
|
||||
for i, c := range chiper {
|
||||
v := c ^ z.magicByte();
|
||||
z.updateKeys(v)
|
||||
plain[i] = v
|
||||
func (z *ZipCrypto) DecryptMessage(chipertext []byte) []byte {
|
||||
length := len(chipertext)
|
||||
PlainText := make([]byte, length)
|
||||
for i, c := range chipertext {
|
||||
v := c ^ z.MagicByte();
|
||||
z.UpdateKeys(v)
|
||||
PlainText[i] = v
|
||||
}
|
||||
return plain
|
||||
return PlainText
|
||||
}
|
||||
|
||||
func crc32update(pCrc32 uint32, bval byte) uint32 {
|
||||
func Crc32update(pCrc32 uint32, bval byte) uint32 {
|
||||
return crc32.IEEETable[(pCrc32 ^ uint32(bval)) & 0xff] ^ (pCrc32 >> 8)
|
||||
}
|
||||
|
||||
func ZipCryptoDecryptor(r *io.SectionReader, password []byte) (*io.SectionReader, error) {
|
||||
//return r, nil
|
||||
z := NewZipCrypto(password)
|
||||
b := make([]byte, r.Size())
|
||||
|
||||
r.Read(b)
|
||||
|
||||
m := z.Decrypt(b)
|
||||
m := z.DecryptMessage(b)
|
||||
fmt.Printf("Header: %X %X %X\n%v\n", m[0:4], m[4:8], m[8:12], m[0:12])
|
||||
fmt.Printf("Header: %X\n", m[11])
|
||||
fmt.Printf("Content: %X\n", m[12:])
|
||||
fmt.Printf("Content: %v\n", string(m[12:]))
|
||||
//if m[11] > 0xFF {
|
||||
// return nil, errors.New("incorrect password")
|
||||
//}
|
||||
//fmt.Printf("Size: %v\n", len(m))
|
||||
return io.NewSectionReader(bytes.NewReader(m), 12, int64(len(m))), nil
|
||||
}
|
||||
|
||||
|
@ -84,25 +94,27 @@ type zipCryptoWriter struct {
|
|||
}
|
||||
|
||||
func (z *zipCryptoWriter) Write(p []byte) (n int, err error) {
|
||||
err = nil
|
||||
if z.first {
|
||||
z.first = false
|
||||
header := []byte{0xF8, 0x53, 0xCF, 0x05, 0x2D, 0xDD, 0xAD, 0xC8, 0x66, 0x3F, 0x8C, 0xAC}
|
||||
header = z.z.Encrypt(header)
|
||||
header = z.z.EncryptMessage(header)
|
||||
|
||||
crc := z.fw.ModifiedTime
|
||||
header[10] = byte(crc)
|
||||
header[11] = byte(crc >> 8)
|
||||
|
||||
z.z.init()
|
||||
z.w.Write(z.z.Encrypt(header))
|
||||
z.z.Init()
|
||||
z.w.Write(z.z.EncryptMessage(header))
|
||||
n += 12
|
||||
//z.z.Init()
|
||||
}
|
||||
z.w.Write(z.z.Encrypt(p))
|
||||
z.w.Write(z.z.EncryptMessage(p))
|
||||
z.fw.FileHeader.CompressedSize += uint32(n)
|
||||
return
|
||||
}
|
||||
|
||||
func ZipCryptoEncryptor(i io.Writer, pass passwordFn, fw *fileWriter) (io.Writer, error) {
|
||||
fmt.Printf("Initializationg...\n")
|
||||
z := NewZipCrypto(pass())
|
||||
zc := &zipCryptoWriter{i, z, true, fw}
|
||||
return zc, nil
|
||||
|
|
Loading…
Reference in New Issue