diff --git a/.gitignore b/.gitignore index 72747d6..eca614c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.idea # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o @@ -24,3 +25,5 @@ _testmain.go *.exe *.test *.prof + +attach diff --git a/README.md b/README.md index f4fdcde..1b65ad8 100644 --- a/README.md +++ b/README.md @@ -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: @@ -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 @@ -26,8 +37,9 @@ import ( "io" "log" "os" + "time" - "github.com/yeka/zip" + "github.com/olegpolukhin/zip" ) func main() { @@ -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) } @@ -60,7 +72,7 @@ import ( "io/ioutil" "log" - "github.com/yeka/zip" + "https://github.com/olegpolukhin/zip" ) func main() { diff --git a/archiver_test.go b/archiver_test.go new file mode 100644 index 0000000..d7d835a --- /dev/null +++ b/archiver_test.go @@ -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) + } + +} diff --git a/crypto.go b/crypto.go index df23856..d258565 100644 --- a/crypto.go +++ b/crypto.go @@ -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 @@ -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") @@ -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) } diff --git a/crypto_test.go b/crypto_test.go index cc5e2de..5777db9 100644 --- a/crypto_test.go +++ b/crypto_test.go @@ -5,6 +5,7 @@ import ( "io" "path/filepath" "testing" + "time" ) // Test simple password reading. @@ -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() @@ -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") } @@ -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") } diff --git a/example_test.go b/example_test.go index dce27ee..0145a4b 100644 --- a/example_test.go +++ b/example_test.go @@ -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) @@ -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 { @@ -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