storj/pkg/eestream/encryption.go
Maximillian von Briesen 821d0b6f1d
Stream encryption (#302)
* begin adding encryption for remote pieces

* begin adding decryption

* add encryption key as arg to Put and Get

* move encryption/decryption to object store

* Add encryption key to object store constructor

* Add the erasure scheme to object store constructor

* Ensure decrypter is initialized with the stripe size used by encrypter

* Revert "Ensure decrypter is initialized with the stripe size used by encrypter"

This reverts commit 07272333f461606edfb43ad106cc152f37a3bd46.

* Revert "Add the erasure scheme to object store constructor"

This reverts commit ea5e793b536159d993b96e3db69a37c1656a193c.

* move encryption to stream store

* move decryption stuff to stream store

* revert changes in object store

* add encryptedBlockSize and close rangers on error during Get

* calculate padding sizes correctly

* encryptedBlockSize -> encryptionBlockSize

* pass encryption key and block size into stream store

* remove encryption key and block size from object store constructor

* move encrypter/decrypter initialization

* remove unnecessary cast

* Fix padding issue

* Fix linter

* add todos

* use random encryption key for data encryption. Store an encrypted copy of this key in segment metadata

* use different encryption key for each segment

* encrypt data in one step if it is small enough

* refactor and move encryption stuff

* fix errors related to nil slices passed to copy

* fix encrypter vs. decrypter bug

* put encryption stuff in eestream

* get captplanet test to pass

* fix linting errors

* add types for encryption keys/nonces and clean up

* fix tests

* more review changes

* add Cipher type for encryption stuff

* fix rs_test

* Simplify type casting of key and nonce

* Init starting nonce to the segment index

* don't copy derived key

* remove default encryption key; force user to explicitly set it

* move getSegmentPath to streams package

* dont require user to specify encryption key for captplanet

* rename GenericKey and GenericNonce to Key and Nonce

* review changes

* fix linting error

* Download uses the encryption type from metadata

* Store enc block size in metadata and use it for download
2018-09-26 09:32:23 -04:00

122 lines
3.6 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package eestream
import (
"github.com/zeebo/errs"
)
// Cipher is a type used to define the type of encryption to use
type Cipher byte
// Constant definitions for no encryption (0), AESGCM (1), and SecretBox (2)
const (
None = Cipher(iota)
AESGCM
SecretBox
)
// Constant definitions for key and nonce sizes
const (
KeySize = 32
NonceSize = 24
AESGCMNonceSize = 12
)
// Key represents the largest key used by any encryption protocol
type Key [KeySize]byte
// Bytes returns the key as a byte array pointer
func (key *Key) Bytes() *[KeySize]byte {
return (*[KeySize]byte)(key)
}
// Nonce represents the largest nonce used by any encryption protocol
type Nonce [NonceSize]byte
// Bytes returns the nonce as a byte array pointer
func (nonce *Nonce) Bytes() *[NonceSize]byte {
return (*[NonceSize]byte)(nonce)
}
// Increment increments the nonce with the given amount
func (nonce *Nonce) Increment(amount int64) (truncated bool, err error) {
return incrementBytes(nonce.Bytes()[:], amount)
}
// AESGCMNonce returns the nonce as a AES-GCM nonce
func (nonce *Nonce) AESGCMNonce() *AESGCMNonce {
aes := new(AESGCMNonce)
copy((*aes)[:], (*nonce)[:AESGCMNonceSize])
return aes
}
// AESGCMNonce represents the nonce used by the AES-GCM protocol
type AESGCMNonce [AESGCMNonceSize]byte
// Bytes returns the nonce as a byte array pointer
func (nonce *AESGCMNonce) Bytes() *[AESGCMNonceSize]byte {
return (*[AESGCMNonceSize]byte)(nonce)
}
// Encrypt encrypts byte data with a key and nonce. The cipher data is returned
// The type of encryption to use can be modified with encType
func (cipher Cipher) Encrypt(data []byte, key *Key, nonce *Nonce) (cipherData []byte, err error) {
switch cipher {
case None:
return data, nil
case AESGCM:
return EncryptAESGCM(data, key[:], nonce[:AESGCMNonceSize])
case SecretBox:
return EncryptSecretBox(data, key, nonce)
default:
return nil, errs.New("Invalid encryption type")
}
}
// Decrypt decrypts byte data with a key and nonce. The plain data is returned
// The type of encryption to use can be modified with encType
func (cipher Cipher) Decrypt(cipherData []byte, key *Key, nonce *Nonce) (data []byte, err error) {
switch cipher {
case None:
return cipherData, nil
case AESGCM:
return DecryptAESGCM(cipherData, key[:], nonce[:AESGCMNonceSize])
case SecretBox:
return DecryptSecretBox(cipherData, key, nonce)
default:
return nil, errs.New("Invalid encryption type")
}
}
// NewEncrypter creates transform stream using a key and a nonce to encrypt data passing through it
// The type of encryption to use can be modified with encType
func (cipher Cipher) NewEncrypter(key *Key, startingNonce *Nonce, encBlockSize int) (Transformer, error) {
switch cipher {
case None:
return &NoopTransformer{}, nil
case AESGCM:
return NewAESGCMEncrypter(key, startingNonce.AESGCMNonce(), encBlockSize)
case SecretBox:
return NewSecretboxEncrypter(key, startingNonce, encBlockSize)
default:
return nil, errs.New("Invalid encryption type")
}
}
// NewDecrypter creates transform stream using a key and a nonce to decrypt data passing through it
// The type of encryption to use can be modified with encType
func (cipher Cipher) NewDecrypter(key *Key, startingNonce *Nonce, encBlockSize int) (Transformer, error) {
switch cipher {
case None:
return &NoopTransformer{}, nil
case AESGCM:
return NewAESGCMDecrypter(key, startingNonce.AESGCMNonce(), encBlockSize)
case SecretBox:
return NewSecretboxDecrypter(key, startingNonce, encBlockSize)
default:
return nil, errs.New("Invalid encryption type")
}
}