const cacheTTL … const derivedKeySizeExtendedNonceGCM … const infoSizeExtendedNonceGCM … const MinSeedSizeExtendedNonceGCM … // NewHKDFExtendedNonceGCMTransformer is the same as NewGCMTransformer but trades storage, // memory and CPU to work around the limitations of AES-GCM's 12 byte nonce size. The input seed // is assumed to be a cryptographically strong slice of MinSeedSizeExtendedNonceGCM+ random bytes. // Unlike NewGCMTransformer, this function is immune to the birthday attack because a new key is generated // per encryption via a key derivation function: KDF(seed, random_bytes) -> key. The derived key is // only used once as an AES-GCM key with a random 12 byte nonce. This avoids any concerns around // cryptographic wear out (by either number of encryptions or the amount of data being encrypted). // Speaking on the cryptographic safety, the limit on the number of operations that can be preformed // with a single seed with derived keys and randomly generated nonces is not practically reachable. // Thus, the scheme does not impose any specific requirements on the seed rotation schedule. // Reusing the same seed is safe to do over time and across process restarts. Whenever a new // seed is needed, the caller should generate it via GenerateKey(MinSeedSizeExtendedNonceGCM). // In regard to KMSv2, organization standards or compliance policies around rotation may require // that the seed be rotated at some interval. This can be implemented externally by rotating // the key encryption key via a key ID change. func NewHKDFExtendedNonceGCMTransformer(seed []byte) (value.Transformer, error) { … } type extendedNonceGCM … func (e *extendedNonceGCM) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) { … } func (e *extendedNonceGCM) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) { … } func (e *extendedNonceGCM) derivedKeyTransformer(info []byte, dataCtx value.Context, write bool) (value.Transformer, error) { … } func (e *extendedNonceGCM) sha256KDFExpandOnly(info []byte) ([]byte, error) { … } func newGCMTransformerWithInfo(key, info []byte) (*transformerWithInfo, error) { … } type transformerWithInfo … func (t *transformerWithInfo) TransformFromStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, bool, error) { … } func (t *transformerWithInfo) TransformToStorage(ctx context.Context, data []byte, dataCtx value.Context) ([]byte, error) { … }