const commonSize … const keySizeCounterNonceGCM … // NewGCMTransformerWithUniqueKeyUnsafe is the same as NewGCMTransformer but is unsafe for general // use because it makes assumptions about the key underlying the block cipher. Specifically, // it uses a 96-bit nonce where the first 32 bits are random data and the remaining 64 bits are // a monotonically incrementing atomic counter. This means that the key must be randomly generated // on process startup and must never be used for encryption outside the lifetime of the process. // Unlike NewGCMTransformer, this function is immune to the birthday attack and thus the key can // be used for 2^64-1 writes without rotation. Furthermore, cryptographic wear out of AES-GCM with // a sequential nonce occurs after 2^64 encryptions, which is not a concern for our use cases. // Even if that occurs, the nonce counter would overflow and crash the process. We have no concerns // around plaintext length because all stored items are small (less than 2 MB). To prevent the // chance of the block cipher being accidentally re-used, it is not taken in as input. Instead, // a new random key is generated and returned on every invocation of this function. This key is // used as the input to the block cipher. If the key is stored and retrieved at a later point, // it can be passed to NewGCMTransformer(aes.NewCipher(key)) to construct a transformer capable // of decrypting values encrypted by this transformer (that transformer must not be used for encryption). func NewGCMTransformerWithUniqueKeyUnsafe() (value.Transformer, []byte, error) { … } func newGCMTransformerWithUniqueKeyUnsafe(block cipher.Block, nonceGen *nonceGenerator) (value.Transformer, error) { … } func randomNonce(b []byte) error { … } type nonceGenerator … func (n *nonceGenerator) next(b []byte) { … } func die(msg string) { … } // GenerateKey generates a random key using system randomness. func GenerateKey(length int) (key []byte, err error) { … } // NewGCMTransformer takes the given block cipher and performs encryption and decryption on the given data. // It implements AEAD encryption of the provided values given a cipher.Block algorithm. // The authenticated data provided as part of the value.Context method must match when the same // value is set to and loaded from storage. In order to ensure that values cannot be copied by // an attacker from a location under their control, use characteristics of the storage location // (such as the etcd key) as part of the authenticated data. // // Because this mode requires a generated IV and IV reuse is a known weakness of AES-GCM, keys // must be rotated before a birthday attack becomes feasible. NIST SP 800-38D // (http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf) recommends using the same // key with random 96-bit nonces (the default nonce length) no more than 2^32 times, and // therefore transformers using this implementation *must* ensure they allow for frequent key // rotation. Future work should include investigation of AES-GCM-SIV as an alternative to // random nonces. func NewGCMTransformer(block cipher.Block) (value.Transformer, error) { … } func newGCM(block cipher.Block) (cipher.AEAD, error) { … } type gcm … func (t *gcm) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) { … } func (t *gcm) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) { … } type cbc … // NewCBCTransformer takes the given block cipher and performs encryption and decryption on the given // data. func NewCBCTransformer(block cipher.Block) value.Transformer { … } var errInvalidBlockSize … var errInvalidPKCS7Data … var errInvalidPKCS7Padding … func (t *cbc) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) { … } func (t *cbc) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) { … }