func TestEncryptWriter(t *testing.T) { k := crypto.NewRandomKey() 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 := crypto.EncryptTo(k, buf) _, err = io.Copy(wr, bytes.NewReader(data)) OK(t, err) OK(t, wr.Close()) ciphertext := buf.Bytes() l := len(data) + crypto.Extension Assert(t, len(ciphertext) == l, "wrong ciphertext length: expected %d, got %d", l, len(ciphertext)) // decrypt with default function plaintext, err := crypto.Decrypt(k, []byte{}, ciphertext) OK(t, err) Assert(t, bytes.Equal(data, plaintext), "wrong plaintext after decryption: expected %02x, got %02x", data, plaintext) } }
func TestEncryptDecrypt(t *testing.T) { k := crypto.NewRandomKey() 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 := make([]byte, size+crypto.Extension) ciphertext, err := crypto.Encrypt(k, buf, data) OK(t, err) Assert(t, len(ciphertext) == len(data)+crypto.Extension, "ciphertext length does not match: want %d, got %d", len(data)+crypto.Extension, len(ciphertext)) plaintext, err := crypto.Decrypt(k, nil, ciphertext) OK(t, err) Assert(t, len(plaintext) == len(data), "plaintext length does not match: want %d, got %d", len(data), len(plaintext)) Equals(t, plaintext, data) } }
// decrypt authenticates and decrypts ciphertext and stores the result in // plaintext. func (r *Repository) decryptTo(plaintext, ciphertext []byte) ([]byte, error) { if r.key == nil { return nil, errors.New("key for repository not set") } return crypto.Decrypt(r.key, nil, ciphertext) }
func (s *Repository) Decrypt(ciphertext []byte) ([]byte, error) { if s.key == nil { return nil, errors.New("key for repository not set") } return crypto.Decrypt(s.key, nil, ciphertext) }
// checkPack reads a pack and checks the integrity of all blobs. func checkPack(r *repository.Repository, id backend.ID) error { debug.Log("Checker.checkPack", "checking pack %v", id.Str()) rd, err := r.Backend().Get(backend.Data, id.String()) if err != nil { return err } buf, err := ioutil.ReadAll(rd) if err != nil { return err } err = rd.Close() if err != nil { return err } unpacker, err := pack.NewUnpacker(r.Key(), bytes.NewReader(buf)) if err != nil { return err } var errs []error for i, blob := range unpacker.Entries { debug.Log("Checker.checkPack", " check blob %d: %v", i, blob.ID.Str()) plainBuf := make([]byte, blob.Length) plainBuf, err = crypto.Decrypt(r.Key(), plainBuf, buf[blob.Offset:blob.Offset+blob.Length]) if err != nil { debug.Log("Checker.checkPack", " error decrypting blob %v: %v", blob.ID.Str(), err) errs = append(errs, fmt.Errorf("blob %v: %v", i, err)) continue } hash := backend.Hash(plainBuf) if !hash.Equal(blob.ID) { debug.Log("Checker.checkPack", " ID does not match, want %v, got %v", blob.ID.Str(), hash.Str()) errs = append(errs, fmt.Errorf("ID does not match, want %v, got %v", blob.ID.Str(), hash.Str())) continue } } if len(errs) > 0 { return fmt.Errorf("pack %v contains %v errors: %v", id.Str(), len(errs), errs) } return nil }
func TestSameBuffer(t *testing.T) { k := crypto.NewRandomKey() size := 600 data := make([]byte, size) _, err := io.ReadFull(rand.Reader, data) OK(t, err) ciphertext := make([]byte, 0, size+crypto.Extension) ciphertext, err = crypto.Encrypt(k, ciphertext, data) OK(t, err) // use the same buffer for decryption ciphertext, err = crypto.Decrypt(k, ciphertext, ciphertext) OK(t, err) Assert(t, bytes.Equal(ciphertext, data), "wrong plaintext returned") }
func BenchmarkDecrypt(b *testing.B) { size := 8 << 20 // 8MiB data := make([]byte, size) k := crypto.NewRandomKey() plaintext := make([]byte, size) ciphertext := make([]byte, size+crypto.Extension) ciphertext, err := crypto.Encrypt(k, ciphertext, data) OK(b, err) b.ResetTimer() b.SetBytes(int64(size)) for i := 0; i < b.N; i++ { plaintext, err = crypto.Decrypt(k, plaintext, ciphertext) OK(b, err) } }
func TestCornerCases(t *testing.T) { k := crypto.NewRandomKey() // nil plaintext should encrypt to the empty string // nil ciphertext should allocate a new slice for the ciphertext c, err := crypto.Encrypt(k, nil, nil) OK(t, err) Assert(t, len(c) == crypto.Extension, "wrong length returned for ciphertext, expected 0, got %d", len(c)) // this should decrypt to nil p, err := crypto.Decrypt(k, nil, c) OK(t, err) Equals(t, []byte(nil), p) // test encryption for same slice, this should return an error _, err = crypto.Encrypt(k, c, c) Equals(t, crypto.ErrInvalidCiphertext, err) }
func TestSmallBuffer(t *testing.T) { k := crypto.NewRandomKey() size := 600 data := make([]byte, size) _, err := io.ReadFull(rand.Reader, data) OK(t, err) ciphertext := make([]byte, size/2) ciphertext, err = crypto.Encrypt(k, ciphertext, data) // this must extend the slice Assert(t, cap(ciphertext) > size/2, "expected extended slice, but capacity is only %d bytes", cap(ciphertext)) // check for the correct plaintext plaintext, err := crypto.Decrypt(k, nil, ciphertext) OK(t, err) Assert(t, bytes.Equal(plaintext, data), "wrong plaintext returned") }
func TestLargeEncrypt(t *testing.T) { if !testLargeCrypto { t.SkipNow() } k := crypto.NewRandomKey() for _, size := range []int{chunker.MaxSize, chunker.MaxSize + 1, chunker.MaxSize + 1<<20} { data := make([]byte, size) _, err := io.ReadFull(rand.Reader, data) OK(t, err) ciphertext, err := crypto.Encrypt(k, make([]byte, size+crypto.Extension), data) OK(t, err) plaintext, err := crypto.Decrypt(k, []byte{}, ciphertext) OK(t, err) Equals(t, plaintext, data) } }
// OpenKey tries do decrypt the key specified by name with the given password. func OpenKey(s *Repository, name string, password string) (*Key, error) { k, err := LoadKey(s, name) if err != nil { debug.Log("OpenKey", "LoadKey(%v) returned error %v", name[:12], err) return nil, err } // check KDF if k.KDF != "scrypt" { return nil, errors.New("only supported KDF is scrypt()") } // derive user key k.user, err = crypto.KDF(k.N, k.R, k.P, k.Salt, password) if err != nil { return nil, err } // decrypt master keys buf, err := crypto.Decrypt(k.user, []byte{}, k.Data) if err != nil { return nil, err } // restore json k.master = &crypto.Key{} err = json.Unmarshal(buf, k.master) if err != nil { debug.Log("OpenKey", "Unmarshal() returned error %v", err) return nil, err } k.name = name if !k.Valid() { return nil, errors.New("Invalid key for repository") } return k, nil }