mirror of
https://github.com/octoleo/restic.git
synced 2024-11-01 03:12:31 +00:00
Use large, dynamic buffer for encrypting maps
This commit is contained in:
parent
2d8dc7b695
commit
719e121c74
@ -48,7 +48,7 @@ func BenchmarkChunkEncrypt(b *testing.B) {
|
|||||||
|
|
||||||
ok(b, err)
|
ok(b, err)
|
||||||
|
|
||||||
buf := make([]byte, khepri.MaxCiphertextSize)
|
buf := make([]byte, khepri.CiphertextExtension+chunker.MaxSize)
|
||||||
_, err = key.Encrypt(buf, chunk_data.Data)
|
_, err = key.Encrypt(buf, chunk_data.Data)
|
||||||
ok(b, err)
|
ok(b, err)
|
||||||
}
|
}
|
||||||
|
@ -81,13 +81,23 @@ func (ch *ContentHandler) Save(t backend.Type, data []byte) (Blob, error) {
|
|||||||
Size: uint64(len(data)),
|
Size: uint64(len(data)),
|
||||||
}
|
}
|
||||||
|
|
||||||
// encrypt blob
|
var ciphertext []byte
|
||||||
ciphertext := GetChunkBuf("ch.Save()")
|
|
||||||
|
// for a bloblist/map, use a larger buffer
|
||||||
|
if t == backend.Map {
|
||||||
|
ciphertext = make([]byte, len(data)+CiphertextExtension)
|
||||||
|
} else {
|
||||||
|
// otherwise use buffer from pool
|
||||||
|
ciphertext = GetChunkBuf("ch.Save()")
|
||||||
defer FreeChunkBuf("ch.Save()", ciphertext)
|
defer FreeChunkBuf("ch.Save()", ciphertext)
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt blob
|
||||||
n, err := ch.key.Encrypt(ciphertext, data)
|
n, err := ch.key.Encrypt(ciphertext, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Blob{}, err
|
return Blob{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ciphertext = ciphertext[:n]
|
ciphertext = ciphertext[:n]
|
||||||
|
|
||||||
// save blob
|
// save blob
|
||||||
|
13
key.go
13
key.go
@ -21,16 +21,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// max size is 8MiB, defined in chunker
|
// max size is 8MiB, defined in chunker
|
||||||
const maxDataSize = chunker.MaxSize
|
|
||||||
const ivSize = aes.BlockSize
|
const ivSize = aes.BlockSize
|
||||||
const hmacSize = sha256.Size
|
const hmacSize = sha256.Size
|
||||||
const MaxCiphertextSize = ivSize + maxDataSize + hmacSize
|
const maxCiphertextSize = ivSize + chunker.MaxSize + hmacSize
|
||||||
|
const CiphertextExtension = ivSize + hmacSize
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrUnauthenticated is returned when ciphertext verification has failed.
|
// ErrUnauthenticated is returned when ciphertext verification has failed.
|
||||||
ErrUnauthenticated = errors.New("ciphertext verification failed")
|
ErrUnauthenticated = errors.New("ciphertext verification failed")
|
||||||
// ErrNoKeyFound is returned when no key for the repository could be decrypted.
|
// ErrNoKeyFound is returned when no key for the repository could be decrypted.
|
||||||
ErrNoKeyFound = errors.New("no key could be found")
|
ErrNoKeyFound = errors.New("no key could be found")
|
||||||
|
// ErrBufferTooSmall is returned when the destination slice is too small
|
||||||
|
// for the ciphertext.
|
||||||
|
ErrBufferTooSmall = errors.New("destination buffer too small")
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: figure out scrypt values on the fly depending on the current
|
// TODO: figure out scrypt values on the fly depending on the current
|
||||||
@ -254,12 +257,12 @@ func (k *Key) newIV(buf []byte) error {
|
|||||||
// HMAC. Encrypt returns the ciphertext's length. For the hash function, SHA256
|
// HMAC. Encrypt returns the ciphertext's length. For the hash function, SHA256
|
||||||
// is used, so the overhead is 16+32=48 byte.
|
// is used, so the overhead is 16+32=48 byte.
|
||||||
func (k *Key) encrypt(ks *keys, ciphertext, plaintext []byte) (int, error) {
|
func (k *Key) encrypt(ks *keys, ciphertext, plaintext []byte) (int, error) {
|
||||||
if cap(ciphertext) < MaxCiphertextSize {
|
if cap(ciphertext) < maxCiphertextSize {
|
||||||
panic("encryption buffer is too small")
|
panic("encryption buffer is too small")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(plaintext) > maxDataSize {
|
if cap(ciphertext) < len(plaintext)+ivSize+hmacSize {
|
||||||
panic("plaintext is too large")
|
return 0, ErrBufferTooSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := io.ReadFull(rand.Reader, ciphertext[:ivSize])
|
_, err := io.ReadFull(rand.Reader, ciphertext[:ivSize])
|
||||||
|
@ -48,7 +48,7 @@ func TestCrypto(t *testing.T) {
|
|||||||
Sign: tv.skey,
|
Sign: tv.skey,
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := make([]byte, MaxCiphertextSize)
|
msg := make([]byte, maxCiphertextSize)
|
||||||
n, err := r.encrypt(r.master, msg, tv.plaintext)
|
n, err := r.encrypt(r.master, msg, tv.plaintext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
25
key_test.go
25
key_test.go
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/fd0/khepri"
|
"github.com/fd0/khepri"
|
||||||
"github.com/fd0/khepri/backend"
|
"github.com/fd0/khepri/backend"
|
||||||
|
"github.com/fd0/khepri/chunker"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testPassword = "foobar"
|
var testPassword = "foobar"
|
||||||
@ -72,6 +73,30 @@ func TestEncryptDecrypt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLargeEncrypt(t *testing.T) {
|
||||||
|
be := setupBackend(t)
|
||||||
|
defer teardownBackend(t, be)
|
||||||
|
k := setupKey(t, be, testPassword)
|
||||||
|
|
||||||
|
for _, size := range []int{chunker.MaxSize, chunker.MaxSize + 1} {
|
||||||
|
data := make([]byte, size)
|
||||||
|
f, err := os.Open("/dev/urandom")
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
_, err = io.ReadFull(f, data)
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
ciphertext := make([]byte, size+khepri.CiphertextExtension)
|
||||||
|
n, err := k.Encrypt(ciphertext, data)
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
plaintext, err := k.Decrypt(ciphertext[:n])
|
||||||
|
ok(t, err)
|
||||||
|
|
||||||
|
equals(t, plaintext, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkEncrypt(b *testing.B) {
|
func BenchmarkEncrypt(b *testing.B) {
|
||||||
size := 8 << 20 // 8MiB
|
size := 8 << 20 // 8MiB
|
||||||
data := make([]byte, size)
|
data := make([]byte, size)
|
||||||
|
2
pools.go
2
pools.go
@ -34,7 +34,7 @@ func newChunkBuf() interface{} {
|
|||||||
chunk_stats.m.Unlock()
|
chunk_stats.m.Unlock()
|
||||||
|
|
||||||
// create buffer for iv, data and hmac
|
// create buffer for iv, data and hmac
|
||||||
return make([]byte, MaxCiphertextSize)
|
return make([]byte, maxCiphertextSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNode() interface{} {
|
func newNode() interface{} {
|
||||||
|
Loading…
Reference in New Issue
Block a user