Playing around

This commit is contained in:
yeka 2016-10-16 19:50:27 +07:00
parent fcc3c52422
commit 9a620c6cd3
6 changed files with 756 additions and 30 deletions

View File

@ -443,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 // PasswordFn is a function that returns the password
// as a byte slice // as a byte slice
type passwordFn func() []byte type passwordFn func() []byte
@ -457,6 +463,6 @@ func (w *Writer) Encrypt(name string, password string) (io.Writer, error) {
Name: name, Name: name,
Method: Deflate, Method: Deflate,
} }
fh.SetPassword(password) fh.SetDecryptionPassword(password)
return w.CreateHeader(fh) return w.CreateHeader(fh)
} }

View File

@ -143,14 +143,21 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
size := int64(f.CompressedSize64) size := int64(f.CompressedSize64)
var r io.Reader var r io.Reader
rr := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size) rr := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
// check for encryption // check for encryption
if f.IsEncrypted() { if f.IsEncrypted() {
if r, err = newDecryptionReader(rr, f); err != nil { if f.ae == 0 {
fmt.Printf("CRC32: %X ---- %v\n", f.CRC32, f.CRC32)
if r, err = ZipCryptoDecryptor(rr, f.password()); err != nil {
return
}
} else if r, err = newDecryptionReader(rr, f); err != nil {
return return
} }
} else { } else {
r = rr r = rr
} }
dcomp := decompressor(f.Method) dcomp := decompressor(f.Method)
if dcomp == nil { if dcomp == nil {
err = ErrAlgorithm err = ErrAlgorithm
@ -254,14 +261,21 @@ func readDirectoryHeader(f *File, r io.Reader) error {
f.CreatorVersion = b.uint16() f.CreatorVersion = b.uint16()
f.ReaderVersion = b.uint16() f.ReaderVersion = b.uint16()
f.Flags = b.uint16() f.Flags = b.uint16()
fmt.Printf("FLAG: %X\n", f.Flags)
f.Method = b.uint16() f.Method = b.uint16()
fmt.Printf("METHOD: %X\n", f.Method)
f.ModifiedTime = b.uint16() f.ModifiedTime = b.uint16()
f.ModifiedDate = b.uint16() f.ModifiedDate = b.uint16()
f.CRC32 = b.uint32() f.CRC32 = b.uint32()
fmt.Printf("Directory CRC: %X\n", f.CRC32)
f.CompressedSize = b.uint32() f.CompressedSize = b.uint32()
f.UncompressedSize = b.uint32() f.UncompressedSize = b.uint32()
f.CompressedSize64 = uint64(f.CompressedSize) f.CompressedSize64 = uint64(f.CompressedSize)
f.UncompressedSize64 = uint64(f.UncompressedSize) 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()) filenameLen := int(b.uint16())
extraLen := int(b.uint16()) extraLen := int(b.uint16())
commentLen := int(b.uint16()) commentLen := int(b.uint16())

32
temp/int.go Normal file
View File

@ -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)
}

544
temp/play.go Normal file
View File

@ -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
}

View File

