Encrypt metadata (#462)

This commit is contained in:
nfarah86 2018-10-17 04:34:50 -07:00 committed by Kaloyan Raev
parent 8fcec8b8cf
commit 92a8a825c4
4 changed files with 137 additions and 78 deletions

View File

@ -20,7 +20,7 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type SegmentMeta struct {
EncryptedKey []byte `protobuf:"bytes,1,opt,name=encrypted_key,json=encryptedKey,proto3" json:"encrypted_key,omitempty"`
EncryptedKeyNonce []byte `protobuf:"bytes,2,opt,name=encrypted_key_nonce,json=encryptedKeyNonce,proto3" json:"encrypted_key_nonce,omitempty"`
KeyNonce []byte `protobuf:"bytes,2,opt,name=key_nonce,json=keyNonce,proto3" json:"key_nonce,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -30,7 +30,7 @@ func (m *SegmentMeta) Reset() { *m = SegmentMeta{} }
func (m *SegmentMeta) String() string { return proto.CompactTextString(m) }
func (*SegmentMeta) ProtoMessage() {}
func (*SegmentMeta) Descriptor() ([]byte, []int) {
return fileDescriptor_meta_e57336c40e64ad60, []int{0}
return fileDescriptor_meta_7cdcbfdcc9c518d5, []int{0}
}
func (m *SegmentMeta) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_SegmentMeta.Unmarshal(m, b)
@ -57,9 +57,9 @@ func (m *SegmentMeta) GetEncryptedKey() []byte {
return nil
}
func (m *SegmentMeta) GetEncryptedKeyNonce() []byte {
func (m *SegmentMeta) GetKeyNonce() []byte {
if m != nil {
return m.EncryptedKeyNonce
return m.KeyNonce
}
return nil
}
@ -78,7 +78,7 @@ func (m *StreamInfo) Reset() { *m = StreamInfo{} }
func (m *StreamInfo) String() string { return proto.CompactTextString(m) }
func (*StreamInfo) ProtoMessage() {}
func (*StreamInfo) Descriptor() ([]byte, []int) {
return fileDescriptor_meta_e57336c40e64ad60, []int{1}
return fileDescriptor_meta_7cdcbfdcc9c518d5, []int{1}
}
func (m *StreamInfo) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StreamInfo.Unmarshal(m, b)
@ -140,7 +140,7 @@ func (m *StreamMeta) Reset() { *m = StreamMeta{} }
func (m *StreamMeta) String() string { return proto.CompactTextString(m) }
func (*StreamMeta) ProtoMessage() {}
func (*StreamMeta) Descriptor() ([]byte, []int) {
return fileDescriptor_meta_e57336c40e64ad60, []int{2}
return fileDescriptor_meta_7cdcbfdcc9c518d5, []int{2}
}
func (m *StreamMeta) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_StreamMeta.Unmarshal(m, b)
@ -194,28 +194,28 @@ func init() {
proto.RegisterType((*StreamMeta)(nil), "streams.StreamMeta")
}
func init() { proto.RegisterFile("meta.proto", fileDescriptor_meta_e57336c40e64ad60) }
func init() { proto.RegisterFile("meta.proto", fileDescriptor_meta_7cdcbfdcc9c518d5) }
var fileDescriptor_meta_e57336c40e64ad60 = []byte{
// 307 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0xcd, 0x4a, 0xfb, 0x40,
0x14, 0xc5, 0x49, 0xd3, 0xfe, 0xff, 0x72, 0x1b, 0xad, 0x1d, 0x15, 0x82, 0x2b, 0x89, 0x0b, 0x45,
0x24, 0x8b, 0xfa, 0x02, 0xd2, 0x9d, 0x88, 0x0a, 0x89, 0x2b, 0x37, 0xc3, 0x24, 0xbd, 0x91, 0xd0,
0x66, 0x26, 0x64, 0xc6, 0x45, 0xfa, 0x42, 0x3e, 0x96, 0xaf, 0x22, 0xf3, 0x91, 0x8f, 0xba, 0xcc,
0xb9, 0x87, 0x7b, 0x7f, 0xe7, 0x4c, 0x00, 0x2a, 0x54, 0x2c, 0xae, 0x1b, 0xa1, 0x04, 0xf9, 0x2f,
0x55, 0x83, 0xac, 0x92, 0x51, 0x06, 0xf3, 0x14, 0x3f, 0x2b, 0xe4, 0xea, 0x05, 0x15, 0x23, 0xd7,
0x70, 0x8c, 0x3c, 0x6f, 0xda, 0x5a, 0xe1, 0x86, 0x6e, 0xb1, 0x0d, 0xbd, 0x2b, 0xef, 0x36, 0x48,
0x82, 0x5e, 0x7c, 0xc6, 0x96, 0xc4, 0x70, 0x76, 0x60, 0xa2, 0x5c, 0xf0, 0x1c, 0xc3, 0x89, 0xb1,
0x2e, 0xc7, 0xd6, 0x57, 0x3d, 0x88, 0xbe, 0x3d, 0x80, 0xd4, 0xdc, 0x7b, 0xe2, 0x85, 0x20, 0xf7,
0x40, 0xf8, 0x57, 0x95, 0x61, 0x43, 0x45, 0x41, 0xa5, 0x3d, 0x2e, 0xcd, 0x21, 0x3f, 0x39, 0xb5,
0x93, 0xb7, 0xc2, 0x41, 0x49, 0x4d, 0xd4, 0x79, 0xa8, 0x2c, 0xf7, 0xf6, 0x8c, 0x9f, 0x04, 0x9d,
0x98, 0x96, 0x7b, 0x24, 0x77, 0xb0, 0xdc, 0x31, 0xa9, 0xba, 0x6d, 0xd6, 0xe8, 0x1b, 0xe3, 0x42,
0x0f, 0xdc, 0x36, 0xe3, 0xbd, 0x84, 0x23, 0x5d, 0xc4, 0x86, 0x29, 0x16, 0x4e, 0x0d, 0x72, 0xff,
0x1d, 0xfd, 0xf4, 0xa4, 0xa6, 0x8d, 0x15, 0x5c, 0x0c, 0x41, 0x6d, 0x63, 0xb4, 0xe4, 0x85, 0x70,
0xad, 0x0c, 0x2d, 0x8c, 0xd2, 0xdd, 0xc0, 0xc2, 0xc9, 0xa5, 0xe0, 0x54, 0xb5, 0xb5, 0x25, 0x9e,
0x25, 0x27, 0x83, 0xfc, 0xde, 0xd6, 0x38, 0x5a, 0xae, 0x8d, 0xd9, 0x4e, 0xe4, 0xdb, 0x81, 0x7b,
0xd6, 0x2f, 0x2f, 0x05, 0x5f, 0xeb, 0x99, 0x61, 0x7f, 0xfc, 0x93, 0x53, 0x83, 0x9b, 0x10, 0xf3,
0xd5, 0x79, 0xec, 0x9e, 0x34, 0x1e, 0xbd, 0xe7, 0x41, 0x7a, 0x2d, 0xac, 0xa7, 0x1f, 0x93, 0x3a,
0xcb, 0xfe, 0x99, 0xbf, 0xe0, 0xe1, 0x37, 0x00, 0x00, 0xff, 0xff, 0xf4, 0xf9, 0xab, 0xce, 0x13,
0x02, 0x00, 0x00,
var fileDescriptor_meta_7cdcbfdcc9c518d5 = []byte{
// 306 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x51, 0xcd, 0x4e, 0xf3, 0x30,
0x10, 0x54, 0xff, 0xbe, 0xaf, 0x6c, 0x03, 0x05, 0x03, 0x52, 0x04, 0x17, 0x14, 0x0e, 0x20, 0x84,
0x72, 0x28, 0x2f, 0x80, 0x7a, 0x43, 0x08, 0x2a, 0x25, 0x9c, 0xb8, 0x58, 0x4e, 0xba, 0x41, 0x51,
0x1a, 0x3b, 0x8a, 0xcd, 0xc1, 0x7d, 0x21, 0x1e, 0x8b, 0x57, 0x41, 0xb6, 0xf3, 0x07, 0xc7, 0x9d,
0x19, 0xcd, 0xce, 0xec, 0x02, 0x94, 0xa8, 0x58, 0x58, 0xd5, 0x42, 0x09, 0xf2, 0x5f, 0xaa, 0x1a,
0x59, 0x29, 0x83, 0x0d, 0x2c, 0x62, 0xfc, 0x28, 0x91, 0xab, 0x17, 0x54, 0x8c, 0x5c, 0xc3, 0x21,
0xf2, 0xb4, 0xd6, 0x95, 0xc2, 0x2d, 0x2d, 0x50, 0xfb, 0xa3, 0xab, 0xd1, 0xad, 0x17, 0x79, 0x1d,
0xf8, 0x8c, 0x9a, 0x5c, 0xc2, 0x41, 0x81, 0x9a, 0x72, 0xc1, 0x53, 0xf4, 0xc7, 0x56, 0x30, 0x2f,
0x50, 0xbf, 0x9a, 0x39, 0xf8, 0x1a, 0x01, 0xc4, 0xd6, 0xfc, 0x89, 0x67, 0x82, 0xdc, 0x03, 0xe1,
0x9f, 0x65, 0x82, 0x35, 0x15, 0x19, 0x95, 0x6e, 0x93, 0xb4, 0xae, 0x93, 0xe8, 0xd8, 0x31, 0x9b,
0xac, 0x49, 0x20, 0xcd, 0xfa, 0x56, 0x43, 0x65, 0xbe, 0x77, 0xee, 0x93, 0xc8, 0x6b, 0xc1, 0x38,
0xdf, 0x23, 0xb9, 0x83, 0x93, 0x1d, 0x93, 0xaa, 0x75, 0x73, 0xc2, 0x89, 0x15, 0x2e, 0x0d, 0xd1,
0xb8, 0x59, 0xed, 0x05, 0xcc, 0x4d, 0xeb, 0x2d, 0x53, 0xcc, 0x9f, 0xba, 0xa4, 0xed, 0x1c, 0x7c,
0x77, 0x49, 0x6d, 0xf5, 0x15, 0x9c, 0xf7, 0xd5, 0xdd, 0x79, 0x68, 0xce, 0x33, 0xd1, 0x9c, 0xe0,
0xb4, 0x23, 0x07, 0xed, 0x6e, 0x60, 0xd9, 0xc0, 0xb9, 0xe0, 0x54, 0xe9, 0xca, 0x25, 0x9e, 0x45,
0x47, 0x3d, 0xfc, 0xa6, 0x2b, 0x1c, 0x98, 0x1b, 0x61, 0xb2, 0x13, 0x69, 0xd1, 0xe7, 0x9e, 0x75,
0xe6, 0xb9, 0xe0, 0x6b, 0xc3, 0xd9, 0xec, 0x8f, 0x7f, 0x7a, 0x9a, 0xe0, 0xb6, 0xc4, 0x62, 0x75,
0x16, 0x36, 0xff, 0x0b, 0x07, 0xcf, 0xfb, 0xd5, 0xde, 0x00, 0xeb, 0xe9, 0xfb, 0xb8, 0x4a, 0x92,
0x7f, 0xf6, 0xe5, 0x0f, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x24, 0xc6, 0xa2, 0x54, 0x00, 0x02,
0x00, 0x00,
}

View File

@ -8,7 +8,7 @@ package streams;
message SegmentMeta {
bytes encrypted_key = 1;
bytes encrypted_key_nonce = 2;
bytes key_nonce = 2;
}
message StreamInfo {

View File

@ -38,15 +38,8 @@ type Meta struct {
// convertMeta converts segment metadata to stream metadata
func convertMeta(lastSegmentMeta segments.Meta) (Meta, error) {
streamMeta := pb.StreamMeta{}
err := proto.Unmarshal(lastSegmentMeta.Data, &streamMeta)
if err != nil {
return Meta{}, err
}
// TODO decrypt before unmarshalling
stream := pb.StreamInfo{}
err = proto.Unmarshal(streamMeta.EncryptedStreamInfo, &stream)
err := proto.Unmarshal(lastSegmentMeta.Data, &stream)
if err != nil {
return Meta{}, err
}
@ -104,7 +97,6 @@ func NewStreamStore(segments segments.Store, segmentSize int64, rootKey string,
// of segments, in a new protobuf, in the metadata of l/<path>.
func (s *streamStore) Put(ctx context.Context, path paths.Path, data io.Reader, metadata []byte, expiration time.Time) (m Meta, err error) {
defer mon.Task()(&ctx)(&err)
// previously file uploaded?
err = s.Delete(ctx, path)
if err != nil && !storage.ErrKeyNotFound.Has(err) {
@ -129,37 +121,40 @@ func (s *streamStore) Put(ctx context.Context, path paths.Path, data io.Reader,
if err != nil {
return Meta{}, err
}
cipher := s.encType
eofReader := NewEOFReader(data)
for !eofReader.isEOF() && !eofReader.hasError() {
var encKey eestream.Key
_, err = rand.Read(encKey[:])
// generate random key for encrypting the segment's content
var contentKey eestream.Key
_, err = rand.Read(contentKey[:])
if err != nil {
return Meta{}, err
}
var nonce eestream.Nonce
_, err := nonce.Increment(currentSegment)
// Initialize the content nonce with the segment's index incremented by 1.
// The increment by 1 is to avoid nonce reuse with the metadata encryption,
// which is encrypted with the zero nonce.
var contentNonce eestream.Nonce
_, err := contentNonce.Increment(currentSegment + 1)
if err != nil {
return Meta{}, err
}
encrypter, err := cipher.NewEncrypter(&encKey, &nonce, s.encBlockSize)
encrypter, err := cipher.NewEncrypter(&contentKey, &contentNonce, s.encBlockSize)
if err != nil {
return Meta{}, err
}
// generate random nonce for encrypting the encryption key
// generate random nonce for encrypting the content key
var keyNonce eestream.Nonce
_, err = rand.Read(keyNonce[:])
if err != nil {
return Meta{}, err
}
encryptedEncKey, err := cipher.Encrypt(encKey[:], (*eestream.Key)(derivedKey), &keyNonce)
encryptedKey, err := cipher.Encrypt(contentKey[:], (*eestream.Key)(derivedKey), &keyNonce)
if err != nil {
return Meta{}, err
}
@ -180,7 +175,7 @@ func (s *streamStore) Put(ctx context.Context, path paths.Path, data io.Reader,
if err != nil {
return Meta{}, err
}
cipherData, err := cipher.Encrypt(data, &encKey, &nonce)
cipherData, err := cipher.Encrypt(data, &contentKey, &contentNonce)
if err != nil {
return Meta{}, err
}
@ -201,8 +196,8 @@ func (s *streamStore) Put(ctx context.Context, path paths.Path, data io.Reader,
}
segmentMeta, err := proto.Marshal(&pb.SegmentMeta{
EncryptedKey: encryptedEncKey,
EncryptedKeyNonce: keyNonce[:],
EncryptedKey: encryptedKey,
KeyNonce: keyNonce[:],
})
if err != nil {
return nil, nil, err
@ -223,16 +218,22 @@ func (s *streamStore) Put(ctx context.Context, path paths.Path, data io.Reader,
return nil, nil, err
}
// encrypt metadata with the content encryption key and zero nonce
encryptedStreamInfo, err := cipher.Encrypt(streamInfo, &contentKey, &eestream.Nonce{})
if err != nil {
return nil, nil, err
}
streamMeta := pb.StreamMeta{
EncryptedStreamInfo: streamInfo, // TODO encrypt this
EncryptedStreamInfo: encryptedStreamInfo,
EncryptionType: int32(s.encType),
EncryptionBlockSize: int32(s.encBlockSize),
}
if cipher != eestream.None {
streamMeta.LastSegmentMeta = &pb.SegmentMeta{
EncryptedKey: encryptedEncKey,
EncryptedKeyNonce: keyNonce[:],
EncryptedKey: encryptedKey,
KeyNonce: keyNonce[:],
}
}
@ -250,6 +251,7 @@ func (s *streamStore) Put(ctx context.Context, path paths.Path, data io.Reader,
currentSegment++
streamSize += sizeReader.Size()
}
if eofReader.hasError() {
return Meta{}, eofReader.err
}
@ -285,15 +287,19 @@ func (s *streamStore) Get(ctx context.Context, path paths.Path) (rr ranger.Range
return nil, Meta{}, err
}
streamMeta := pb.StreamMeta{}
err = proto.Unmarshal(lastSegmentMeta.Data, &streamMeta)
streamInfo, err := decryptStreamInfo(ctx, lastSegmentMeta, path, s.rootKey)
if err != nil {
return nil, Meta{}, err
}
// TODO decrypt before umarshalling
stream := pb.StreamInfo{}
err = proto.Unmarshal(streamMeta.EncryptedStreamInfo, &stream)
err = proto.Unmarshal(streamInfo, &stream)
if err != nil {
return nil, Meta{}, err
}
streamMeta := pb.StreamMeta{}
err = proto.Unmarshal(lastSegmentMeta.Data, &streamMeta)
if err != nil {
return nil, Meta{}, err
}
@ -307,8 +313,8 @@ func (s *streamStore) Get(ctx context.Context, path paths.Path) (rr ranger.Range
for i := int64(0); i < stream.NumberOfSegments-1; i++ {
currentPath := getSegmentPath(encPath, i)
size := stream.SegmentsSize
var nonce eestream.Nonce
_, err := nonce.Increment(i)
var contentNonce eestream.Nonce
_, err := contentNonce.Increment(i + 1)
if err != nil {
return nil, Meta{}, err
}
@ -317,15 +323,15 @@ func (s *streamStore) Get(ctx context.Context, path paths.Path) (rr ranger.Range
path: currentPath,
size: size,
derivedKey: (*eestream.Key)(derivedKey),
startingNonce: &nonce,
startingNonce: &contentNonce,
encBlockSize: int(streamMeta.EncryptionBlockSize),
encType: eestream.Cipher(streamMeta.EncryptionType),
}
rangers = append(rangers, rr)
}
var nonce eestream.Nonce
_, err = nonce.Increment(stream.NumberOfSegments - 1)
var contentNonce eestream.Nonce
_, err = contentNonce.Increment(stream.NumberOfSegments)
if err != nil {
return nil, Meta{}, err
}
@ -338,7 +344,7 @@ func (s *streamStore) Get(ctx context.Context, path paths.Path) (rr ranger.Range
(*eestream.Key)(derivedKey),
encryptedKey,
keyNonce,
&nonce,
&contentNonce,
int(streamMeta.EncryptionBlockSize),
)
if err != nil {
@ -348,6 +354,7 @@ func (s *streamStore) Get(ctx context.Context, path paths.Path) (rr ranger.Range
catRangers := ranger.Concat(rangers...)
lastSegmentMeta.Data = streamInfo
meta, err = convertMeta(lastSegmentMeta)
if err != nil {
return nil, Meta{}, err
@ -370,12 +377,18 @@ func (s *streamStore) Meta(ctx context.Context, path paths.Path) (meta Meta, err
return Meta{}, err
}
streamMeta, err := convertMeta(lastSegmentMeta)
streamInfo, err := decryptStreamInfo(ctx, lastSegmentMeta, path, s.rootKey)
if err != nil {
return Meta{}, err
}
return streamMeta, nil
lastSegmentMeta.Data = streamInfo
newStreamMeta, err := convertMeta(lastSegmentMeta)
if err != nil {
return Meta{}, err
}
return newStreamMeta, nil
}
// Delete all the segments, with the last one last
@ -391,15 +404,13 @@ func (s *streamStore) Delete(ctx context.Context, path paths.Path) (err error) {
return err
}
streamMeta := pb.StreamMeta{}
err = proto.Unmarshal(lastSegmentMeta.Data, &streamMeta)
streamInfo, err := decryptStreamInfo(ctx, lastSegmentMeta, path, s.rootKey)
if err != nil {
return err
}
// TODO decrypt before unmarshalling
stream := pb.StreamInfo{}
err = proto.Unmarshal(streamMeta.EncryptedStreamInfo, &stream)
err = proto.Unmarshal(streamInfo, &stream)
if err != nil {
return err
}
@ -450,6 +461,7 @@ func (s *streamStore) List(ctx context.Context, prefix, startAfter, endBefore pa
if err != nil {
return nil, false, err
}
encEndBefore, err := s.encryptMarker(endBefore, prefixKey)
if err != nil {
return nil, false, err
@ -462,15 +474,23 @@ func (s *streamStore) List(ctx context.Context, prefix, startAfter, endBefore pa
items = make([]ListItem, len(segments))
for i, item := range segments {
path, err := s.decryptMarker(item.Path, prefixKey)
if err != nil {
return nil, false, err
}
streamInfo, err := decryptStreamInfo(ctx, item.Meta, path.Prepend(prefix...), s.rootKey)
if err != nil {
return nil, false, err
}
item.Meta.Data = streamInfo
newMeta, err := convertMeta(item.Meta)
if err != nil {
return nil, false, err
}
decPath, err := s.decryptMarker(item.Path, prefixKey)
if err != nil {
return nil, false, err
}
items[i] = ListItem{Path: decPath, Meta: newMeta, IsPrefix: item.IsPrefix}
items[i] = ListItem{Path: path, Meta: newMeta, IsPrefix: item.IsPrefix}
}
return items, more, nil
@ -622,7 +642,33 @@ func getEncryptedKeyAndNonce(m *pb.SegmentMeta) ([]byte, *eestream.Nonce) {
}
var nonce eestream.Nonce
copy(nonce[:], m.EncryptedKeyNonce)
copy(nonce[:], m.KeyNonce)
return m.EncryptedKey, &nonce
}
func decryptStreamInfo(ctx context.Context, item segments.Meta, path paths.Path, rootKey []byte) (streamInfo []byte, err error) {
streamMeta := pb.StreamMeta{}
err = proto.Unmarshal(item.Data, &streamMeta)
if err != nil {
return nil, err
}
derivedKey, err := path.DeriveContentKey(rootKey)
if err != nil {
return nil, err
}
cipher := eestream.Cipher(streamMeta.EncryptionType)
encryptedKey, keyNonce := getEncryptedKeyAndNonce(streamMeta.LastSegmentMeta)
e, err := cipher.Decrypt(encryptedKey, (*eestream.Key)(derivedKey), keyNonce)
if err != nil {
return nil, err
}
var contentKey eestream.Key
copy(contentKey[:], e)
// decrypt metadata with the content encryption key and zero nonce
return cipher.Decrypt(streamMeta.EncryptedStreamInfo, &contentKey, &eestream.Nonce{})
}

View File

@ -47,15 +47,28 @@ func TestStreamStoreMeta(t *testing.T) {
if err != nil {
t.Fatal(err)
}
staticTime := time.Now()
segmentMeta := segments.Meta{
Modified: staticTime,
Expiration: staticTime,
Size: 10,
Size: 50,
Data: lastSegmentMetadata,
}
streamMeta, err := convertMeta(segmentMeta)
streamMetaUnmarshaled := pb.StreamMeta{}
err = proto.Unmarshal(segmentMeta.Data, &streamMetaUnmarshaled)
if err != nil {
t.Fatal(err)
}
segmentMetaStreamInfo := segments.Meta{
Modified: staticTime,
Expiration: staticTime,
Size: 50,
Data: streamMetaUnmarshaled.EncryptedStreamInfo,
}
streamMeta, err := convertMeta(segmentMetaStreamInfo)
if err != nil {
t.Fatal(err)
}