diff --git a/docs/architecture/adr-015-symmetric-crypto.md b/docs/architecture/adr-015-symmetric-crypto.md new file mode 100644 index 000000000..e798f8492 --- /dev/null +++ b/docs/architecture/adr-015-symmetric-crypto.md @@ -0,0 +1,79 @@ +# ADR 015: Need for symmetric cryptography + +## Context + +We require symmetric ciphers to handle how we encrypt keys in the sdk, +and to potentially encrypt `priv_validator.json` in tendermint. + +Currently we use AEAD's to support symmetric encryption, +which is great since we want data integrity in addition to privacy and authenticity. +We don't currently have a scenario where we want to encrypt without data integrity, +so it is fine to optimize our code to just use AEAD's. +Currently there is not a way to switch out AEAD's easily, this ADR outlines a way +to easily swap these out. + +### How do we encrypt with AEAD's + +AEAD's typically require a nonce in addition to the key. +For the purposes we require symmetric cryptography for, +we need encryption to be stateless. +Because of this we use random nonces. +(Thus the AEAD must support random nonces) + +We currently construct a random nonce, and encrypt the data with it. +The returned value is `nonce || encrypted data`. +The limitation of this is that does not provide a way to identify +which algorithm was used in encryption. +Consequently decryption with multiple algoritms is sub-optimal. +(You have to try them all) + +## Decision + +We should create the following two methods in a new `crypto/encoding/symmetric` package: +```golang +func EncryptSymmetric(aead cipher.AEAD, plaintext []byte) (ciphertext []byte, err error) +func DecryptSymmetric(key []byte, ciphertext []byte) (plaintext []byte, err error) +func RegisterSymmetric(aead cipher.AEAD, algo_name string, NewAead func(key []byte) (cipher.Aead, error)) error +``` + +This allows you to specify the algorithm in encryption, but not have to specify +it in decryption. +This is intended for ease of use in downstream applications, in addition to people +looking at the file directly. +One downside is that for the encrypt function you must have already initialized an AEAD, +but I don't really see this as an issue. + +If there is no error in encryption, EncryptSymmetric will return `algo_name || nonce || aead_ciphertext`. +This requires a mapping from aead type to name. +We can achieve this via reflection. +```golang +func getType(myvar interface{}) string { + if t := reflect.TypeOf(myvar); t.Kind() == reflect.Ptr { + return "*" + t.Elem().Name() + } else { + return t.Name() + } +} +``` +Then we maintain a map from the name returned from `getType(aead)` to `algo_name`. + +In decryption, we read the `algo_name`, and then instantiate a new AEAD with the key. +Then we call the AEAD's decrypt method on the provided nonce/ciphertext. + +`RegisterSymmetric` allows a downstream user to add their own desired AEAD to the symmetric package. + +## Status + +Proposed. + +## Consequences + +### Positive +* Allows us to support new AEAD's, in a way that makes decryption easier +* Allows downstream users to add their own AEAD + +### Negative + +### Neutral +* Caller has to instantiate the AEAD with the private key. +However it forces them to be aware of what signing algorithm they are using, which is a positive. \ No newline at end of file