forked from TrueCloudLab/restic
Use large, dynamic buffer for encrypting maps
This commit is contained in:
parent
2d8dc7b695
commit
719e121c74
6 changed files with 48 additions and 10 deletions
|
@ -48,7 +48,7 @@ func BenchmarkChunkEncrypt(b *testing.B) {
|
|||
|
||||
ok(b, err)
|
||||
|
||||
buf := make([]byte, khepri.MaxCiphertextSize)
|
||||
buf := make([]byte, khepri.CiphertextExtension+chunker.MaxSize)
|
||||
_, err = key.Encrypt(buf, chunk_data.Data)
|
||||
ok(b, err)
|
||||
}
|
||||
|
|
|
@ -81,13 +81,23 @@ func (ch *ContentHandler) Save(t backend.Type, data []byte) (Blob, error) {
|
|||
Size: uint64(len(data)),
|
||||
}
|
||||
|
||||
var ciphertext []byte
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// encrypt blob
|
||||
ciphertext := GetChunkBuf("ch.Save()")
|
||||
defer FreeChunkBuf("ch.Save()", ciphertext)
|
||||
n, err := ch.key.Encrypt(ciphertext, data)
|
||||
if err != nil {
|
||||
return Blob{}, err
|
||||
}
|
||||
|
||||
ciphertext = ciphertext[:n]
|
||||
|
||||
// save blob
|
||||
|
|
13
key.go
13
key.go
|
@ -21,16 +21,19 @@ import (
|
|||
)
|
||||
|
||||
// max size is 8MiB, defined in chunker
|
||||
const maxDataSize = chunker.MaxSize
|
||||
const ivSize = aes.BlockSize
|
||||
const hmacSize = sha256.Size
|
||||
const MaxCiphertextSize = ivSize + maxDataSize + hmacSize
|
||||
const maxCiphertextSize = ivSize + chunker.MaxSize + hmacSize
|
||||
const CiphertextExtension = ivSize + hmacSize
|
||||
|
||||
var (
|
||||
// ErrUnauthenticated is returned when ciphertext verification has failed.
|
||||
ErrUnauthenticated = errors.New("ciphertext verification failed")
|
||||
// ErrNoKeyFound is returned when no key for the repository could be decrypted.
|
||||
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
|
||||
|
@ -254,12 +257,12 @@ func (k *Key) newIV(buf []byte) error {
|
|||
// HMAC. Encrypt returns the ciphertext's length. For the hash function, SHA256
|
||||
// is used, so the overhead is 16+32=48 byte.
|
||||
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")
|
||||
}
|
||||
|
||||
if len(plaintext) > maxDataSize {
|
||||
panic("plaintext is too large")
|
||||
if cap(ciphertext) < len(plaintext)+ivSize+hmacSize {
|
||||
return 0, ErrBufferTooSmall
|
||||
}
|
||||
|
||||
_, err := io.ReadFull(rand.Reader, ciphertext[:ivSize])
|
||||
|
|
|
@ -48,7 +48,7 @@ func TestCrypto(t *testing.T) {
|
|||
Sign: tv.skey,
|
||||
}
|
||||
|
||||
msg := make([]byte, MaxCiphertextSize)
|
||||
msg := make([]byte, maxCiphertextSize)
|
||||
n, err := r.encrypt(r.master, msg, tv.plaintext)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
25
key_test.go
25
key_test.go
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/fd0/khepri"
|
||||
"github.com/fd0/khepri/backend"
|
||||
"github.com/fd0/khepri/chunker"
|
||||
)
|
||||
|
||||
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) {
|
||||
size := 8 << 20 // 8MiB
|
||||
data := make([]byte, size)
|
||||
|
|
2
pools.go
2
pools.go
|
@ -34,7 +34,7 @@ func newChunkBuf() interface{} {
|
|||
chunk_stats.m.Unlock()
|
||||
|
||||
// create buffer for iv, data and hmac
|
||||
return make([]byte, MaxCiphertextSize)
|
||||
return make([]byte, maxCiphertextSize)
|
||||
}
|
||||
|
||||
func newNode() interface{} {
|
||||
|
|
Loading…
Reference in a new issue