Use large, dynamic buffer for encrypting maps

This commit is contained in:
Alexander Neumann 2014-11-23 22:58:28 +01:00
parent 2d8dc7b695
commit 719e121c74
6 changed files with 48 additions and 10 deletions

View file

@ -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)
}

View file

@ -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
View file

@ -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])

View file

@ -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)

View file

@ -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)

View file

@ -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{} {