diff --git a/backend/crypt/cipher.go b/backend/crypt/cipher.go index ae1e62393..e90d75615 100644 --- a/backend/crypt/cipher.go +++ b/backend/crypt/cipher.go @@ -21,6 +21,7 @@ import ( "github.com/rclone/rclone/backend/crypt/pkcs7" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/accounting" + "github.com/rclone/rclone/lib/readers" "github.com/rclone/rclone/lib/version" "github.com/rfjakob/eme" "golang.org/x/crypto/nacl/secretbox" @@ -609,7 +610,7 @@ func (n *nonce) pointer() *[fileNonceSize]byte { // fromReader fills the nonce from an io.Reader - normally the OSes // crypto random number generator func (n *nonce) fromReader(in io.Reader) error { - read, err := io.ReadFull(in, (*n)[:]) + read, err := readers.ReadFill(in, (*n)[:]) if read != fileNonceSize { return fmt.Errorf("short read of nonce: %w", err) } @@ -708,14 +709,12 @@ func (fh *encrypter) Read(p []byte) (n int, err error) { // Read data // FIXME should overlap the reads with a go-routine and 2 buffers? readBuf := fh.readBuf[:blockDataSize] - n, err = io.ReadFull(fh.in, readBuf) + n, err = readers.ReadFill(fh.in, readBuf) if n == 0 { - // err can't be nil since: - // n == len(buf) if and only if err == nil. return fh.finish(err) } // possibly err != nil here, but we will process the - // data and the next call to ReadFull will return 0, err + // data and the next call to ReadFill will return 0, err // Encrypt the block using the nonce secretbox.Seal(fh.buf[:0], readBuf[:n], fh.nonce.pointer(), &fh.c.dataKey) fh.bufIndex = 0 @@ -783,8 +782,8 @@ func (c *Cipher) newDecrypter(rc io.ReadCloser) (*decrypter, error) { } // Read file header (magic + nonce) readBuf := fh.readBuf[:fileHeaderSize] - _, err := io.ReadFull(fh.rc, readBuf) - if err == io.EOF || err == io.ErrUnexpectedEOF { + n, err := readers.ReadFill(fh.rc, readBuf) + if n < fileHeaderSize && err == io.EOF { // This read from 0..fileHeaderSize-1 bytes return nil, fh.finishAndClose(ErrorEncryptedFileTooShort) } else if err != nil { @@ -845,10 +844,8 @@ func (c *Cipher) newDecrypterSeek(ctx context.Context, open OpenRangeSeek, offse func (fh *decrypter) fillBuffer() (err error) { // FIXME should overlap the reads with a go-routine and 2 buffers? readBuf := fh.readBuf - n, err := io.ReadFull(fh.rc, readBuf) + n, err := readers.ReadFill(fh.rc, readBuf) if n == 0 { - // err can't be nil since: - // n == len(buf) if and only if err == nil. return err } // possibly err != nil here, but we will process the data and @@ -856,7 +853,7 @@ func (fh *decrypter) fillBuffer() (err error) { // Check header + 1 byte exists if n <= blockHeaderSize { - if err != nil { + if err != nil && err != io.EOF { return err // return pending error as it is likely more accurate } return ErrorEncryptedFileBadHeader @@ -864,7 +861,7 @@ func (fh *decrypter) fillBuffer() (err error) { // Decrypt the block using the nonce _, ok := secretbox.Open(fh.buf[:0], readBuf[:n], fh.nonce.pointer(), &fh.c.dataKey) if !ok { - if err != nil { + if err != nil && err != io.EOF { return err // return pending error as it is likely more accurate } return ErrorEncryptedBadBlock diff --git a/backend/crypt/cipher_test.go b/backend/crypt/cipher_test.go index 9ff4fdcc1..6b683b437 100644 --- a/backend/crypt/cipher_test.go +++ b/backend/crypt/cipher_test.go @@ -1495,8 +1495,10 @@ func TestDecrypterRead(t *testing.T) { case i == fileHeaderSize: // This would normally produce an error *except* on the first block expectedErr = nil + case i <= fileHeaderSize+blockHeaderSize: + expectedErr = ErrorEncryptedFileBadHeader default: - expectedErr = io.ErrUnexpectedEOF + expectedErr = ErrorEncryptedBadBlock } if expectedErr != nil { assert.EqualError(t, err, expectedErr.Error(), what)