mirror of https://github.com/yeka/zip.git
Tidy up error handling and comments
This commit is contained in:
parent
34bcc3949b
commit
fcc3c52422
55
crypto.go
55
crypto.go
|
@ -41,7 +41,6 @@ func aesKeyLen(strength byte) int {
|
||||||
|
|
||||||
// Encryption/Decryption Errors
|
// Encryption/Decryption Errors
|
||||||
var (
|
var (
|
||||||
ErrEncryption = errors.New("zip: encryption error")
|
|
||||||
ErrDecryption = errors.New("zip: decryption error")
|
ErrDecryption = errors.New("zip: decryption error")
|
||||||
ErrPassword = errors.New("zip: invalid password")
|
ErrPassword = errors.New("zip: invalid password")
|
||||||
ErrAuthentication = errors.New("zip: authentication failed")
|
ErrAuthentication = errors.New("zip: authentication failed")
|
||||||
|
@ -188,16 +187,16 @@ func (a *authReader) Read(p []byte) (int, error) {
|
||||||
a.err = err
|
a.err = err
|
||||||
}
|
}
|
||||||
// write any data to mac
|
// write any data to mac
|
||||||
nn, err := a.mac.Write(p[:n])
|
_, err = a.mac.Write(p[:n])
|
||||||
if nn != n || err != nil {
|
if err != nil {
|
||||||
a.err = io.ErrUnexpectedEOF
|
a.err = err
|
||||||
return n, a.err
|
return n, a.err
|
||||||
}
|
}
|
||||||
if end {
|
if end {
|
||||||
ab := new(bytes.Buffer)
|
ab := new(bytes.Buffer)
|
||||||
_, err = io.Copy(ab, a.adata)
|
_, err = io.Copy(ab, a.adata)
|
||||||
if err != nil || ab.Len() != 10 {
|
if err != nil || ab.Len() != 10 {
|
||||||
a.err = io.ErrUnexpectedEOF
|
a.err = ErrDecryption
|
||||||
return n, a.err
|
return n, a.err
|
||||||
}
|
}
|
||||||
if !a.checkAuthentication(ab.Bytes()) {
|
if !a.checkAuthentication(ab.Bytes()) {
|
||||||
|
@ -223,18 +222,21 @@ func (a *bufferedAuthReader) Read(b []byte) (int, error) {
|
||||||
if !a.auth {
|
if !a.auth {
|
||||||
_, err := io.Copy(a.buf, a.data)
|
_, err := io.Copy(a.buf, a.data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.err = io.ErrUnexpectedEOF
|
a.err = err
|
||||||
return 0, a.err
|
return 0, a.err
|
||||||
}
|
}
|
||||||
ab := new(bytes.Buffer) // remove this buffer and io.Copy to mac
|
ab := new(bytes.Buffer)
|
||||||
nn, err := io.Copy(ab, a.adata)
|
nn, err := io.Copy(ab, a.adata)
|
||||||
if err != nil || nn != 10 {
|
if err != nil {
|
||||||
a.err = io.ErrUnexpectedEOF
|
a.err = err
|
||||||
|
return 0, a.err
|
||||||
|
} else if nn != 10 {
|
||||||
|
a.err = ErrDecryption
|
||||||
return 0, a.err
|
return 0, a.err
|
||||||
}
|
}
|
||||||
mn, err := a.mac.Write(a.buf.Bytes())
|
_, err = a.mac.Write(a.buf.Bytes())
|
||||||
if mn != a.buf.Len() || err != nil {
|
if err != nil {
|
||||||
a.err = io.ErrUnexpectedEOF
|
a.err = err
|
||||||
return 0, a.err
|
return 0, a.err
|
||||||
}
|
}
|
||||||
if !a.checkAuthentication(ab.Bytes()) {
|
if !a.checkAuthentication(ab.Bytes()) {
|
||||||
|
@ -254,7 +256,6 @@ func (a *authReader) checkAuthentication(authcode []byte) bool {
|
||||||
expectedAuthCode := a.mac.Sum(nil)
|
expectedAuthCode := a.mac.Sum(nil)
|
||||||
// Truncate at the first 10 bytes
|
// Truncate at the first 10 bytes
|
||||||
expectedAuthCode = expectedAuthCode[:10]
|
expectedAuthCode = expectedAuthCode[:10]
|
||||||
// Change to use crypto/subtle for constant time comparison
|
|
||||||
a.auth = subtle.ConstantTimeCompare(expectedAuthCode, authcode) > 0
|
a.auth = subtle.ConstantTimeCompare(expectedAuthCode, authcode) > 0
|
||||||
return a.auth
|
return a.auth
|
||||||
}
|
}
|
||||||
|
@ -280,20 +281,18 @@ func newDecryptionReader(r *io.SectionReader, f *File) (io.Reader, error) {
|
||||||
if saltLen == 0 {
|
if saltLen == 0 {
|
||||||
return nil, ErrDecryption
|
return nil, ErrDecryption
|
||||||
}
|
}
|
||||||
// grab the salt, pwvv, data, and authcode
|
// grab the salt and pwvv
|
||||||
saltpwvv := make([]byte, saltLen+2)
|
saltpwvv := make([]byte, saltLen+2)
|
||||||
if _, err := r.Read(saltpwvv); err != nil {
|
if _, err := r.Read(saltpwvv); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
salt := saltpwvv[:saltLen]
|
salt := saltpwvv[:saltLen]
|
||||||
pwvv := saltpwvv[saltLen : saltLen+2]
|
pwvv := saltpwvv[saltLen : saltLen+2]
|
||||||
// generate keys
|
// generate keys only if we have a password
|
||||||
if f.password == nil {
|
if f.password == nil {
|
||||||
return nil, ErrPassword
|
return nil, ErrPassword
|
||||||
}
|
}
|
||||||
decKey, authKey, pwv := generateKeys(f.password(), salt, keyLen)
|
decKey, authKey, pwv := generateKeys(f.password(), salt, keyLen)
|
||||||
// check password verifier (pwv)
|
|
||||||
// Change to use crypto/subtle for constant time comparison
|
|
||||||
if !checkPasswordVerification(pwv, pwvv) {
|
if !checkPasswordVerification(pwv, pwvv) {
|
||||||
return nil, ErrPassword
|
return nil, ErrPassword
|
||||||
}
|
}
|
||||||
|
@ -306,9 +305,7 @@ func newDecryptionReader(r *io.SectionReader, f *File) (io.Reader, error) {
|
||||||
data := io.NewSectionReader(r, dataOff, dataLen)
|
data := io.NewSectionReader(r, dataOff, dataLen)
|
||||||
authOff := dataOff + dataLen
|
authOff := dataOff + dataLen
|
||||||
authcode := io.NewSectionReader(r, authOff, 10)
|
authcode := io.NewSectionReader(r, authOff, 10)
|
||||||
// setup auth reader, (buffered)/streaming
|
|
||||||
ar := newAuthReader(authKey, data, authcode, f.DeferAuth)
|
ar := newAuthReader(authKey, data, authcode, f.DeferAuth)
|
||||||
// return decryption reader
|
|
||||||
dr := decryptStream(decKey, ar)
|
dr := decryptStream(decKey, ar)
|
||||||
if dr == nil {
|
if dr == nil {
|
||||||
return nil, ErrDecryption
|
return nil, ErrDecryption
|
||||||
|
@ -342,12 +339,12 @@ func (aw *authWriter) Write(p []byte) (int, error) {
|
||||||
|
|
||||||
// writes out the salt, pwv, and then the encrypted file data
|
// writes out the salt, pwv, and then the encrypted file data
|
||||||
type encryptionWriter struct {
|
type encryptionWriter struct {
|
||||||
pwv []byte // password verification code to be written
|
pwv []byte
|
||||||
salt []byte // salt to be written
|
salt []byte
|
||||||
w io.Writer // where to write the salt + pwv
|
w io.Writer // where to write the salt + pwv
|
||||||
es io.Writer // where to write plaintext
|
es io.Writer // where to write plaintext
|
||||||
first bool // first write
|
first bool // first write
|
||||||
err error // last error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ew *encryptionWriter) Write(p []byte) (int, error) {
|
func (ew *encryptionWriter) Write(p []byte) (int, error) {
|
||||||
|
@ -372,7 +369,7 @@ func (ew *encryptionWriter) Write(p []byte) (int, error) {
|
||||||
func encryptStream(key []byte, w io.Writer) (io.Writer, error) {
|
func encryptStream(key []byte, w io.Writer) (io.Writer, error) {
|
||||||
block, err := aes.NewCipher(key)
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("zip: couldn't create AES cipher")
|
return nil, err
|
||||||
}
|
}
|
||||||
stream := newWinZipCTR(block)
|
stream := newWinZipCTR(block)
|
||||||
writer := &cipher.StreamWriter{S: stream, W: w}
|
writer := &cipher.StreamWriter{S: stream, W: w}
|
||||||
|
@ -382,13 +379,13 @@ func encryptStream(key []byte, w io.Writer) (io.Writer, error) {
|
||||||
// newEncryptionWriter returns an io.Writer that when written to, 1. writes
|
// newEncryptionWriter returns an io.Writer that when written to, 1. writes
|
||||||
// out the salt, 2. writes out pwv, and 3. writes out authenticated, encrypted
|
// out the salt, 2. writes out pwv, and 3. writes out authenticated, encrypted
|
||||||
// data. The authcode will be written out in fileWriter.close().
|
// data. The authcode will be written out in fileWriter.close().
|
||||||
func newEncryptionWriter(w io.Writer, fh *FileHeader, fw *fileWriter) (io.Writer, error) {
|
func newEncryptionWriter(w io.Writer, password passwordFn, fw *fileWriter) (io.Writer, error) {
|
||||||
var salt [16]byte
|
var salt [16]byte
|
||||||
_, err := rand.Read(salt[:])
|
_, err := rand.Read(salt[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("zip: unable to generate random salt")
|
return nil, errors.New("zip: unable to generate random salt")
|
||||||
}
|
}
|
||||||
ekey, akey, pwv := generateKeys(fh.password(), salt[:], aes256)
|
ekey, akey, pwv := generateKeys(password(), salt[:], aes256)
|
||||||
fw.hmac = hmac.New(sha1.New, akey)
|
fw.hmac = hmac.New(sha1.New, akey)
|
||||||
aw := &authWriter{
|
aw := &authWriter{
|
||||||
hmac: fw.hmac,
|
hmac: fw.hmac,
|
||||||
|
@ -450,9 +447,11 @@ func (h *FileHeader) SetPassword(password string) {
|
||||||
// as a byte slice
|
// as a byte slice
|
||||||
type passwordFn func() []byte
|
type passwordFn func() []byte
|
||||||
|
|
||||||
// Encrypt is similar to Create except that it will encrypt the file contents
|
// Encrypt adds a file to the zip file using the provided name.
|
||||||
// using AES-256 with the given password. Must follow all the same constraints
|
// It returns a Writer to which the file contents should be written. File
|
||||||
// as Create.
|
// 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) (io.Writer, error) {
|
func (w *Writer) Encrypt(name string, password string) (io.Writer, error) {
|
||||||
fh := &FileHeader{
|
fh := &FileHeader{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
|
|
@ -232,9 +232,9 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
||||||
// we have a password and need to encrypt.
|
// we have a password and need to encrypt.
|
||||||
fh.writeWinZipExtra()
|
fh.writeWinZipExtra()
|
||||||
fh.Method = 99 // ok to change, we've gotten the comp and wrote extra
|
fh.Method = 99 // ok to change, we've gotten the comp and wrote extra
|
||||||
ew, err := newEncryptionWriter(sw, fh, fw)
|
ew, err := newEncryptionWriter(sw, fh.password, fw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("zip: unable to create an encryption writer")
|
return nil, err
|
||||||
}
|
}
|
||||||
sw = ew
|
sw = ew
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue