restic/key_test.go
Alexander Neumann af57fb86d7 Reduce memory usage of decryptReader
benchmark                         old ns/op     new ns/op     delta
    BenchmarkChunkEncrypt             260007360     261144414     +0.44%
    BenchmarkChunkEncryptParallel     262839697     261201438     -0.62%
    BenchmarkArchiveDirectory         0.00          0.00          +0.00%
    BenchmarkEncryptWriter            86994839      88297245      +1.50%
    BenchmarkEncrypt                  87414849      87406446      -0.01%
    BenchmarkDecryptReader            90354651      89948630      -0.45%
    BenchmarkEncryptDecryptReader     184533845     178374144     -3.34%
    BenchmarkDecrypt                  88153894      88289705      +0.15%
    BenchmarkSaveJSON                 213906        213917        +0.01%
    BenchmarkSaveFrom                 75263853      74881361      -0.51%

    benchmark                         old MB/s     new MB/s     speedup
    BenchmarkChunkEncrypt             40.33        40.15        1.00x
    BenchmarkChunkEncryptParallel     39.89        40.14        1.01x
    BenchmarkEncryptWriter            96.43        95.00        0.99x
    BenchmarkEncrypt                  95.96        95.97        1.00x
    BenchmarkDecryptReader            92.84        93.26        1.00x
    BenchmarkEncryptDecryptReader     45.46        47.03        1.03x
    BenchmarkDecrypt                  95.16        95.01        1.00x
    BenchmarkSaveFrom                 55.73        56.01        1.01x

    benchmark                         old allocs     new allocs     delta
    BenchmarkChunkEncrypt             113            113            +0.00%
    BenchmarkChunkEncryptParallel     104            104            +0.00%
    BenchmarkArchiveDirectory         0              0              +0.00%
    BenchmarkEncryptWriter            20             20             +0.00%
    BenchmarkEncrypt                  14             14             +0.00%
    BenchmarkDecryptReader            18             18             +0.00%
    BenchmarkEncryptDecryptReader     55             40             -27.27%
    BenchmarkDecrypt                  17             17             +0.00%
    BenchmarkSaveJSON                 125            125            +0.00%
    BenchmarkSaveFrom                 119            116            -2.52%

    benchmark                         old bytes     new bytes     delta
    BenchmarkChunkEncrypt             8515750       8515750       +0.00%
    BenchmarkChunkEncryptParallel     8515766       8515766       +0.00%
    BenchmarkArchiveDirectory         0             0             +0.00%
    BenchmarkEncryptWriter            28927         28927         +0.00%
    BenchmarkEncrypt                  422313        422313        +0.00%
    BenchmarkDecryptReader            527827        527827        +0.00%
    BenchmarkEncryptDecryptReader     35814894      4100824       -88.55%
    BenchmarkDecrypt                  8391127       8391127       +0.00%
    BenchmarkSaveJSON                 9208          9208          +0.00%
    BenchmarkSaveFrom                 40541         39694         -2.09%
2015-02-17 18:14:56 +01:00

352 lines
7.7 KiB
Go

