Commit 5e3666b9 authored by akwizgran's avatar akwizgran
Browse files

Add spec for handshake protocol.

parent a1c44199
# Bramble Handshake Protocol, version 0
## 1 Introduction
Bramble Handshake Protocol (BHP) is a key agreement protocol for delay-tolerant networks. It enables two peers that have previously exchanged long-term public keys to establish an ephemeral shared secret that is not known to any other party.
BHP is designed to be used with Bramble Transport Protocol (BTP) in handshake mode. The shared secret produced by BHP can be used to derive a root key for upgrading BTP to transport mode, which provides forward secrecy.
BHP can operate over any connection-oriented, bidirectional transport protocol. Unidirectional transports are not suitable for BHP.
### 1.1 Adversary Model
We assume the adversary can observe, block, delay, replay and modify traffic on all underlying transports.
We do not assume the peers exchanged their long-term public keys over a secure channel. If the adversary intercepted the prior exchange of public keys and replaced them with its own public keys then BHP does not detect or prevent man-in-the-middle attacks. If the adversary knows both peers' long-term public keys but did not replace them during the prior exchange then BHP prevents man-in-the-middle attacks.
BHP does not rely on lower protocol layers to provide confidentiality, integrity, authenticity or forward secrecy. If the traffic between peers needs to be indistinguishable from random then BHP should be used with a protocol that provides this property, such as BTP in handshake mode.
### 1.2 Prerequisites
Before two peers can communicate using BHP they must exchange long-term public keys. BHP does not specify how this should be done. Any synchronous or asynchronous communication channel can be used, subject to the caveat that if an adversary can replace the keys being exchanged then the adversary can carry out a man-in-the-middle attack against BHP.
The peers must also establish a connection over a bidirectional transport. Each peer needs to know which peer it's connected to so it can use the appropriate long-term public key for authenticating the other peer. When BHP is used with BTP in handshake mode, BTP enables the peers to identify each other so they can look up the appropriate long-term public keys.
Each peer uses the long-term public keys to decide whether it will take the role of **Alice** or **Bob** in BHP. The peers take roles according to the lexicographic order of their long-term public keys, compared as byte strings. The peer with the earlier key plays the role of Alice, while the peer with the later key plays the role of Bob. The roles are symmetrical except for the order of the protocol steps.
### 1.3 Notation
- || denotes concatenation
- Double quotes denote an ASCII string
- len(x) denotes the length of x in bytes
- int\_n(x) denotes x represented as an unsigned, big-endian, n-bit integer
### 1.4 Cryptographic Primitives
BHP uses three cryptographic primitives:
1. **A cryptographic hash function**, H(m)
2. **A key agreement function**, DH(pri, pub), where pri is one party's private key and pub is the other party's public key
3. **A message authentication code**, MAC(k, m), which must be a pseudo-random function
We use H(m) to define a multi-argument hash function:
- HASH(x\_1, ..., x\_n) = H(int\_32(len(x\_1)) || x\_1 || ... || int\_32(len(x\_n)) || x\_n)
We use MAC(k, m) to define a key derivation function:
- KDF(k, x\_1, ..., x\_n) = MAC(k, int\_32(len(x\_1)) || x\_1 || ... || int\_32(len(x\_n)) || x\_n)
All hashes are HASH\_LEN bytes, all symmetric keys are KEY\_LEN bytes, and the output of MAC(k, m) is MAC\_LEN bytes. For simplicity we require that HASH\_LEN = KEY\_LEN = MAC\_LEN.
(*Note:* The current version of the protocol uses BLAKE2b as the hash function and keyed BLAKE2b as the message authentication code, both with an output length of 32 bytes. This gives HASH\_LEN = KEY\_LEN = MAC\_LEN = 32. The key agreement function is X25519.)
## 2 The Handshake Protocol
### 2.1 Records
The peers exchange a series of **records** over the transport connection. Each record has the following format:
- record\_header = int\_8(protocol\_version) || int\_8(record\_type) || int\_16(len(payload))
- record = record\_header || payload
The maximum length of the payload is 48 KiB.
The current version of the protocol is 0, which has two record types:
**0: EPHEMERAL\_PUBLIC\_KEY** - The payload consists of the sender's ephemeral public key.
**1: PROOF\_OF\_OWNERSHIP** - The payload consists of a message authentication code proving ownership of the sender's long-term and ephemeral public keys and binding them to the recipient's long-term and ephemeral public keys.
A peer should reject any record with an unsupported protocol version and ignore any record with a supported protocol version but an unrecognised record type. This allows new record types to be added without breaking compatibility.
### 2.2 Protocol Steps
The protocol has four steps:
1. Alice generates an ephemeral key pair and sends an EPHEMERAL\_PUBLIC\_KEY record
2. Bob generates an ephemeral key pair and sends an EPHEMERAL\_PUBLIC\_KEY record
3. Alice derives the master key and sends a PROOF\_OF\_OWNERSHIP record
4. Bob derives the master key and sends a PROOF\_OF\_OWNERSHIP record
### 2.3 Key Derivation
Alice calculates three "raw" shared secrets as follows:
- raw\_static = DH(pri\_long\_term\_a, pub\_long\_term\_b)
- raw\_static\_ephemeral = DH(pri\_long\_term\_a, pub\_ephemeral\_b)
- raw\_ephemeral\_static = DH(pri\_ephemeral\_a, pub\_long\_term\_b)
Bob calculates three "raw" shared secrets as follows:
- raw\_static = DH(pri\_long\_term\_b, pub\_long\_term\_a)
- raw\_static\_ephemeral = DH(pri\_ephemeral\_b, pub\_long\_term\_a)
- raw\_ephemeral\_static = DH(pri\_long\_term\_b, pub\_ephemeral\_a)
(*Note:* If a peer calculates an X25519 raw shared secret that is all zeroes, the peer must abort the protocol.)
If the adversary has not modified the long-term or ephemeral public keys, both peers will calculate the same shared secrets. The peers then derive a "cooked" shared secret known as the **master key**, which incorporates both peers' long-term and ephemeral public keys:
- master\_key = HASH("org.briarproject.bramble.handshake/MASTER\_KEY", raw\_static, raw\_static\_ephemeral, raw\_ephemeral\_static, pub\_long\_term\_a, pub\_long\_term\_b, pub\_ephemeral\_a, pub\_ephemeral\_b)
### 2.4 Proof of Ownership
The master key depends on both peers' long-term and ephemeral public keys, as well as on shared secrets that can only be derived by the owners of those keys. Each peer sends a message authentication code to prove that it has derived the correct master key, which in turn proves that it owns the long-term and ephemeral public keys received by the other peer, and has received the long-term and ephemeral public keys sent by the other peer.
Each peer calculates its own message authentication code and the code it expects to receive from the other peer. If the code received from the other peer differs from the expected code then the peer must abort the protocol.
- alice\_proof = MAC(master\_key, "org.briarproject.bramble.handshake/ALICE\_PROOF")
- bob\_proof = MAC(master\_key, "org.briarproject.bramble.handshake/BOB\_PROOF")
As noted above, if the adversary intercepted the prior exchange of long-term public keys and replaced them with its own public keys then BHP does not prevent a man-in-the-middle attack: the adversary can intercept the BHP connection, replace the peers' ephemeral public keys with its own public keys, and produce a proof of ownership of its own long-term and ephemeral public keys that will satisfy each peer.
However, if the adversary did *not* intercept the prior exchange of long-term public keys, and if the adversary now intercepts the BHP connection and replaces the peers' ephemeral public keys with its own keys, then the adversary will not be able to produce a proof of ownership that will satisfy either peer.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment