encrypt: more paranoia in FetchStreaming

Change-Id: Ie072a56015eb8a921328eccc6684647d2a153df3
This commit is contained in:
Brad Fitzpatrick 2013-06-15 20:37:33 -07:00
parent 3176c5be43
commit 1fddf9579a
1 changed files with 33 additions and 12 deletions

View File

@ -166,34 +166,53 @@ func (s *storage) ReceiveBlob(plainBR *blobref.BlobRef, source io.Reader) (sb bl
return blobref.SizedBlobRef{plainBR, plainSize}, nil
}
func (s *storage) FetchStreaming(b *blobref.BlobRef) (file io.ReadCloser, size int64, err error) {
meta, err := s.fetchMeta(b)
func (s *storage) FetchStreaming(plainBR *blobref.BlobRef) (file io.ReadCloser, size int64, err error) {
meta, err := s.fetchMeta(plainBR)
if err != nil {
return nil, 0, err
}
rc, _, err := s.blobs.FetchStreaming(meta.EncBlobRef)
encData, _, err := s.blobs.FetchStreaming(meta.EncBlobRef)
if err != nil {
log.Printf("encrypt: plaintext %s's encrypted %v blob not found", b, meta.EncBlobRef)
log.Printf("encrypt: plaintext %s's encrypted %v blob not found", plainBR, meta.EncBlobRef)
return
}
defer encData.Close()
// Quick sanity check that the blob begins with the same IV we
// have in our metadata.
blobIV := make([]byte, len(meta.IV))
_, err = io.ReadFull(rc, blobIV)
_, err = io.ReadFull(encData, blobIV)
if err != nil {
return nil, 0, fmt.Errorf("Error reading off IV header from blob: %v", err)
}
if !bytes.Equal(blobIV, meta.IV) {
return nil, 0, fmt.Errorf("Blob and meta IV don't match")
}
// Slurp the whole blob into memory to validate its plaintext
// checksum (no tampered bits) before returning it. Clients
// should be the party doing this in the general case, but
// we'll be extra paranoid and always do it here, at the cost
// of sometimes having it be done twice.
var plain bytes.Buffer
plainHash := plainBR.Hash()
plainSize, err := io.Copy(io.MultiWriter(&plain, plainHash), cipher.StreamReader{
S: cipher.NewCTR(s.block, meta.IV),
R: encData,
})
if err != nil {
return nil, 0, err
}
if !plainBR.HashMatches(plainHash) {
return nil, 0, blobserver.ErrCorruptBlob
}
return struct {
io.Reader
*bytes.Reader
io.Closer
}{
Closer: rc,
Reader: cipher.StreamReader{
S: cipher.NewCTR(s.block, meta.IV),
R: rc,
},
}, meta.PlainSize, nil
bytes.NewReader(plain.Bytes()),
dummyCloser,
}, plainSize, nil
}
func (s *storage) EnumerateBlobs(dest chan<- blobref.SizedBlobRef, after string, limit int, wait time.Duration) error {
@ -284,6 +303,8 @@ func parseMetaValue(v string) (mv *metaValue, err error) {
return mv, nil
}
var dummyCloser io.Closer = ioutil.NopCloser(nil)
func init() {
blobserver.RegisterStorageConstructor("encrypt", blobserver.StorageConstructor(newFromConfig))
}