mirror of https://github.com/restic/restic.git
backup: verify blobs before upload
This only covers the blobs themselves, the pack header is not verified so far. Unpacked files are also not covered by the integrity check.
This commit is contained in:
parent
0ea62b5ac6
commit
2f30c940b2
|
@ -423,6 +423,11 @@ func (r *Repository) saveAndEncrypt(ctx context.Context, t restic.BlobType, data
|
|||
// encrypt blob
|
||||
ciphertext = r.key.Seal(ciphertext, nonce, data, nil)
|
||||
|
||||
if err := r.verifyCiphertext(ciphertext, uncompressedLength, id); err != nil {
|
||||
// FIXME call to action
|
||||
return 0, fmt.Errorf("detected data corruption while saving blob %v: %w", id, err)
|
||||
}
|
||||
|
||||
// find suitable packer and add blob
|
||||
var pm *packerManager
|
||||
|
||||
|
@ -438,6 +443,27 @@ func (r *Repository) saveAndEncrypt(ctx context.Context, t restic.BlobType, data
|
|||
return pm.SaveBlob(ctx, t, id, ciphertext, uncompressedLength)
|
||||
}
|
||||
|
||||
func (r *Repository) verifyCiphertext(buf []byte, uncompressedLength int, id restic.ID) error {
|
||||
nonce, ciphertext := buf[:r.key.NonceSize()], buf[r.key.NonceSize():]
|
||||
plaintext, err := r.key.Open(nil, nonce, ciphertext, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decryption failed: %w", err)
|
||||
}
|
||||
if uncompressedLength != 0 {
|
||||
// DecodeAll will allocate a slice if it is not large enough since it
|
||||
// knows the decompressed size (because we're using EncodeAll)
|
||||
plaintext, err = r.getZstdDecoder().DecodeAll(plaintext, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decompression failed: %w", err)
|
||||
}
|
||||
}
|
||||
if !restic.Hash(plaintext).Equal(id) {
|
||||
return errors.New("hash mismatch")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) compressUnpacked(p []byte) ([]byte, error) {
|
||||
// compression is only available starting from version 2
|
||||
if r.cfg.Version < 2 {
|
||||
|
|
Loading…
Reference in New Issue