@ -11,10 +11,10 @@ import (
"hash" "hash"
"hash/crc32" "hash/crc32"
"io" "io"
"fmt"
) )
// TODO(adg): support zip file comments // TODO(adg): support zip file comments
// TODO(adg): support specifying deflate level
// Writer implements a zip file writer. // Writer implements a zip file writer.
type Writer struct { type Writer struct {
@ -22,6 +22,7 @@ type Writer struct {
dir []*header dir []*header
last *fileWriter last *fileWriter
closed bool closed bool
compressors map[uint16]Compressor
} }
type header struct { type header struct {
@ -78,7 +79,8 @@ func (w *Writer) Close() error {
b.uint16(h.ModifiedTime) b.uint16(h.ModifiedTime)
b.uint16(h.ModifiedDate) b.uint16(h.ModifiedDate)
b.uint32(h.CRC32) 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 // the file needs a zip64 header. store maxint in both
// 32 bit size fields (and offset later) to signal that the // 32 bit size fields (and offset later) to signal that the
// zip64 extra header should be used. // zip64 extra header should be used.
@ -98,6 +100,7 @@ func (w *Writer) Close() error {
b.uint32(h.CompressedSize) b.uint32(h.CompressedSize)
b.uint32(h.UncompressedSize) b.uint32(h.UncompressedSize)
} }
b.uint16(uint16(len(h.Name))) b.uint16(uint16(len(h.Name)))
b.uint16(uint16(len(h.Extra))) b.uint16(uint16(len(h.Extra)))
b.uint16(uint16(len(h.Comment))) 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 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.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
fh.ReaderVersion = zipVersion20 fh.ReaderVersion = zipVersion20
@ -221,18 +223,17 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
compCount: &countWriter{w: w.cw}, compCount: &countWriter{w: w.cw},
crc32: crc32.NewIEEE(), crc32: crc32.NewIEEE(),
} }
// Get the compressor before possibly changing Method to 99 due to password comp := w.compressor(fh.Method)
comp := compressor(fh.Method)
if comp == nil { if comp == nil {
return nil, ErrAlgorithm return nil, ErrAlgorithm
} }
// 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 {
// we have a password and need to encrypt. if !fh.IsEncrypted() {
fh.writeWinZipExtra() fh.setEncryptionBit()
fh.Method = 99 // ok to change, we've gotten the comp and wrote extra }
ew, err := newEncryptionWriter(sw, fh.password, fw) ew, err := ZipCryptoEncryptor(sw, fh.password, fw)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -272,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) // since we are writing a data descriptor crc32,
b.uint32(0) // compressed size, b.uint32(0) // compressed size,
b.uint32(0) // and uncompressed size should be zero 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.Name)))
b.uint16(uint16(len(h.Extra))) b.uint16(uint16(len(h.Extra)))
if _, err := w.Write(buf[:]); err != nil { if _, err := w.Write(buf[:]); err != nil {
@ -284,6 +286,24 @@ func writeHeader(w io.Writer, h *FileHeader) error {
return err 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 { type fileWriter struct {
*header *header
zipw io.Writer zipw io.Writer
@ -312,21 +332,10 @@ func (w *fileWriter) close() error {
if err := w.comp.Close(); err != nil { if err := w.comp.Close(); err != nil {
return err return err
} }
// if encrypted grab the hmac and write it out
if w.header.IsEncrypted() {
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 // update FileHeader
fh := w.header.FileHeader fh := w.header.FileHeader
// ae-2 we don't write out CRC
if !fh.IsEncrypted() {
fh.CRC32 = w.crc32.Sum32() fh.CRC32 = w.crc32.Sum32()
}
fh.CompressedSize64 = uint64(w.compCount.count) fh.CompressedSize64 = uint64(w.compCount.count)
fh.UncompressedSize64 = uint64(w.rawCount.count) fh.UncompressedSize64 = uint64(w.rawCount.count)

121
zipcrypto.go Normal file
View File

@ -0,0 +1,121 @@
package zip
import (
"io"
"bytes"
"fmt"
"hash/crc32"
)
type ZipCrypto struct {
password []byte
Keys [3]uint32
}
func NewZipCrypto(passphrase []byte) *ZipCrypto {
z := &ZipCrypto{}
z.password = passphrase
z.Init()
return z
}
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])
}
}
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));
}
func (z *ZipCrypto) MagicByte() byte {
var t uint32 = z.Keys[2] | 2
return byte((t * (t ^ 1)) >> 8)
}
func (z *ZipCrypto) EncryptMessage(plaintext []byte) []byte {
length := len(plaintext)
CipherText := make([]byte, length)
for i := 0; i < length; i++ {
C := plaintext[i]
CipherText[i] = plaintext[i] ^ z.MagicByte()
z.UpdateKeys(C)
}
return CipherText
}
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 PlainText
}
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.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
}
type zipCryptoWriter struct {
w io.Writer
z *ZipCrypto
first bool
fw *fileWriter
}
func (z *zipCryptoWriter) Write(p []byte) (n int, err error) {
if z.first {
z.first = false
header := []byte{0xF8, 0x53, 0xCF, 0x05, 0x2D, 0xDD, 0xAD, 0xC8, 0x66, 0x3F, 0x8C, 0xAC}
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.EncryptMessage(header))
n += 12
//z.z.Init()
}
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
}