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) } }
// SaveJSONUnpacked serialises item as JSON and encrypts and saves it in the // backend as type t, without a pack. It returns the storage hash. func (s *Repository) SaveJSONUnpacked(t backend.Type, item interface{}) (backend.ID, error) { // create file blob, err := s.be.Create() if err != nil { return nil, err } debug.Log("Repo.SaveJSONUnpacked", "create new file %p", blob) // hash hw := backend.NewHashingWriter(blob, sha256.New()) // encrypt blob ewr := crypto.EncryptTo(s.key, hw) enc := json.NewEncoder(ewr) err = enc.Encode(item) if err != nil { return nil, fmt.Errorf("json.Encode: %v", err) } err = ewr.Close() if err != nil { return nil, err } // finalize blob in the backend sid := backend.ID(hw.Sum(nil)) err = blob.Finalize(t, sid.String()) if err != nil { return nil, err } return sid, nil }
func BenchmarkEncryptDecryptReader(b *testing.B) { k := crypto.NewRandomKey() 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 := crypto.EncryptTo(k, buf) _, err := io.Copy(wr, rd) OK(b, err) OK(b, wr.Close()) r, err := crypto.DecryptFrom(k, buf) OK(b, err) _, err = io.Copy(ioutil.Discard, r) OK(b, err) } }
// CreateEncryptedBlob returns a BlobWriter that encrypts and saves the data // written to it in the backend. After Close() was called, ID() returns the // backend.ID. func (r *Repository) CreateEncryptedBlob(t backend.Type) (*BlobWriter, error) { blob, err := r.be.Create() if err != nil { return nil, err } // hash hw := backend.NewHashingWriter(blob, sha256.New()) // encrypt blob ewr := crypto.EncryptTo(r.key, hw) return &BlobWriter{t: t, blob: blob, hw: hw, ewr: ewr}, nil }
func BenchmarkEncryptWriter(b *testing.B) { size := 8 << 20 // 8MiB k := crypto.NewRandomKey() b.ResetTimer() b.SetBytes(int64(size)) for i := 0; i < b.N; i++ { rd := RandomLimitReader(23, size) wr := crypto.EncryptTo(k, ioutil.Discard) n, err := io.Copy(wr, rd) OK(b, err) OK(b, wr.Close()) Assert(b, n == int64(size), "not enough bytes writter: want %d, got %d", size, n) } }
// SaveJSONUnpacked serialises item as JSON and encrypts and saves it in the // backend as type t, without a pack. It returns the storage hash. func (r *Repository) SaveJSONUnpacked(t backend.Type, item interface{}) (backend.ID, error) { // create file blob, err := r.be.Create() if err != nil { return backend.ID{}, err } debug.Log("Repo.SaveJSONUnpacked", "create new blob %v", t) // hash hw := backend.NewHashingWriter(blob, sha256.New()) // encrypt blob ewr := crypto.EncryptTo(r.key, hw) enc := json.NewEncoder(ewr) err = enc.Encode(item) if err != nil { return backend.ID{}, fmt.Errorf("json.Encode: %v", err) } err = ewr.Close() if err != nil { return backend.ID{}, err } // finalize blob in the backend hash := hw.Sum(nil) sid := backend.ID{} copy(sid[:], hash) err = blob.Finalize(t, sid.String()) if err != nil { debug.Log("Repo.SaveJSONUnpacked", "error saving blob %v as %v: %v", t, sid, err) return backend.ID{}, err } debug.Log("Repo.SaveJSONUnpacked", "new blob %v saved as %v", t, sid) return sid, nil }
// SaveIndex saves all new packs in the index in the backend, returned is the // storage ID. func (r *Repository) SaveIndex() (backend.ID, error) { debug.Log("Repo.SaveIndex", "Saving index") // create blob blob, err := r.be.Create() if err != nil { return backend.ID{}, err } debug.Log("Repo.SaveIndex", "create new pack %p", blob) // hash hw := backend.NewHashingWriter(blob, sha256.New()) // encrypt blob ewr := crypto.EncryptTo(r.key, hw) err = r.idx.Encode(ewr) if err != nil { return backend.ID{}, err } err = ewr.Close() if err != nil { return backend.ID{}, err } // finalize blob in the backend sid := backend.ID{} copy(sid[:], hw.Sum(nil)) err = blob.Finalize(backend.Index, sid.String()) if err != nil { return backend.ID{}, err } debug.Log("Repo.SaveIndex", "Saved index as %v", sid.Str()) return sid, nil }
// Finalize writes the header for all added blobs and finalizes the pack. // Returned are the complete number of bytes written, including the header. // After Finalize() has finished, the ID of this pack can be obtained by // calling ID(). func (p *Packer) Finalize() (bytesWritten uint, err error) { p.m.Lock() defer p.m.Unlock() bytesWritten = p.bytes // create writer to encrypt header wr := crypto.EncryptTo(p.k, p.hw) bytesHeader, err := p.writeHeader(wr) if err != nil { wr.Close() return bytesWritten + bytesHeader, err } bytesWritten += bytesHeader // finalize encrypted header err = wr.Close() if err != nil { return bytesWritten, err } // account for crypto overhead bytesWritten += crypto.Extension // write length err = binary.Write(p.hw, binary.LittleEndian, uint32(uint(len(p.blobs))*entrySize+crypto.Extension)) if err != nil { return bytesWritten, err } bytesWritten += uint(binary.Size(uint32(0))) p.bytes = uint(bytesWritten) return bytesWritten, nil }