mirror of https://github.com/perkeep/perkeep.git
encrypt: more paranoia in FetchStreaming
Change-Id: Ie072a56015eb8a921328eccc6684647d2a153df3
This commit is contained in:
parent
3176c5be43
commit
1fddf9579a
|
@ -166,34 +166,53 @@ func (s *storage) ReceiveBlob(plainBR *blobref.BlobRef, source io.Reader) (sb bl
|
||||||
return blobref.SizedBlobRef{plainBR, plainSize}, nil
|
return blobref.SizedBlobRef{plainBR, plainSize}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) FetchStreaming(b *blobref.BlobRef) (file io.ReadCloser, size int64, err error) {
|
func (s *storage) FetchStreaming(plainBR *blobref.BlobRef) (file io.ReadCloser, size int64, err error) {
|
||||||
meta, err := s.fetchMeta(b)
|
meta, err := s.fetchMeta(plainBR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
rc, _, err := s.blobs.FetchStreaming(meta.EncBlobRef)
|
encData, _, err := s.blobs.FetchStreaming(meta.EncBlobRef)
|
||||||
if err != nil {
|
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
|
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))
|
blobIV := make([]byte, len(meta.IV))
|
||||||
_, err = io.ReadFull(rc, blobIV)
|
_, err = io.ReadFull(encData, blobIV)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, fmt.Errorf("Error reading off IV header from blob: %v", err)
|
return nil, 0, fmt.Errorf("Error reading off IV header from blob: %v", err)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(blobIV, meta.IV) {
|
if !bytes.Equal(blobIV, meta.IV) {
|
||||||
return nil, 0, fmt.Errorf("Blob and meta IV don't match")
|
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 {
|
return struct {
|
||||||
io.Reader
|
*bytes.Reader
|
||||||
io.Closer
|
io.Closer
|
||||||
}{
|
}{
|
||||||
Closer: rc,
|
bytes.NewReader(plain.Bytes()),
|
||||||
Reader: cipher.StreamReader{
|
dummyCloser,
|
||||||
S: cipher.NewCTR(s.block, meta.IV),
|
}, plainSize, nil
|
||||||
R: rc,
|
|
||||||
},
|
|
||||||
}, meta.PlainSize, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *storage) EnumerateBlobs(dest chan<- blobref.SizedBlobRef, after string, limit int, wait time.Duration) error {
|
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
|
return mv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dummyCloser io.Closer = ioutil.NopCloser(nil)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
blobserver.RegisterStorageConstructor("encrypt", blobserver.StorageConstructor(newFromConfig))
|
blobserver.RegisterStorageConstructor("encrypt", blobserver.StorageConstructor(newFromConfig))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue