From f76312ffe6073ddbedf89334f84f7798b0e240b7 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Wed, 19 Sep 2018 19:33:20 -0700 Subject: [PATCH] docs: Update secure-p2p doc to match the spec + current implementation Closes #2421. I am of the opinion that the spec is easier to read than this though, and we shouldn't really explain this here other than that we use a variant of station to station protocol, with X25519 for the diffie hellman, and we describe the related security properties. --- docs/tendermint-core/secure-p2p.md | 50 ++++++++++++++++-------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/docs/tendermint-core/secure-p2p.md b/docs/tendermint-core/secure-p2p.md index 01d2f22b..ee02f3f7 100644 --- a/docs/tendermint-core/secure-p2p.md +++ b/docs/tendermint-core/secure-p2p.md @@ -8,41 +8,43 @@ Each peer generates an ED25519 key-pair to use as a persistent (long-term) id. When two peers establish a TCP connection, they first each generate an -ephemeral ED25519 key-pair to use for this session, and send each other +ephemeral X25519 key-pair to use for this session, and send each other their respective ephemeral public keys. This happens in the clear. -They then each compute the shared secret. The shared secret is the -multiplication of the peer's ephemeral private key by the other peer's -ephemeral public key. The result is the same for both peers by the magic -of [elliptic -curves](https://en.wikipedia.org/wiki/Elliptic_curve_cryptography). The -shared secret is used as the symmetric key for the encryption algorithm. +They then each compute the shared secret, as done in a [diffie hellman +key exhange](https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange). +The shared secret is used as the symmetric key for the encryption algorithm. -The two ephemeral public keys are sorted to establish a canonical order. -Then a 24-byte nonce is generated by concatenating the public keys and -hashing them with Ripemd160. Note Ripemd160 produces 20byte hashes, so -the nonce ends with four 0s. +We then run [hkdf-sha256](https://en.wikipedia.org/wiki/HKDF) to expand the +shared secret to generate a symmetric key for sending data, +a symmetric key for receiving data, +a challenge to authenticate the other party. +One peer will send data with their sending key, and the other peer +would decode it using their own receiving key. +We must ensure that both parties don't try to use the same key as the sending +key, and the same key as the receiving key, as in that case nothing can be +decoded. +To ensure this, the peer with the canonically smaller ephemeral pubkey +uses the first key as their receiving key, and the second key as their sending key. +If the peer has the canonically larger ephemeral pubkey, they do the reverse. -The nonce is used to seed the encryption - it is critical that the same -nonce never be used twice with the same private key. For convenience, -the last bit of the nonce is flipped, giving us two nonces: one for -encrypting our own messages, one for decrypting our peer's. Which ever -peer has the higher public key uses the "bit-flipped" nonce for -encryption. +Each peer also keeps a received message counter and sent message counter, both +are initialized to zero. +All future communication is encrypted using chacha20poly1305. +The key used to send the message is the sending key, and the key used to decode +the message is the receiving key. +The nonce for chacha20poly1305 is the relevant message counter. +It is critical that the message counter is incremented every time you send a +message and every time you receive a message that decodes correctly. -Now, a challenge is generated by concatenating the ephemeral public keys -and taking the SHA256 hash. - -Each peer signs the challenge with their persistent private key, and +Each peer now signs the challenge with their persistent private key, and sends the other peer an AuthSigMsg, containing their persistent public key and the signature. On receiving an AuthSigMsg, the peer verifies the signature. The peers are now authenticated. -All future communications can now be encrypted using the shared secret -and the generated nonces, where each nonce is incremented by one each -time it is used. The communications maintain Perfect Forward Secrecy, as +The communication maintains Perfect Forward Secrecy, as the persistent key pair was not used for generating secrets - only for authenticating.