mirror of https://github.com/yeka/zip.git
247 lines
6.6 KiB
Go
247 lines
6.6 KiB
Go
package zip
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
// Test simple password reading.
|
|
func TestPasswordReadSimple(t *testing.T) {
|
|
file := "hello-aes.zip"
|
|
var buf bytes.Buffer
|
|
r, err := OpenReader(filepath.Join("testdata", file))
|
|
if err != nil {
|
|
t.Errorf("Expected %s to open: %v.", file, err)
|
|
}
|
|
defer r.Close()
|
|
if len(r.File) != 1 {
|
|
t.Errorf("Expected %s to contain one file.", file)
|
|
}
|
|
f := r.File[0]
|
|
if f.FileInfo().Name() != "hello.txt" {
|
|
t.Errorf("Expected %s to have a file named hello.txt", file)
|
|
}
|
|
if f.Method != 0 {
|
|
t.Errorf("Expected %s to have its Method set to 0.", file)
|
|
}
|
|
f.SetPassword("golang")
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
t.Errorf("Expected to open the readcloser: %v.", err)
|
|
}
|
|
_, err = io.Copy(&buf, rc)
|
|
if err != nil {
|
|
t.Errorf("Expected to copy bytes: %v.", err)
|
|
}
|
|
if !bytes.Contains(buf.Bytes(), []byte("Hello World\r\n")) {
|
|
t.Errorf("Expected contents were not found.")
|
|
}
|
|
}
|
|
|
|
// Test for multi-file password protected zip.
|
|
// Each file can be protected with a different password.
|
|
func TestPasswordHelloWorldAes(t *testing.T) {
|
|
file := "world-aes.zip"
|
|
expecting := "helloworld"
|
|
r, err := OpenReader(filepath.Join("testdata", file))
|
|
if err != nil {
|
|
t.Errorf("Expected %s to open: %v", file, err)
|
|
}
|
|
defer r.Close()
|
|
if len(r.File) != 2 {
|
|
t.Errorf("Expected %s to contain two files.", file)
|
|
}
|
|
var b bytes.Buffer
|
|
for _, f := range r.File {
|
|
if !f.IsEncrypted() {
|
|
t.Errorf("Expected %s to be encrypted.", f.FileInfo().Name)
|
|
}
|
|
f.SetPassword("golang")
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
t.Errorf("Expected to open readcloser: %v", err)
|
|
}
|
|
defer rc.Close()
|
|
if _, err := io.Copy(&b, rc); err != nil {
|
|
t.Errorf("Expected to copy bytes to buffer: %v", err)
|
|
}
|
|
}
|
|
if !bytes.Equal([]byte(expecting), b.Bytes()) {
|
|
t.Errorf("Expected ending content to be %s instead of %s", expecting, b.Bytes())
|
|
}
|
|
}
|
|
|
|
// Test for password protected file that is larger than a single
|
|
// AES block size to check CTR implementation.
|
|
func TestPasswordMacbethAct1(t *testing.T) {
|
|
file := "macbeth-act1.zip"
|
|
expecting := "Exeunt"
|
|
var b bytes.Buffer
|
|
r, err := OpenReader(filepath.Join("testdata", file))
|
|
if err != nil {
|
|
t.Errorf("Expected %s to open: %v", file, err)
|
|
}
|
|
defer r.Close()
|
|
for _, f := range r.File {
|
|
if !f.IsEncrypted() {
|
|
t.Errorf("Expected %s to be encrypted.", f.Name)
|
|
}
|
|
f.SetPassword("golang")
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
t.Errorf("Expected to open readcloser: %v", err)
|
|
}
|
|
defer rc.Close()
|
|
if _, err := io.Copy(&b, rc); err != nil {
|
|
t.Errorf("Expected to copy bytes to buffer: %v", err)
|
|
}
|
|
}
|
|
if !bytes.Contains(b.Bytes(), []byte(expecting)) {
|
|
t.Errorf("Expected to find %s in the buffer %v", expecting, b.Bytes())
|
|
}
|
|
}
|
|
|
|
// Change to AE-1 and change CRC value to fail check.
|
|
// Must be != 0 due to zip package already skipping if == 0.
|
|
func returnAE1BadCRC() (io.ReaderAt, int64) {
|
|
return messWith("hello-aes.zip", func(b []byte) {
|
|
// Change version to AE-1(1)
|
|
b[0x2B] = 1 // file
|
|
b[0xBA] = 1 // TOC
|
|
// Change CRC to bad value
|
|
b[0x11]++ // file
|
|
b[0x6B]++ // TOC
|
|
})
|
|
}
|
|
|
|
// Test for AE-1 Corrupt CRC
|
|
func TestPasswordAE1BadCRC(t *testing.T) {
|
|
buf := new(bytes.Buffer)
|
|
file, s := returnAE1BadCRC()
|
|
r, err := NewReader(file, s)
|
|
if err != nil {
|
|
t.Errorf("Expected hello-aes.zip to open: %v", err)
|
|
}
|
|
for _, f := range r.File {
|
|
if !f.IsEncrypted() {
|
|
t.Errorf("Expected zip to be encrypted")
|
|
}
|
|
f.SetPassword("golang")
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
t.Errorf("Expected the readcloser to open.")
|
|
}
|
|
defer rc.Close()
|
|
if _, err := io.Copy(buf, rc); err != ErrChecksum {
|
|
t.Errorf("Expected the checksum to fail")
|
|
}
|
|
}
|
|
}
|
|
|
|
// Corrupt the last byte of ciphertext to fail authentication
|
|
func returnTamperedData() (io.ReaderAt, int64) {
|
|
return messWith("hello-aes.zip", func(b []byte) {
|
|
b[0x50]++
|
|
})
|
|
}
|
|
|
|
// Test for tampered file data payload.
|
|
func TestPasswordTamperedData(t *testing.T) {
|
|
buf := new(bytes.Buffer)
|
|
file, s := returnTamperedData()
|
|
r, err := NewReader(file, s)
|
|
if err != nil {
|
|
t.Errorf("Expected hello-aes.zip to open: %v", err)
|
|
}
|
|
for _, f := range r.File {
|
|
if !f.IsEncrypted() {
|
|
t.Errorf("Expected zip to be encrypted")
|
|
}
|
|
f.SetPassword("golang")
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
t.Errorf("Expected the readcloser to open.")
|
|
}
|
|
defer rc.Close()
|
|
if _, err := io.Copy(buf, rc); err != ErrAuthentication {
|
|
t.Errorf("Expected the checksum to fail")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPasswordWriteSimple(t *testing.T) {
|
|
contents := []byte("Hello World")
|
|
conLen := len(contents)
|
|
|
|
for _, enc := range []EncryptionMethod{ZipStandardEncryption, AES128Encryption, AES192Encryption, AES256Encryption} {
|
|
raw := new(bytes.Buffer)
|
|
zipw := NewWriter(raw)
|
|
w, err := zipw.Encrypt("hello.txt", "golang", enc)
|
|
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()
|
|
|
|
// Read the zip
|
|
buf := new(bytes.Buffer)
|
|
zipr, err := NewReader(bytes.NewReader(raw.Bytes()), int64(raw.Len()))
|
|
if err != nil {
|
|
t.Errorf("Expected to open a new zip reader: %v", err)
|
|
}
|
|
nn := len(zipr.File)
|
|
if nn != 1 {
|
|
t.Errorf("Expected to have one file in the zip archive, but has %d files", nn)
|
|
}
|
|
z := zipr.File[0]
|
|
z.SetPassword("golang")
|
|
rr, err := z.Open()
|
|
if err != nil {
|
|
t.Errorf("Expected to open the readcloser: %v", err)
|
|
}
|
|
n, err = io.Copy(buf, rr)
|
|
if err != nil {
|
|
t.Errorf("Expected to write to temporary buffer: %v", err)
|
|
}
|
|
if n != int64(conLen) {
|
|
t.Errorf("Expected to copy %d bytes to temp buffer, but copied %d bytes instead", conLen, n)
|
|
}
|
|
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", ZipStandardEncryption)
|
|
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())
|
|
}
|
|
}
|