Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
.idea

# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
Expand All @@ -24,3 +25,5 @@ _testmain.go
*.exe
*.test
*.prof

attach
20 changes: 16 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
This fork add support for Standard Zip Encryption.

The work is based on https://github.com/alexmullins/zip
The work is based on https://github.com/yeka/zip

Available encryption:

Expand All @@ -18,6 +18,17 @@ Unless you have to work with it, please use AES encryption instead.

## Example Encrypt Zip

method `Encrypt("test.txt", "golang", zip.AES256Encryption, 0x800, time.Now())` it takes parameters:
* Name File
* Archive Password
* Type Encrypt
* Flag encoding
* Date Modify File

Flag 0x800 solves the problem with the file name encoding, for example, if the name was written in russian letters.

Code example:

```
package main

Expand All @@ -26,8 +37,9 @@ import (
"io"
"log"
"os"
"time"

"github.com/yeka/zip"
"github.com/olegpolukhin/zip"
)

func main() {
Expand All @@ -38,7 +50,7 @@ func main() {
}
zipw := zip.NewWriter(fzip)
defer zipw.Close()
w, err := zipw.Encrypt(`test.txt`, `golang`, zip.AES256Encryption)
w, err := zipw.Encrypt(`test.txt`, `golang`, zip.AES256Encryption, 0x800, time.Now())
if err != nil {
log.Fatal(err)
}
Expand All @@ -60,7 +72,7 @@ import (
"io/ioutil"
"log"

"github.com/yeka/zip"
"https://github.com/olegpolukhin/zip"
)

func main() {
Expand Down
138 changes: 138 additions & 0 deletions archiver_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package zip

import (
"bufio"
"bytes"
"fmt"
"io"
"log"
"os"
"strconv"
"syscall"
"testing"
"time"
)

func timespecToTime(ts syscall.Timespec) time.Time {

return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}

func saveArchiveProtectedToStorage(Filename, path, id, password, format string) error {
// get last modified time
file, err := os.Stat(Filename)
if err != nil {
fmt.Println(err)
}

fileFd, err := os.Open(Filename)

if err != nil {
return fmt.Errorf("read file error %s", err.Error())
}
defer fileFd.Close()
// Создаем папку для файла

errorChdir := os.Chdir(path)
if errorChdir != nil {
return fmt.Errorf("Chdir error %s", errorChdir.Error())
}

errFolder := os.Mkdir(id, os.ModePerm)
if errFolder != nil {
return fmt.Errorf("Create direcory error %s", errFolder.Error())
}

// Заходим в созданный каталог
errorChdir = os.Chdir(id)
if errorChdir != nil {
return fmt.Errorf("Chdir error %s", errorChdir.Error())
}

defer fileFd.Close()

// читаем в буфер
buffer := bytes.NewBuffer(make([]byte, 0))
bufferReader := make([]byte, 1024)
for {
n, err := fileFd.Read(bufferReader)
if err != nil && err != io.EOF {
return fmt.Errorf("read file error %s", err.Error())
}
if n == 0 {
break
}

buffer.Write(bufferReader[:n])
}

// Пишем в защищенный архив
raw := new(bytes.Buffer)
zipWriter := NewWriter(raw)
w, err := zipWriter.Encrypt(Filename, password, AES256Encryption, 0x800, file.ModTime())
if err != nil {
return fmt.Errorf("encrypt error %s", err.Error())
}

_, err = io.Copy(w, bytes.NewReader(buffer.Bytes()))
if err != nil {
return fmt.Errorf("cope new reader error %s", err.Error())
}

if err := zipWriter.Close(); err != nil {
return fmt.Errorf("zip close error %s", err.Error())
}

// Создаём защищенный архив
fo, err := os.Create(Filename + format)
if err != nil {
return fmt.Errorf("create archive '%s' error %s", Filename+format, err.Error())
}

// close fo on exit and check for its returned error
defer func() {
if err := fo.Close(); err != nil {
panic(err)
}
}()

// make a write buffer
writer := bufio.NewWriter(fo)

// make a buffer to keep chunks that are read
buf := make([]byte, 1024)
r := bytes.NewReader(raw.Bytes())
for {
// read a chunk
n, err := r.Read(buf)
if err != nil && err != io.EOF {
return fmt.Errorf("read buffer error %s", err.Error())
}
if n == 0 {
break
}

// write a chunk
if _, err := writer.Write(buf[:n]); err != nil {
return fmt.Errorf("writer error %s", err.Error())
}
}

if err = writer.Flush(); err != nil {
return fmt.Errorf("writer flush error %s", err.Error())
}

return nil
}

func TestArchive(t *testing.T) {
id := strconv.FormatInt(time.Now().Unix(), 9)
name := "Teams - (имя файла на русском языке!) (1).txt"
log.Println(">>> ", id)

err := saveArchiveProtectedToStorage(name, "attach", id, "password", ".zip")
if err != nil {
t.Error(err)
}

}
11 changes: 7 additions & 4 deletions crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
"crypto/sha1"
"crypto/subtle"
"errors"
"golang.org/x/crypto/pbkdf2"
"hash"
"io"

"golang.org/x/crypto/pbkdf2"
"time"
)

type EncryptionMethod int
Expand Down Expand Up @@ -388,7 +388,7 @@ func encryptStream(key []byte, w io.Writer) (io.Writer, error) {
// 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)
salt := make([]byte, keysize/2)
_, err := rand.Read(salt[:])
if err != nil {
return nil, errors.New("zip: unable to generate random salt")
Expand Down Expand Up @@ -472,12 +472,15 @@ 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, enc EncryptionMethod, flag uint16, timeModify time.Time) (io.Writer, error) {
fh := &FileHeader{
Name: name,
Method: Deflate,
Flags: flag,
}
fh.SetPassword(password)
fh.setEncryptionMethod(enc)
//fh.SetFlags(flag)
fh.SetModTime(timeModify)
return w.CreateHeader(fh)
}
7 changes: 4 additions & 3 deletions crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"path/filepath"
"testing"
"time"
)

// Test simple password reading.
Expand Down Expand Up @@ -56,7 +57,7 @@ func TestPasswordHelloWorldAes(t *testing.T) {
var b bytes.Buffer
for _, f := range r.File {
if !f.IsEncrypted() {
t.Errorf("Expected %s to be encrypted.", f.FileInfo().Name)
t.Errorf("Expected %s to be encrypted.", f.FileInfo().Name())
}
f.SetPassword("golang")
rc, err := f.Open()
Expand Down Expand Up @@ -178,7 +179,7 @@ func TestPasswordWriteSimple(t *testing.T) {
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", enc, 0x800, time.Now())
if err != nil {
t.Errorf("Expected to create a new FileHeader")
}
Expand Down Expand Up @@ -223,7 +224,7 @@ func TestZipCrypto(t *testing.T) {

raw := new(bytes.Buffer)
zipw := NewWriter(raw)
w, err := zipw.Encrypt("hello.txt", "golang", StandardEncryption)
w, err := zipw.Encrypt("hello.txt", "golang", StandardEncryption, 0x800, time.Now())
if err != nil {
t.Errorf("Expected to create a new FileHeader")
}
Expand Down
7 changes: 4 additions & 3 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import (
"io"
"log"
"os"
"testing"

"github.com/yeka/zip"
)

func ExampleWriter() {
func TestExampleWriter(t *testing.T) {
// Create a buffer to write our archive to.
buf := new(bytes.Buffer)

Expand Down Expand Up @@ -47,7 +48,7 @@ func ExampleWriter() {
}
}

func ExampleReader() {
func TestExampleReader(t *testing.T) {
// Open a zip archive for reading.
r, err := zip.OpenReader("testdata/readme.zip")
if err != nil {
Expand Down Expand Up @@ -75,7 +76,7 @@ func ExampleReader() {
// This is the source code repository for the Go programming language.
}

func ExampleWriter_Encrypt() {
func TestExampleWriter_Encrypt(t *testing.T) {
contents := []byte("Hello World")

// write a password zip
Expand Down