mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 15:30:06 +08:00
crypt: try not to return "unexpected EOF" error
Before this change the code wasn't taking into account the error io.ErrUnexpectedEOF that io.ReadFull can return properly. Sometimes that error was being returned instead of a more specific and useful error. To fix this, io.ReadFull was replaced with the simpler readers.ReadFill which is much easier to use correctly.
This commit is contained in:
parent
07c4d95f38
commit
d5afcf9e34
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/rclone/rclone/backend/crypt/pkcs7"
|
"github.com/rclone/rclone/backend/crypt/pkcs7"
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
"github.com/rclone/rclone/fs/accounting"
|
"github.com/rclone/rclone/fs/accounting"
|
||||||
|
"github.com/rclone/rclone/lib/readers"
|
||||||
"github.com/rclone/rclone/lib/version"
|
"github.com/rclone/rclone/lib/version"
|
||||||
"github.com/rfjakob/eme"
|
"github.com/rfjakob/eme"
|
||||||
"golang.org/x/crypto/nacl/secretbox"
|
"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
|
// fromReader fills the nonce from an io.Reader - normally the OSes
|
||||||
// crypto random number generator
|
// crypto random number generator
|
||||||
func (n *nonce) fromReader(in io.Reader) error {
|
func (n *nonce) fromReader(in io.Reader) error {
|
||||||
read, err := io.ReadFull(in, (*n)[:])
|
read, err := readers.ReadFill(in, (*n)[:])
|
||||||
if read != fileNonceSize {
|
if read != fileNonceSize {
|
||||||
return fmt.Errorf("short read of nonce: %w", err)
|
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
|
// Read data
|
||||||
// FIXME should overlap the reads with a go-routine and 2 buffers?
|
// FIXME should overlap the reads with a go-routine and 2 buffers?
|
||||||
readBuf := fh.readBuf[:blockDataSize]
|
readBuf := fh.readBuf[:blockDataSize]
|
||||||
n, err = io.ReadFull(fh.in, readBuf)
|
n, err = readers.ReadFill(fh.in, readBuf)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
// err can't be nil since:
|
|
||||||
// n == len(buf) if and only if err == nil.
|
|
||||||
return fh.finish(err)
|
return fh.finish(err)
|
||||||
}
|
}
|
||||||
// possibly err != nil here, but we will process the
|
// 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
|
// Encrypt the block using the nonce
|
||||||
secretbox.Seal(fh.buf[:0], readBuf[:n], fh.nonce.pointer(), &fh.c.dataKey)
|
secretbox.Seal(fh.buf[:0], readBuf[:n], fh.nonce.pointer(), &fh.c.dataKey)
|
||||||
fh.bufIndex = 0
|
fh.bufIndex = 0
|
||||||
|
@ -783,8 +782,8 @@ func (c *Cipher) newDecrypter(rc io.ReadCloser) (*decrypter, error) {
|
||||||
}
|
}
|
||||||
// Read file header (magic + nonce)
|
// Read file header (magic + nonce)
|
||||||
readBuf := fh.readBuf[:fileHeaderSize]
|
readBuf := fh.readBuf[:fileHeaderSize]
|
||||||
_, err := io.ReadFull(fh.rc, readBuf)
|
n, err := readers.ReadFill(fh.rc, readBuf)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if n < fileHeaderSize && err == io.EOF {
|
||||||
// This read from 0..fileHeaderSize-1 bytes
|
// This read from 0..fileHeaderSize-1 bytes
|
||||||
return nil, fh.finishAndClose(ErrorEncryptedFileTooShort)
|
return nil, fh.finishAndClose(ErrorEncryptedFileTooShort)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -845,10 +844,8 @@ func (c *Cipher) newDecrypterSeek(ctx context.Context, open OpenRangeSeek, offse
|
||||||
func (fh *decrypter) fillBuffer() (err error) {
|
func (fh *decrypter) fillBuffer() (err error) {
|
||||||
// FIXME should overlap the reads with a go-routine and 2 buffers?
|
// FIXME should overlap the reads with a go-routine and 2 buffers?
|
||||||
readBuf := fh.readBuf
|
readBuf := fh.readBuf
|
||||||
n, err := io.ReadFull(fh.rc, readBuf)
|
n, err := readers.ReadFill(fh.rc, readBuf)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
// err can't be nil since:
|
|
||||||
// n == len(buf) if and only if err == nil.
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// possibly err != nil here, but we will process the data and
|
// 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
|
// Check header + 1 byte exists
|
||||||
if n <= blockHeaderSize {
|
if n <= blockHeaderSize {
|
||||||
if err != nil {
|
if err != nil && err != io.EOF {
|
||||||
return err // return pending error as it is likely more accurate
|
return err // return pending error as it is likely more accurate
|
||||||
}
|
}
|
||||||
return ErrorEncryptedFileBadHeader
|
return ErrorEncryptedFileBadHeader
|
||||||
|
@ -864,7 +861,7 @@ func (fh *decrypter) fillBuffer() (err error) {
|
||||||
// Decrypt the block using the nonce
|
// Decrypt the block using the nonce
|
||||||
_, ok := secretbox.Open(fh.buf[:0], readBuf[:n], fh.nonce.pointer(), &fh.c.dataKey)
|
_, ok := secretbox.Open(fh.buf[:0], readBuf[:n], fh.nonce.pointer(), &fh.c.dataKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
if err != nil {
|
if err != nil && err != io.EOF {
|
||||||
return err // return pending error as it is likely more accurate
|
return err // return pending error as it is likely more accurate
|
||||||
}
|
}
|
||||||
return ErrorEncryptedBadBlock
|
return ErrorEncryptedBadBlock
|
||||||
|
|
|
@ -1495,8 +1495,10 @@ func TestDecrypterRead(t *testing.T) {
|
||||||
case i == fileHeaderSize:
|
case i == fileHeaderSize:
|
||||||
// This would normally produce an error *except* on the first block
|
// This would normally produce an error *except* on the first block
|
||||||
expectedErr = nil
|
expectedErr = nil
|
||||||
|
case i <= fileHeaderSize+blockHeaderSize:
|
||||||
|
expectedErr = ErrorEncryptedFileBadHeader
|
||||||
default:
|
default:
|
||||||
expectedErr = io.ErrUnexpectedEOF
|
expectedErr = ErrorEncryptedBadBlock
|
||||||
}
|
}
|
||||||
if expectedErr != nil {
|
if expectedErr != nil {
|
||||||
assert.EqualError(t, err, expectedErr.Error(), what)
|
assert.EqualError(t, err, expectedErr.Error(), what)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user