Documentation
¶
Overview ¶
Package zipcrypt adds password protection to archive/zip.
It does not fork archive/zip. Writer wraps a *zip.Writer and registers its own compressors on it; for entries created with Writer.CreateWith they compress at the requested level and then encrypt. Everything else, such as headers, CRC-32, data descriptors, ZIP64 and the central directory, is left to archive/zip. Open decrypts entries read with zip.Reader.
Two encryption methods are supported:
- ZipCrypto, the traditional PKWARE encryption. It is cryptographically weak, but it is the only method that Windows Explorer and macOS Archive Utility open without extra software.
- WinZip AES (AE-1) with 128, 192 or 256-bit keys, which 7-Zip, WinZip, WinRAR and similar tools open.
Example ¶
package main
import (
"archive/zip"
"bytes"
"fmt"
"io"
"log"
"github.com/creatorKoo/zipcrypt"
)
func main() {
// Write an archive with one AES-256 encrypted file.
var buf bytes.Buffer
w := zipcrypt.NewWriter(&buf)
fw, err := w.CreateWith(&zip.FileHeader{Name: "secret.txt", Method: zip.Deflate},
zipcrypt.Options{Method: zipcrypt.AES256, Password: "golang"})
if err != nil {
log.Fatal(err)
}
fmt.Fprint(fw, "Hello, Gophers!")
if err := w.Close(); err != nil {
log.Fatal(err)
}
// Read it back with archive/zip and zipcrypt.Open.
r, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
if err != nil {
log.Fatal(err)
}
rc, err := zipcrypt.Open(r.File[0], "golang")
if err != nil {
log.Fatal(err)
}
defer rc.Close()
b, err := io.ReadAll(rc)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
Output: Hello, Gophers!
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrAuthentication = errors.New("zipcrypt: authentication failed")
ErrAuthentication is returned at the end of an AES entry whose data does not match its authentication code.
var ErrPassword = errors.New("zipcrypt: wrong password")
ErrPassword is returned when the password does not match an entry.
Functions ¶
func Open ¶
Open returns a ReadCloser for the contents of f, decrypting it with password if f is encrypted. Unencrypted entries are opened with f.Open and the password is ignored.
A wrong password is usually reported as ErrPassword. ZipCrypto checks a single byte, so about 1 wrong password in 256 gets past that check; the data then fails to decompress or to match its CRC-32 instead. AES entries report altered data as ErrAuthentication once the end is read, after the decrypted bytes have been returned, as any streaming reader must.
Types ¶
type Method ¶
type Method int
Method selects how an entry is encrypted.
const ( // None writes the entry unencrypted. None Method = iota // ZipCrypto is the traditional PKWARE encryption. It is weak, but it is // the only method Windows Explorer and macOS Archive Utility can open. ZipCrypto // AES128, AES192 and AES256 are WinZip AES encryption (AE-1). They need // 7-Zip, WinZip, WinRAR or a similar tool to open. AES128 AES192 AES256 )
type Options ¶
type Options struct {
// Method selects the encryption. The zero value, None, writes the entry
// unencrypted.
Method Method
// Password encrypts the entry. It is required unless Method is None, and
// must be empty if Method is None.
Password string
// Level is the flate level for Deflate entries, as for flate.NewWriter.
// Zero means 5, the level archive/zip uses.
Level int
// NoCompression writes Deflate entries as uncompressed blocks, for data
// that is already compressed, such as JPEG or MP4. It is as fast as Store
// and adds 5 bytes per 64 KiB, but unlike Store the entry ends itself:
// readers that scan an archive from the front, such as macOS ditto, cannot
// mistake bytes inside it for the end of the entry.
NoCompression bool
}
Options describes how one entry is written.
Example (NoCompression) ¶
Files that are already compressed, such as photos and videos, gain almost nothing from Deflate. NoCompression writes them at disk speed.
package main
import (
"archive/zip"
"bytes"
"log"
"github.com/creatorKoo/zipcrypt"
)
func main() {
var buf bytes.Buffer
w := zipcrypt.NewWriter(&buf)
fw, err := w.CreateWith(&zip.FileHeader{Name: "photo.jpg", Method: zip.Deflate},
zipcrypt.Options{Method: zipcrypt.ZipCrypto, Password: "golang", NoCompression: true})
if err != nil {
log.Fatal(err)
}
fw.Write([]byte{0xff, 0xd8, 0xff, 0xe0}) // the JPEG data
if err := w.Close(); err != nil {
log.Fatal(err)
}
}
Output:
type Writer ¶
Writer is a zip.Writer that can also write encrypted entries. Entries added through the embedded zip.Writer are written unencrypted, as archive/zip would write them.
func NewWriter ¶
NewWriter returns a Writer writing a zip file to w.
It registers compressors for zip.Store, zip.Deflate and method 99 (AES) on the embedded zip.Writer. Registering another compressor for those methods on it disables encryption for them.
func (*Writer) CreateWith ¶
CreateWith adds a file to the archive like zip.Writer.CreateHeader and compresses and encrypts it as opt says. fh.Method must be zip.Store or zip.Deflate. Directories are never encrypted. As with CreateHeader, the file's contents must be written before the next call to CreateWith, CreateHeader or Close, and fh must not be modified or reused afterwards.