forked from TrueCloudLab/restic
Use Seal/Open everywhere
This commit is contained in:
parent
a5f0e9ab65
commit
931e6ed2ac
6 changed files with 49 additions and 59 deletions
|
@ -32,6 +32,7 @@ type Rdr interface {
|
||||||
func benchmarkChunkEncrypt(b testing.TB, buf, buf2 []byte, rd Rdr, key *crypto.Key) {
|
func benchmarkChunkEncrypt(b testing.TB, buf, buf2 []byte, rd Rdr, key *crypto.Key) {
|
||||||
rd.Seek(0, 0)
|
rd.Seek(0, 0)
|
||||||
ch := chunker.New(rd, testPol)
|
ch := chunker.New(rd, testPol)
|
||||||
|
nonce := crypto.NewRandomNonce()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
chunk, err := ch.Next(buf)
|
chunk, err := ch.Next(buf)
|
||||||
|
@ -42,12 +43,10 @@ func benchmarkChunkEncrypt(b testing.TB, buf, buf2 []byte, rd Rdr, key *crypto.K
|
||||||
|
|
||||||
rtest.OK(b, err)
|
rtest.OK(b, err)
|
||||||
|
|
||||||
// reduce length of buf
|
|
||||||
rtest.Assert(b, uint(len(chunk.Data)) == chunk.Length,
|
rtest.Assert(b, uint(len(chunk.Data)) == chunk.Length,
|
||||||
"invalid length: got %d, expected %d", len(chunk.Data), chunk.Length)
|
"invalid length: got %d, expected %d", len(chunk.Data), chunk.Length)
|
||||||
|
|
||||||
_, err = key.Encrypt(buf2, chunk.Data)
|
_ = key.Seal(buf2[:0], nonce, chunk.Data, nil)
|
||||||
rtest.OK(b, err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +70,7 @@ func BenchmarkChunkEncrypt(b *testing.B) {
|
||||||
|
|
||||||
func benchmarkChunkEncryptP(b *testing.PB, buf []byte, rd Rdr, key *crypto.Key) {
|
func benchmarkChunkEncryptP(b *testing.PB, buf []byte, rd Rdr, key *crypto.Key) {
|
||||||
ch := chunker.New(rd, testPol)
|
ch := chunker.New(rd, testPol)
|
||||||
|
nonce := crypto.NewRandomNonce()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
chunk, err := ch.Next(buf)
|
chunk, err := ch.Next(buf)
|
||||||
|
@ -78,8 +78,7 @@ func benchmarkChunkEncryptP(b *testing.PB, buf []byte, rd Rdr, key *crypto.Key)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// reduce length of chunkBuf
|
_ = key.Seal(chunk.Data[:0], nonce, chunk.Data, nil)
|
||||||
key.Encrypt(chunk.Data, chunk.Data)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -724,15 +724,15 @@ func checkPack(ctx context.Context, r restic.Repository, id restic.ID) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := r.Key().Decrypt(buf, buf)
|
nonce, ciphertext := buf[:r.Key().NonceSize()], buf[r.Key().NonceSize():]
|
||||||
|
plaintext, err := r.Key().Open(ciphertext[:0], nonce, ciphertext, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
debug.Log(" error decrypting blob %v: %v", blob.ID.Str(), err)
|
debug.Log(" error decrypting blob %v: %v", blob.ID.Str(), err)
|
||||||
errs = append(errs, errors.Errorf("blob %v: %v", i, err))
|
errs = append(errs, errors.Errorf("blob %v: %v", i, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buf = buf[:n]
|
|
||||||
|
|
||||||
hash := restic.Hash(buf)
|
hash := restic.Hash(plaintext)
|
||||||
if !hash.Equal(blob.ID) {
|
if !hash.Equal(blob.ID) {
|
||||||
debug.Log(" Blob ID does not match, want %v, got %v", blob.ID.Str(), hash.Str())
|
debug.Log(" Blob ID does not match, want %v, got %v", blob.ID.Str(), hash.Str())
|
||||||
errs = append(errs, errors.Errorf("Blob ID does not match, want %v, got %v", blob.ID.Str(), hash.Str()))
|
errs = append(errs, errors.Errorf("Blob ID does not match, want %v, got %v", blob.ID.Str(), hash.Str()))
|
||||||
|
|
|
@ -75,10 +75,10 @@ func (p *Packer) Finalize() (uint, error) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
encryptedHeader, err := p.k.Encrypt(nil, hdrBuf.Bytes())
|
encryptedHeader := make([]byte, 0, hdrBuf.Len()+p.k.Overhead()+p.k.NonceSize())
|
||||||
if err != nil {
|
nonce := crypto.NewRandomNonce()
|
||||||
return 0, err
|
encryptedHeader = append(encryptedHeader, nonce...)
|
||||||
}
|
encryptedHeader = p.k.Seal(encryptedHeader, nonce, hdrBuf.Bytes(), nil)
|
||||||
|
|
||||||
// append the header
|
// append the header
|
||||||
n, err := p.wr.Write(encryptedHeader)
|
n, err := p.wr.Write(encryptedHeader)
|
||||||
|
@ -268,15 +268,19 @@ func List(k *crypto.Key, rd io.ReaderAt, size int64) (entries []restic.Blob, err
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := k.Decrypt(buf, buf)
|
if len(buf) < k.NonceSize()+k.Overhead() {
|
||||||
|
return nil, errors.New("invalid header, too small")
|
||||||
|
}
|
||||||
|
|
||||||
|
nonce, buf := buf[:k.NonceSize()], buf[k.NonceSize():]
|
||||||
|
buf, err = k.Open(buf[:0], nonce, buf, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
buf = buf[:n]
|
|
||||||
|
|
||||||
hdrRd := bytes.NewReader(buf)
|
hdrRd := bytes.NewReader(buf)
|
||||||
|
|
||||||
entries = make([]restic.Blob, 0, uint(n)/entrySize)
|
entries = make([]restic.Blob, 0, uint(len(buf))/entrySize)
|
||||||
|
|
||||||
pos := uint(0)
|
pos := uint(0)
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -87,12 +87,12 @@ func OpenKey(ctx context.Context, s *Repository, name string, password string) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt master keys
|
// decrypt master keys
|
||||||
buf := make([]byte, len(k.Data))
|
nonce, ciphertext := k.Data[:k.user.NonceSize()], k.Data[k.user.NonceSize():]
|
||||||
n, err := k.user.Decrypt(buf, k.Data)
|
buf := make([]byte, 0, len(ciphertext))
|
||||||
|
buf, err = k.user.Open(buf, nonce, ciphertext, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
buf = buf[:n]
|
|
||||||
|
|
||||||
// restore json
|
// restore json
|
||||||
k.master = &crypto.Key{}
|
k.master = &crypto.Key{}
|
||||||
|
@ -221,7 +221,11 @@ func AddKey(ctx context.Context, s *Repository, password string, template *crypt
|
||||||
return nil, errors.Wrap(err, "Marshal")
|
return nil, errors.Wrap(err, "Marshal")
|
||||||
}
|
}
|
||||||
|
|
||||||
newkey.Data, err = newkey.user.Encrypt(nil, buf)
|
nonce := crypto.NewRandomNonce()
|
||||||
|
ciphertext := make([]byte, 0, len(buf)+newkey.user.Overhead()+newkey.user.NonceSize())
|
||||||
|
ciphertext = append(ciphertext, nonce...)
|
||||||
|
ciphertext = newkey.user.Seal(ciphertext, nonce, buf, nil)
|
||||||
|
newkey.Data = ciphertext
|
||||||
|
|
||||||
// dump as json
|
// dump as json
|
||||||
buf, err = json.Marshal(newkey)
|
buf, err = json.Marshal(newkey)
|
||||||
|
|
|
@ -90,14 +90,13 @@ func Repack(ctx context.Context, repo restic.Repository, packs restic.IDSet, kee
|
||||||
h, tempfile.Name(), len(buf), n)
|
h, tempfile.Name(), len(buf), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err = repo.Key().Decrypt(buf, buf)
|
nonce, ciphertext := buf[:repo.Key().NonceSize()], buf[repo.Key().NonceSize():]
|
||||||
|
plaintext, err := repo.Key().Open(ciphertext[:0], nonce, ciphertext, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = buf[:n]
|
id := restic.Hash(plaintext)
|
||||||
|
|
||||||
id := restic.Hash(buf)
|
|
||||||
if !id.Equal(entry.ID) {
|
if !id.Equal(entry.ID) {
|
||||||
debug.Log("read blob %v/%v from %v: wrong data returned, hash is %v",
|
debug.Log("read blob %v/%v from %v: wrong data returned, hash is %v",
|
||||||
h.Type, h.ID, tempfile.Name(), id)
|
h.Type, h.ID, tempfile.Name(), id)
|
||||||
|
@ -105,7 +104,7 @@ func Repack(ctx context.Context, repo restic.Repository, packs restic.IDSet, kee
|
||||||
h, tempfile.Name(), id)
|
h, tempfile.Name(), id)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = repo.SaveBlob(ctx, entry.Type, buf, entry.ID)
|
_, err = repo.SaveBlob(ctx, entry.Type, plaintext, entry.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,13 +79,13 @@ func (r *Repository) LoadAndDecrypt(ctx context.Context, t restic.FileType, id r
|
||||||
return nil, errors.Errorf("load %v: invalid data returned", h)
|
return nil, errors.Errorf("load %v: invalid data returned", h)
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt
|
nonce, ciphertext := buf[:r.key.NonceSize()], buf[r.key.NonceSize():]
|
||||||
n, err := r.decryptTo(buf, buf)
|
plaintext, err := r.key.Open(ciphertext[:0], nonce, ciphertext, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf[:n], nil
|
return plaintext, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// sortCachedPacks moves all cached pack files to the front of blobs.
|
// sortCachedPacks moves all cached pack files to the front of blobs.
|
||||||
|
@ -156,20 +156,22 @@ func (r *Repository) loadBlob(ctx context.Context, id restic.ID, t restic.BlobTy
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt
|
// decrypt
|
||||||
n, err = r.decryptTo(plaintextBuf, plaintextBuf)
|
nonce, ciphertext := plaintextBuf[:r.key.NonceSize()], plaintextBuf[r.key.NonceSize():]
|
||||||
|
plaintext, err := r.key.Open(ciphertext[:0], nonce, ciphertext, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastError = errors.Errorf("decrypting blob %v failed: %v", id, err)
|
lastError = errors.Errorf("decrypting blob %v failed: %v", id, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
plaintextBuf = plaintextBuf[:n]
|
|
||||||
|
|
||||||
// check hash
|
// check hash
|
||||||
if !restic.Hash(plaintextBuf).Equal(id) {
|
if !restic.Hash(plaintext).Equal(id) {
|
||||||
lastError = errors.Errorf("blob %v returned invalid hash", id)
|
lastError = errors.Errorf("blob %v returned invalid hash", id)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(plaintextBuf), nil
|
// move decrypted data to the start of the provided buffer
|
||||||
|
copy(plaintextBuf[0:], plaintext)
|
||||||
|
return len(plaintext), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastError != nil {
|
if lastError != nil {
|
||||||
|
@ -210,11 +212,12 @@ func (r *Repository) SaveAndEncrypt(ctx context.Context, t restic.BlobType, data
|
||||||
ciphertext := getBuf()
|
ciphertext := getBuf()
|
||||||
defer freeBuf(ciphertext)
|
defer freeBuf(ciphertext)
|
||||||
|
|
||||||
|
ciphertext = ciphertext[:0]
|
||||||
|
nonce := crypto.NewRandomNonce()
|
||||||
|
ciphertext = append(ciphertext, nonce...)
|
||||||
|
|
||||||
// encrypt blob
|
// encrypt blob
|
||||||
ciphertext, err := r.Encrypt(ciphertext, data)
|
ciphertext = r.key.Seal(ciphertext, nonce, data, nil)
|
||||||
if err != nil {
|
|
||||||
return restic.ID{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// find suitable packer and add blob
|
// find suitable packer and add blob
|
||||||
var pm *packerManager
|
var pm *packerManager
|
||||||
|
@ -266,10 +269,11 @@ func (r *Repository) SaveJSONUnpacked(ctx context.Context, t restic.FileType, it
|
||||||
// storage hash.
|
// storage hash.
|
||||||
func (r *Repository) SaveUnpacked(ctx context.Context, t restic.FileType, p []byte) (id restic.ID, err error) {
|
func (r *Repository) SaveUnpacked(ctx context.Context, t restic.FileType, p []byte) (id restic.ID, err error) {
|
||||||
ciphertext := restic.NewBlobBuffer(len(p))
|
ciphertext := restic.NewBlobBuffer(len(p))
|
||||||
ciphertext, err = r.Encrypt(ciphertext, p)
|
ciphertext = ciphertext[:0]
|
||||||
if err != nil {
|
nonce := crypto.NewRandomNonce()
|
||||||
return restic.ID{}, err
|
ciphertext = append(ciphertext, nonce...)
|
||||||
}
|
|
||||||
|
ciphertext = r.key.Seal(ciphertext, nonce, p, nil)
|
||||||
|
|
||||||
id = restic.Hash(ciphertext)
|
id = restic.Hash(ciphertext)
|
||||||
h := restic.Handle{Type: t, Name: id.String()}
|
h := restic.Handle{Type: t, Name: id.String()}
|
||||||
|
@ -522,26 +526,6 @@ func (r *Repository) init(ctx context.Context, password string, cfg restic.Confi
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypt authenticates and decrypts ciphertext and stores the result in
|
|
||||||
// plaintext.
|
|
||||||
func (r *Repository) decryptTo(plaintext, ciphertext []byte) (int, error) {
|
|
||||||
if r.key == nil {
|
|
||||||
return 0, errors.New("key for repository not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.key.Decrypt(plaintext, ciphertext)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt encrypts and authenticates the plaintext and saves the result in
|
|
||||||
// ciphertext.
|
|
||||||
func (r *Repository) Encrypt(ciphertext, plaintext []byte) ([]byte, error) {
|
|
||||||
if r.key == nil {
|
|
||||||
return nil, errors.New("key for repository not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.key.Encrypt(ciphertext, plaintext)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key returns the current master key.
|
// Key returns the current master key.
|
||||||
func (r *Repository) Key() *crypto.Key {
|
func (r *Repository) Key() *crypto.Key {
|
||||||
return r.key
|
return r.key
|
||||||
|
|
Loading…
Reference in a new issue