specifications/network/noise.md
Communication between DiemNet peers are encrypted and authenticated via the Noise protocol framework. This specification documents how we make use of Noise to encrypt communications in three types of network:
The Noise protocol is "pre-negotiated" in peers' advertised or configured NetworkAddresses. Canonical DiemNet addresses will include the following Protocol after the base transport Protocols:
human-readable format: "/ln-noise-ik/<x25519-public-key>"
where <x25519-public-key> is the advertising peer's remote static public key in Noise terminology.
For context, we use the following functions defined in the noise specification:
Initialize(handshake_pattern, initiator, prologue, s, e, rs, re)WriteMessage(payload, message_buffer)ReadMessage(message, payload_buffer)EncryptWithAd(ad, plaintext)DecryptWithAd(ad, ciphertext)Specifically, we use the noise IK handshake pattern:
IK:
<- s
...
-> e, es, s, ss
<- e, ee, se
This handshake pattern is a one-round trip protocol where:
The protocol has been formally verified in noiseexplorer.
We also use Noise with:
The following constants are known to an implementation:
PROTOCOL_NAME = "Noise_IK_25519_AESGCM_SHA256". The protocol name that we use with Noise.HANDSHAKE_MSG_1 = 32 + (32 + 16) + (8 + 16). The size of the first handshake message which includes a public key, an encrypted public key, and an encrypted 8-byte payload.HANDSHAKE_MSG_2 = 32 + 16. The size of the second handshake message which contains a public key and an encrypted 0-byte payload.A peer maintains a few variables:
peer_id. The peer's id, a 16-byte value which is either:
private_key. The peer's X25519 private key, a 32-byte value.
public_key. The peer's X25519 public key, a 32-byte value.
A validator maintains the follow additional variables for the VN:
trusted_peers. A mapping of peer ids to public keys which represents the current validator set.timestamps. A mapping of peer ids to the last 8-byte timestamp seen from them. This value can be treated as a stateless and strictly increasing counter to avoid replay attacks (see security considerations section).Note that no client authentication is done in the VFN as it is currently a private network.
Our noise wrapper exposes two functions to create a noise session with a peer by dialing or listening to a socket:
upgrade_outbound(remote_public_key)
prologue in clear as peer_id followed by remote_public_key to the server.Initialize(PROTOCOL_NAME, true, prologue, private_key, null, remote_public_key, null).payload of the current epoch unix time in milliseconds.WriteMessage(payload, message_buffer) with the created payload.message_buffer to the server.server_response of size HANDSHAKE_MSG_2 bytes.ReadMessage(server_response, null) and return the two noise CipherStates obtained. Refer to the post-handshake session on how to use these.upgrade_inbound()
Receive the client's prologue, it should contain a 32-byte initiator_peer_id followed with a 32-byte responder_expected_public_key.
Verify that the received initiator_peer_id is either:
Verify that the received responder_expected_public_key is our public key.
Receive the client's client_message of size HANDSHAKE_MSG_1 bytes, it should be of size large enough to contain a payload of 8-byte.
Call noise's Initialize(PROTOCOL_NAME, true, prologue, private_key, null, remote_public_key, null).
Call noise's ReadMessage(client_message, payload_buffer).
If in the VN:
initiator_public_key received in the noise handshake message is in our trusted_peers set under the initiator_peer_id.payload is greater than any timestamp received so far for that initiator_peer_id.payload as the last timestamp seen for that initiator_peer_id.If in the PFN and VFN, enforce that the initiator_peer_id is correctly derived from the initiator_public_key.
call noise's WriteMessage(null, message_buffer) and store the two noise CipherStates obtained.
Send the constructed message_buffer to the server.
Return the two noise CipherStates. Refer to the post-handshake session on how to use these.
Once two CipherStates from noise have been obtained, we define the two wrapper functions:
encrypt(message)
EncryptWithAd(null, message) with the first CipherState to construct a ciphertext.ciphertext as a 2-byte value to the peer.ciphertext to the peer.decrypt(message)
length.length bytes from the peer as ciphertext.DecryptWithAd(null, ciphertext) and return the result.In the mutually-authenticated VN, an man-in-the-middle observer can in theory replay the first handshake message in order to:
As noise's IK handshake pattern does not provide key confirmation, it is necessary to prevent the first attack to wait for another client message before confirming the connection.
To prevent the second attack, we add a counter in the client's first noise message payload. A replay will be detected if the counter is not striclty increasing. In order to avoid keeping track of this counter on the client side we use an 8-byte unix timestamp, and in order to avoid connection issues from preventing a client to connect we set the precision to milliseconds. Thanks to this countermeasure, a server can halve (from 4 to 2) the number of Diffie-Hellman key exchanges they have to perform when detecting a replay.
Note that if a validator crashes, they will lose track of timestamps seen from clients. This would allow an attacker to replay all handshakes from a client in order. But this would not allow the attacker to prevent valid connection attempts.
We do not protect against this in the FN since an attacker can just create as many valid handshakes as they want.
We currently do not rekey session. We thus have long-lived sessions without forward and backward secrecy. This is currently not foreseen to be an issue as no critically confidential data is exchanged between validators, and important messages are further signed on the application layer.
From section Payload security properties of the noise specification, we observe that the sender's authentication is vulnerable to KCI: if the server's key is compromised, the attacker can impersonate anyone to the server.
We accept the risk.
Section Identity hiding of the noise specification outlines identity hiding risks, which we accept as well as the identities of our peers are not private.