Merge pull request #63 from waku-org/device-pairing-update

WAKU2-DEVICE-PAIRING: Update
This commit is contained in:
Jimmy Debe 2025-06-12 06:47:49 -04:00 committed by GitHub
commit 48479c7513
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -24,7 +24,7 @@ and then securely completed over the Waku network.
The protocol we propose consists of two main subprotocols or _phases_: The protocol we propose consists of two main subprotocols or _phases_:
- [Device Pairing](#Device-Pairing): two phisically close devices initialize the _pairing_ by exchanging a QR code out-of-band. The devices then exchange and authenticate their respective long-term device ID static key by exchanging handshake messages over the Waku network; - [Device Pairing](#Device-Pairing): two physically close devices initialize the _pairing_ by exchanging a QR code out-of-band. The devices then exchange and authenticate their respective long-term device ID static key by exchanging handshake messages over the Waku network;
- [Secure Transfer](#Secure-Transfer): the devices securely exchange information in encrypted form using key material obtained during a successful pairing phase. The communication will happen over the Waku network, hence the devices do not need to be phisically close in this phase. - [Secure Transfer](#Secure-Transfer): the devices securely exchange information in encrypted form using key material obtained during a successful pairing phase. The communication will happen over the Waku network, hence the devices do not need to be phisically close in this phase.
## Theory / Semantics ## Theory / Semantics
@ -37,7 +37,7 @@ and will share a Noise session within which they can securely exchange informati
The request is made by exposing a QR code that, by default, has to be scanned by device `A`. The request is made by exposing a QR code that, by default, has to be scanned by device `A`.
If device `A` doesn't have a camera while device `B` does, If device `A` doesn't have a camera while device `B` does,
[it is possible](#Rationale) to execute a slightly different pairing (with same security guarantees), [it is possible](#rationale) to execute a slightly different pairing (with same security guarantees),
where `A` is exposing a QR code instead. where `A` is exposing a QR code instead.
This protocol is designed in order to achieve two main security objectives: This protocol is designed in order to achieve two main security objectives:
@ -82,18 +82,19 @@ d. -> sA, sAeB, sAsB {s}
- The content topic parameters `contentTopicParams = {application-name}, {application-version}, {shard-id}`. - The content topic parameters `contentTopicParams = {application-name}, {application-version}, {shard-id}`.
- A (randomly generated) 16-bytes long `messageNametag`. - A (randomly generated) 16-bytes long `messageNametag`.
- A commitment `H(sB||r)` for its static key `sB` where `r` is a random fixed-lenght value. - A commitment `H(sB||r)` for its static key `sB` where `r` is a random fixed-lenght value.
2. The device `A`: 2. The device `A`:
- scans the QR code; - scans the QR code;
- obtains `eB`, `contentTopicParams`, `messageNametag`, `Hash(sB||r)`; - obtains `eB`, `contentTopicParams`, `messageNametag`, `Hash(sB||r)`;
- checks if `{application-name}` and `{application-version}` from `contentTopicParams` match the local application name and version: if not, aborts the pairing. Sets `contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto`; - checks if `{application-name}` and `{application-version}` from `contentTopicParams` match the local application name and version: if not, aborts the pairing. Sets `contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto`;
- initializes the Noise handshake by passing `contentTopicParams`, `messageNametag` and `Hash(sB||r)` to the handshake prologue; - initializes the Noise handshake by passing `contentTopicParams`, `messageNametag` and `Hash(sB||r)` to the handshake prologue;
- executes the pre-handshake message, i.e. processes the key `eB`; - performs the pre-handshake process, i.e. processes the key `eB`;
- executes the first handshake message over `contentTopic`, i.e. - executes the first handshake message over `contentTopic`, i.e.
- processes and sends a Waku message containing an ephemeral key `eA`; - processes and sends a [14/WAKU2-MESSAGE](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/14/message.md) containing an ephemeral key `eA`;
- performs `DH(eA,eB)` (which computes a symmetric encryption key); - performs `DH(eA,eB)` (which computes a symmetric encryption key);
- attaches as payload to the handshake message the (encrypted) commitment `H(sA||s)` for `A`'s static key `sA`, where `s` is a random fixed-length value; - attaches, as payload to the handshake message,
the (encrypted) commitment `H(sA||s)` for `A`'s static key `sA`, where `s` is a random fixed-length value;
- an 8-digits authorization code `authcode` obtained as `HKDF(h) mod 10^8` is displayed on the device, where `h` is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) obtained once the first handshake message is processed. - an 8-digits authorization code `authcode` obtained as `HKDF(h) mod 10^8` is displayed on the device, where `h` is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) obtained once the first handshake message is processed.
3. The device `B`: 3. The device `B`:
@ -101,14 +102,14 @@ d. -> sA, sAeB, sAsB {s}
- sets `contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto`; - sets `contentTopic = /{application-name}/{application-version}/wakunoise/1/sessions_shard-{shard-id}/proto`;
- listens to messages sent to `contentTopic` and locally filters only those with [Waku payload](./noise.md/#abnf) starting with `messageNametag`. If any, continues. - listens to messages sent to `contentTopic` and locally filters only those with [Waku payload](./noise.md/#abnf) starting with `messageNametag`. If any, continues.
- initializes the Noise handshake by passing `contentTopicParams`, `messageNametag` and `Hash(sB||r)` to the handshake prologue; - initializes the Noise handshake by passing `contentTopicParams`, `messageNametag` and `Hash(sB||r)` to the handshake prologue;
- executes the pre-handshake message, i.e. processes its ephemeral key `eB`; - performs the pre-handshake process, i.e. processes its ephemeral key `eB`;
- executes the first handshake message, i.e. - processes the received first handshake message, i.e.
- obtains from the received message a public key `eA`. If `eA` is not a valid public key, the protocol is aborted. - obtains from the received message a public key `eA`. If `eA` is not a valid public key, the protocol is aborted.
- performs `DH(eA,eB)` (which computes a symmetric encryption key); - performs `DH(eA,eB)` (which computes a symmetric encryption key);
- decrypts the commitment `H(sA||s)` for `A`'s static key `sA`. - decrypts the commitment `H(sA||s)` for `A`'s static key `sA`.
- an 8 decimal digits authorization code `authcode` obtained as `HKDF(h) mod 10^8` is displayed on the device, where `h`is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) obtained once the first handshake message is processed. - an 8 decimal digits authorization code `authcode` obtained as `HKDF(h) mod 10^8` is displayed on the device, where `h`is the [handshake hash value](https://noiseprotocol.org/noise.html#overview-of-handshake-state-machine) obtained once the first handshake message is processed.
4. Device `A` and `B` wait for the user to confirm with an interaction (button press) 4. Device `A` and `B` wait for user confirmations, through a user interface,
that the authorization code displayed on both devices are the same. that the authorization code displayed on both devices are the same.
If not, the protocol is aborted. If not, the protocol is aborted.
@ -121,7 +122,8 @@ d. -> sA, sAeB, sAsB {s}
6. The device `A`: 6. The device `A`:
- listens to messages sent to `contentTopic` and locally filters only those with Waku payload starting with `messageNametag`. If any, continues. - listens to messages sent to `contentTopic` and locally filters only those with [26/WAKU2-PAYLOAD](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/application/26/payload.md) starting with `messageNametag`.
If any, continues.
- decrypts the received message and obtains the public key `sB`. If `sB` is not a valid public key, the protocol is aborted. - decrypts the received message and obtains the public key `sB`. If `sB` is not a valid public key, the protocol is aborted.
- performs `DH(eA,sB)` (which updates a symmetric encryption key); - performs `DH(eA,sB)` (which updates a symmetric encryption key);
- decrypts the payload to obtain the randomness `r`. - decrypts the payload to obtain the randomness `r`.
@ -135,12 +137,14 @@ d. -> sA, sAeB, sAsB {s}
7. The device `B`: 7. The device `B`:
- listens to messages sent to `contentTopic` and locally filters only those with Waku payload starting with `messageNametag`. If any, continues. - listens to messages sent to `contentTopic` and locally filters only those with [26/WAKU2-PAYLOAD](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/application/26/payload.md) starting with `messageNametag`. If any, continues.
- obtains from decrypting the received message a public key `sA`. If `sA` is not a valid public key, the protocol is aborted. - processess the third handshake message, i.e.
- performs `DH(sA,eB)` (which updates a symmetric encryption key); - obtains from decrypting the received message a public key `sA`. If `sA` is not a valid public key, the protocol is aborted.
- performs `DH(sA,sB)` (which updates a symmetric encryption key); - performs `DH(sA,eB)` (which updates a symmetric encryption key);
- decrypts the payload to obtain the randomness `s`. - performs `DH(sA,sB)` (which updates a symmetric encryption key);
- Computes `H(sA||s)` and checks if this value corresponds to the commitment obtained in step 3. If not, the protocol is aborted. - decrypts the payload to obtain the randomness `s`.
- Computes `H(sA||s)` and checks if this value corresponds to the commitment obtained in step 3.
If not, the protocol is aborted.
- Calls [Split()](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object) and obtains two cipher states to encrypt inbound and outbound messages. - Calls [Split()](http://www.noiseprotocol.org/noise.html#the-symmetricstate-object) and obtains two cipher states to encrypt inbound and outbound messages.
#### The `WakuPairing` for Devices without a Camera #### The `WakuPairing` for Devices without a Camera
@ -152,9 +156,9 @@ exchanging a single message (e.g., Noise sessions, cryptographic keys, signature
However, since the user(s) confirm(s) at the end of message `b.` that the authorization code is the same on both devices, However, since the user(s) confirm(s) at the end of message `b.` that the authorization code is the same on both devices,
the role of the handhsake initiator and responder can be safely swapped in message `a.` and `b.`. the role of the handhsake initiator and responder can be safely swapped in message `a.` and `b.`.
Indeed, if the pairing phase successfully completes on both devices, Indeed, if the pairing phase successfully completes on both devices, the authentication code,
the authentication code, the committed static keys and the Noise processing rules will ensure that no Man-in-the-Middle attack took place the committed static keys and the Noise processing rules will ensure that no Man-in-the-Middle attack took place.
and that messages can be securely exchanged bi-directionally in the transfer phase. Messages can then be securely exchanged bi-directionally in the transfer phase.
This allows pairing in case device `A` does not have a camera to scan a QR (e.g. a desktop client) while device `B` has. This allows pairing in case device `A` does not have a camera to scan a QR (e.g. a desktop client) while device `B` has.
@ -257,7 +261,7 @@ in order to frequently and deterministically change the `messageNametag` of mess
ideally, at each message exchanged. ideally, at each message exchanged.
Given the proposed construction, Given the proposed construction,
the `mntsInbound` and `mntsOutbound` secrets can be used to iteratively generate the `messageNametag` field of Waku payloads the `mntsInbound` and `mntsOutbound` secrets can be used to iteratively generate the `messageNametag` field of [26/WAKU2-PAYLOAD](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/application/26/payload.md)s
for inbound and outbound messages, respectively. for inbound and outbound messages, respectively.
The derivation of `messageNametag` should be deterministic only for communicating devices The derivation of `messageNametag` should be deterministic only for communicating devices
@ -374,3 +378,4 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public
- [The Double-Ratchet Algorithm](https://signal.org/docs/specifications/doubleratchet/) - [The Double-Ratchet Algorithm](https://signal.org/docs/specifications/doubleratchet/)
- [The Noise Protocol Framework specifications](http://www.noiseprotocol.org/noise.html) - [The Noise Protocol Framework specifications](http://www.noiseprotocol.org/noise.html)
- [IETF RFC 4648 - The Base16, Base32, and Base64 Data Encodings](https://datatracker.ietf.org/doc/html/rfc4648) - [IETF RFC 4648 - The Base16, Base32, and Base64 Data Encodings](https://datatracker.ietf.org/doc/html/rfc4648)
- [14/WAKU2-MESSAGE](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/14/message.md)