mirror of
https://github.com/rclone/rclone.git
synced 2026-02-19 02:43:32 +00:00
Add cryptcheck command to check integrity of crypt remotes #1102
This commit is contained in:
@@ -416,7 +416,7 @@ type encrypter struct {
|
||||
}
|
||||
|
||||
// newEncrypter creates a new file handle encrypting on the fly
|
||||
func (c *cipher) newEncrypter(in io.Reader) (*encrypter, error) {
|
||||
func (c *cipher) newEncrypter(in io.Reader, nonce *nonce) (*encrypter, error) {
|
||||
fh := &encrypter{
|
||||
in: in,
|
||||
c: c,
|
||||
@@ -425,9 +425,13 @@ func (c *cipher) newEncrypter(in io.Reader) (*encrypter, error) {
|
||||
bufSize: fileHeaderSize,
|
||||
}
|
||||
// Initialise nonce
|
||||
err := fh.nonce.fromReader(c.cryptoRand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if nonce != nil {
|
||||
fh.nonce = *nonce
|
||||
} else {
|
||||
err := fh.nonce.fromReader(c.cryptoRand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Copy magic into buffer
|
||||
copy(fh.buf, fileMagicBytes)
|
||||
@@ -485,7 +489,7 @@ func (fh *encrypter) finish(err error) (int, error) {
|
||||
|
||||
// Encrypt data encrypts the data stream
|
||||
func (c *cipher) EncryptData(in io.Reader) (io.Reader, error) {
|
||||
out, err := c.newEncrypter(in)
|
||||
out, err := c.newEncrypter(in, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -681,7 +681,7 @@ func testEncryptDecrypt(t *testing.T, bufSize int, copySize int64) {
|
||||
c.cryptoRand = &zeroes{} // zero out the nonce
|
||||
buf := make([]byte, bufSize)
|
||||
source := newRandomSource(copySize)
|
||||
encrypted, err := c.newEncrypter(source)
|
||||
encrypted, err := c.newEncrypter(source, nil)
|
||||
assert.NoError(t, err)
|
||||
decrypted, err := c.newDecrypter(ioutil.NopCloser(encrypted))
|
||||
assert.NoError(t, err)
|
||||
@@ -775,14 +775,14 @@ func TestNewEncrypter(t *testing.T) {
|
||||
|
||||
z := &zeroes{}
|
||||
|
||||
fh, err := c.newEncrypter(z)
|
||||
fh, err := c.newEncrypter(z, nil)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, nonce{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}, fh.nonce)
|
||||
assert.Equal(t, []byte{'R', 'C', 'L', 'O', 'N', 'E', 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}, fh.buf[:32])
|
||||
|
||||
// Test error path
|
||||
c.cryptoRand = bytes.NewBufferString("123456789abcdefghijklmn")
|
||||
fh, err = c.newEncrypter(z)
|
||||
fh, err = c.newEncrypter(z, nil)
|
||||
assert.Nil(t, fh)
|
||||
assert.Error(t, err, "short read of nonce")
|
||||
|
||||
@@ -795,7 +795,7 @@ func TestNewEncrypterErrUnexpectedEOF(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
|
||||
in := &errorReader{io.ErrUnexpectedEOF}
|
||||
fh, err := c.newEncrypter(in)
|
||||
fh, err := c.newEncrypter(in, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
n, err := io.CopyN(ioutil.Discard, fh, 1E6)
|
||||
|
||||
@@ -312,6 +312,59 @@ func (f *Fs) UnWrap() fs.Fs {
|
||||
return f.Fs
|
||||
}
|
||||
|
||||
// ComputeHash takes the nonce from o, and encrypts the contents of
|
||||
// src with it, and calcuates the hash given by HashType on the fly
|
||||
//
|
||||
// Note that we break lots of encapsulation in this function.
|
||||
func (f *Fs) ComputeHash(o *Object, src fs.Object, hashType fs.HashType) (hash string, err error) {
|
||||
// Read the nonce - opening the file is sufficient to read the nonce in
|
||||
in, err := o.Open()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to read nonce")
|
||||
}
|
||||
nonce := in.(*decrypter).nonce
|
||||
// fs.Debugf(o, "Read nonce % 2x", nonce)
|
||||
|
||||
// Check nonce isn't all zeros
|
||||
isZero := true
|
||||
for i := range nonce {
|
||||
if nonce[i] != 0 {
|
||||
isZero = false
|
||||
}
|
||||
}
|
||||
if isZero {
|
||||
fs.Errorf(o, "empty nonce read")
|
||||
}
|
||||
|
||||
// Close in once we have read the nonce
|
||||
err = in.Close()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to close nonce read")
|
||||
}
|
||||
|
||||
// Open the src for input
|
||||
in, err = src.Open()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to open src")
|
||||
}
|
||||
defer fs.CheckClose(in, &err)
|
||||
|
||||
// Now encrypt the src with the nonce
|
||||
out, err := f.cipher.(*cipher).newEncrypter(in, &nonce)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to make encrypter")
|
||||
}
|
||||
|
||||
// pipe into hash
|
||||
m := fs.NewMultiHasher()
|
||||
_, err = io.Copy(m, out)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to hash data")
|
||||
}
|
||||
|
||||
return m.Sums()[hashType], nil
|
||||
}
|
||||
|
||||
// Object describes a wrapped for being read from the Fs
|
||||
//
|
||||
// This decrypts the remote name and decrypts the data
|
||||
@@ -366,6 +419,11 @@ func (o *Object) Hash(hash fs.HashType) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// UnWrap returns the wrapped Object
|
||||
func (o *Object) UnWrap() fs.Object {
|
||||
return o.Object
|
||||
}
|
||||
|
||||
// Open opens the file for read. Call Close() on the returned io.ReadCloser
|
||||
func (o *Object) Open(options ...fs.OpenOption) (rc io.ReadCloser, err error) {
|
||||
var offset int64
|
||||
|
||||
Reference in New Issue
Block a user