encrypt: write encrypted blobs.

no meta or retrieval yet, though.

Change-Id: I9f3a53500ca6b96226fbcfe65e8278481618d3b0
This commit is contained in:
Brad Fitzpatrick 2013-06-15 15:42:37 -07:00
parent d12007af52
commit 8e3a432e53
1 changed files with 42 additions and 2 deletions

View File

@ -17,6 +17,10 @@ limitations under the License.
package encrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
@ -53,6 +57,8 @@ Option a)
type storage struct {
*blobserver.SimpleBlobHubPartitionMap
block cipher.Block
// Encryption key.
key []byte
@ -72,6 +78,18 @@ type storage struct {
meta blobserver.Storage
}
func (s *storage) randIV() []byte {
iv := make([]byte, s.block.BlockSize())
n, err := rand.Read(iv)
if err != nil {
panic(err)
}
if n != len(iv) {
panic("short read from crypto/rand")
}
return iv
}
func (s *storage) RemoveBlobs(blobs []*blobref.BlobRef) error {
panic("TODO: implement")
}
@ -81,7 +99,25 @@ func (s *storage) StatBlobs(dest chan<- blobref.SizedBlobRef, blobs []*blobref.B
}
func (s *storage) ReceiveBlob(b *blobref.BlobRef, source io.Reader) (sb blobref.SizedBlobRef, err error) {
panic("TODO: implement")
iv := s.randIV()
stream := cipher.NewCTR(s.block, iv)
var buf bytes.Buffer
buf.Write(iv) // TODO: write more structured header w/ version & IV length? or does that weaken it?
sw := cipher.StreamWriter{S: stream, W: &buf}
n, err := io.Copy(sw, source)
if err != nil {
return sb, err
}
if err := sw.Close(); err != nil {
return sb, err
}
// TODO: upload buf.Bytes() to s.blobs
// TODO: upload meta blob with two blobrefs & IV to s.meta
// TODO: update index with mapping
return blobref.SizedBlobRef{b, n}, nil
}
func (s *storage) FetchStreaming(b *blobref.BlobRef) (file io.ReadCloser, size int64, err error) {
@ -107,7 +143,7 @@ func newFromConfig(ld blobserver.Loader, config jsonconfig.Obj) (bs blobserver.S
case key != "":
sto.key, err = hex.DecodeString(key)
if err != nil || len(sto.key) != 16 {
return nil, fmt.Errorf("The 'key' parameter must be 16 bytes of 32 hex digits. (currently fixed at AES-128")
return nil, fmt.Errorf("The 'key' parameter must be 16 bytes of 32 hex digits. (currently fixed at AES-128)")
}
case keyFile != "":
// TODO: check that keyFile's unix permissions aren't too permissive.
@ -134,5 +170,9 @@ func newFromConfig(ld blobserver.Loader, config jsonconfig.Obj) (bs blobserver.S
// TODO: add a way to prompt from stdin on start? or keychain support?
return nil, errors.New("no encryption key set with 'key' or 'keyFile'")
}
sto.block, err = aes.NewCipher(sto.key)
if err != nil {
return nil, fmt.Errorf("The key must be exactly 16 bytes (currently only AES-128 is supported): %v", err)
}
return sto, nil
}