package restic_test
import (
"bytes"
"flag"
"io"
"io/ioutil"
"os"
"testing"
"github.com/restic/restic"
"github.com/restic/restic/backend"
"github.com/restic/restic/chunker"
)
var testPassword = "foobar"
var testCleanup = flag.Bool("test.cleanup", true, "clean up after running tests (remove local backend directory with all content)")
var testLargeCrypto = flag.Bool("test.largecrypto", false, "also test crypto functions with large payloads")
func setupBackend(t testing.TB) restic.Server {
tempdir, err := ioutil.TempDir("", "restic-test-")
ok(t, err)
b, err := backend.CreateLocal(tempdir)
ok(t, err)
return restic.NewServer(b)
}
func teardownBackend(t testing.TB, s restic.Server) {
if !*testCleanup {
l := s.Backend().(*backend.Local)
t.Logf("leaving local backend at %s\n", l.Location())
return
}
ok(t, s.Delete())
}
func setupKey(t testing.TB, s restic.Server, password string) *restic.Key {
k, err := restic.CreateKey(s, password)
ok(t, err)
return k
}
func TestRepo(t *testing.T) {
s := setupBackend(t)
defer teardownBackend(t, s)
_ = setupKey(t, s, testPassword)
}
func TestEncryptDecrypt(t *testing.T) {
s := setupBackend(t)
defer teardownBackend(t, s)
k := setupKey(t, s, testPassword)
tests := []int{5, 23, 2<<18 + 23, 1 << 20}
if *testLargeCrypto {
tests = append(tests, 7<<20+123)
}
for _, size := range tests {
data := make([]byte, size)
_, err := io.ReadFull(randomReader(42, size), data)
ok(t, err)
ciphertext := restic.GetChunkBuf("TestEncryptDecrypt")
n, err := k.Encrypt(ciphertext, data)
ok(t, err)
plaintext, err := k.Decrypt(ciphertext[:n])
ok(t, err)
restic.FreeChunkBuf("TestEncryptDecrypt", ciphertext)
equals(t, plaintext, data)
}
}
func TestSmallBuffer(t *testing.T) {
s := setupBackend(t)
defer teardownBackend(t, s)
k := setupKey(t, s, testPassword)
size := 600
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/2)
_, err = k.Encrypt(ciphertext, data)
// this must throw an error, since the target slice is too small
assert(t, err != nil && err == restic.ErrBufferTooSmall,
"expected restic.ErrBufferTooSmall, got %#v", err)
}
func TestLargeEncrypt(t *testing.T) {
if !*testLargeCrypto {
t.SkipNow()
}
s := setupBackend(t)
defer teardownBackend(t, s)
k := setupKey(t, s, testPassword)
for _, size := range []int{chunker.MaxSize, chunker.MaxSize + 1, chunker.MaxSize + 1<<20} {
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+restic.CiphertextExtension)
n, err := k.Encrypt(ciphertext, data)
ok(t, err)
plaintext, err := k.Decrypt(ciphertext[:n])
ok(t, err)
equals(t, plaintext, data)
}
}
func BenchmarkEncryptWriter(b *testing.B) {
size := 8 << 20 // 8MiB
rd := randomReader(23, size)
be := setupBackend(b)
defer teardownBackend(b, be)
k := setupKey(b, be, testPassword)
b.ResetTimer()
b.SetBytes(int64(size))
for i := 0; i < b.N; i++ {
rd.Seek(0, 0)
wr := k.EncryptTo(ioutil.Discard)
_, err := io.Copy(wr, rd)
ok(b, err)
}
}
func BenchmarkEncrypt(b *testing.B) {
size := 8 << 20 // 8MiB
data := make([]byte, size)
be := setupBackend(b)
defer teardownBackend(b, be)
k := setupKey(b, be, testPassword)
b.ResetTimer()
b.SetBytes(int64(size))
buf := make([]byte, len(data)+restic.CiphertextExtension)
for i := 0; i < b.N; i++ {
_, err := k.Encrypt(buf, data)
ok(b, err)
}
}
func BenchmarkDecryptReader(b *testing.B) {
be := setupBackend(b)
defer teardownBackend(b, be)
k := setupKey(b, be, testPassword)
size := 8 << 20 // 8MiB
buf := get_random(23, size)
ciphertext := make([]byte, len(buf)+restic.CiphertextExtension)
_, err := k.Encrypt(ciphertext, buf)
ok(b, err)
rd := bytes.NewReader(ciphertext)
b.ResetTimer()
b.SetBytes(int64(size))
for i := 0; i < b.N; i++ {
rd.Seek(0, 0)
decRd, err := k.DecryptFrom(rd)
ok(b, err)
_, err = io.Copy(ioutil.Discard, decRd)
ok(b, err)
}
}
func BenchmarkEncryptDecryptReader(b *testing.B) {
be := setupBackend(b)
defer teardownBackend(b, be)
k := setupKey(b, be, testPassword)
size := 8 << 20 // 8MiB
rd := randomReader(23, size)
b.ResetTimer()
b.SetBytes(int64(size))
buf := bytes.NewBuffer(nil)
for i := 0; i < b.N; i++ {
rd.Seek(0, 0)
buf.Reset()
wr := k.EncryptTo(buf)
_, err := io.Copy(wr, rd)
ok(b, err)
ok(b, wr.Close())
r, err := k.DecryptFrom(buf)
ok(b, err)
_, err = io.Copy(ioutil.Discard, r)
ok(b, err)
}
}
func BenchmarkDecrypt(b *testing.B) {
size := 8 << 20 // 8MiB
data := make([]byte, size)
s := setupBackend(b)
defer teardownBackend(b, s)
k := setupKey(b, s, testPassword)
ciphertext := restic.GetChunkBuf("BenchmarkDecrypt")
n, err := k.Encrypt(ciphertext, data)
ok(b, err)
b.ResetTimer()
b.SetBytes(int64(size))
for i := 0; i < b.N; i++ {
_, err := k.Decrypt(ciphertext[:n])
ok(b, err)
}
restic.FreeChunkBuf("BenchmarkDecrypt", ciphertext)
}
func TestEncryptStreamWriter(t *testing.T) {
s := setupBackend(t)
defer teardownBackend(t, s)
k := setupKey(t, s, testPassword)
tests := []int{5, 23, 2<<18 + 23, 1 << 20}
if *testLargeCrypto {
tests = append(tests, 7<<20+123)
}
for _, size := range tests {
data := make([]byte, size)
_, err := io.ReadFull(randomReader(42, size), data)
ok(t, err)
ciphertext := bytes.NewBuffer(nil)
wr := k.EncryptTo(ciphertext)
_, err = io.Copy(wr, bytes.NewReader(data))
ok(t, err)
ok(t, wr.Close())
l := len(data) + restic.CiphertextExtension
assert(t, len(ciphertext.Bytes()) == l,
"wrong ciphertext length: expected %d, got %d",
l, len(ciphertext.Bytes()))
// decrypt with default function
plaintext, err := k.Decrypt(ciphertext.Bytes())
ok(t, err)
assert(t, bytes.Equal(data, plaintext),
"wrong plaintext after decryption: expected %02x, got %02x",
data, plaintext)
}
}
func TestDecryptStreamReader(t *testing.T) {
s := setupBackend(t)
defer teardownBackend(t, s)
k := setupKey(t, s, testPassword)
tests := []int{5, 23, 2<<18 + 23, 1 << 20}
if *testLargeCrypto {
tests = append(tests, 7<<20+123)
}
for _, size := range tests {
data := make([]byte, size)
_, err := io.ReadFull(randomReader(42, size), data)
ok(t, err)
ciphertext := make([]byte, size+restic.CiphertextExtension)
// encrypt with default function
n, err := k.Encrypt(ciphertext, data)
ok(t, err)
assert(t, n == len(data)+restic.CiphertextExtension,
"wrong number of bytes returned after encryption: expected %d, got %d",
len(data)+restic.CiphertextExtension, n)
rd, err := k.DecryptFrom(bytes.NewReader(ciphertext))
ok(t, err)
plaintext, err := ioutil.ReadAll(rd)
ok(t, err)
assert(t, bytes.Equal(data, plaintext),
"wrong plaintext after decryption: expected %02x, got %02x",
data, plaintext)
}
}
func TestEncryptWriter(t *testing.T) {
s := setupBackend(t)
defer teardownBackend(t, s)
k := setupKey(t, s, testPassword)
tests := []int{5, 23, 2<<18 + 23, 1 << 20}
if *testLargeCrypto {
tests = append(tests, 7<<20+123)
}
for _, size := range tests {
data := make([]byte, size)
_, err := io.ReadFull(randomReader(42, size), data)
ok(t, err)
buf := bytes.NewBuffer(nil)
wr := k.EncryptTo(buf)
_, err = io.Copy(wr, bytes.NewReader(data))
ok(t, err)
ok(t, wr.Close())
ciphertext := buf.Bytes()
l := len(data) + restic.CiphertextExtension
assert(t, len(ciphertext) == l,
"wrong ciphertext length: expected %d, got %d",
l, len(ciphertext))
// decrypt with default function
plaintext, err := k.Decrypt(ciphertext)
ok(t, err)
assert(t, bytes.Equal(data, plaintext),
"wrong plaintext after decryption: expected %02x, got %02x",
data, plaintext)
}
}