matrix-doc/proposals/3903-x25519-ecdhe.md

158 lines
6.7 KiB
Markdown

# MSC3903: X25519 Elliptic-curve Diffie-Hellman ephemeral for establishing secure channel between two Matrix clients
In [MSC3906](https://github.com/matrix-org/matrix-spec-proposals/pull/3906) a
proposal is made to allow a user to login on a new device using an existing
device by means of scanning a QR code.
[MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886) already
proposes a simple unsecured rendezvous protocol.
In this proposal we build a secure layer on top of MSC3886 to allow for trusted
out-of-bands communication between two Matrix clients.
It is notable that the combination of this proposal and [MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886)
provides a similar capability to the existing
[Send-to-Device messaging](https://spec.matrix.org/v1.4/client-server-api/#send-to-device-messaging)
feature. See the alternatives section for more on this.
## Proposal
The proposal is to use X25519 to agree a shared secret that is then used to
perform AES.
All payloads are transmitted as JSON and could be done over any bidirectional
transport including [MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886)
or elsewhere in Matrix.
As Diffie-Hellman key agreement is a non-authenticated key-agreement protocol,
this proposal makes use of a checksum for the user to authenticate the key agreement.
**1a.** The initiator generates a ephemeral Curve25519 private key `privateA`.
This key should never be re-used.
**1b.** The initiator derives the public key from `privateA` as
`publicA = scalarMult(privateA, 9)`
**1c.** The initiator shares it's key with the recipient via a trusted medium
using the following payload:
```json
{
"algorithm": "m.rendezvous.v2.curve25519-aes-sha256",
"key": "gRr3uZSpm2qz37CkqnrhZTW3H0JQvc6l4HY0tBULNSU"
}
```
The `key` is the unpadded base64-encoded value for `publicA` (the x co-ordinate
of the curve).
**2.** The recipient similarly generates a private key `privateB`, derives the
public key `publicB` and shares is using the same structure of payload:
```json
{
"algorithm": "m.rendezvous.v2.curve25519-aes-sha256",
"key": "E03zK4t29xyiXlt54kOVpIzNtGytjQSvaHXF8n8tTBs"
}
```
**3.** Both sides derive the same shared secret as follows:
Initiator: `sharedSecret = scalarMult(privateA, publicB) = scalarMult(privateA, scalarMult(privateB, 9))`
Recipient: `sharedSecret = scalarMult(privateB, publicA) = scalarMult(privateB, scalarMult(privateA, 9))`
**4.** Both sides then derive a 256 bit AES key using HKDF SHA-256 with a salt
of 8 bytes of zero (i.e. `[0,0,0,0,0,0,0,0]`) and info of
`<algorithm>|<unpadded base64-encoded initiator public key>|<unpadded base64-encoded recipient public key>`.
For the above example keys the info would be:
`m.rendezvous.v2.curve25519-aes-sha256|gRr3uZSpm2qz37CkqnrhZTW3H0JQvc6l4HY0tBULNSU|E03zK4t29xyiXlt54kOVpIzNtGytjQSvaHXF8n8tTBs`.
**5.** Subsequent payloads are then sent encrypted using 256 bit AES-GCM using a
256 bit random initialisation vector and 128 bit authentication tag.
**6.** Encrypted payloads are then encoded and transmitted by either party as follows:
```json
{
"ciphertext": "L3SHZU2DnfPxiVHVcgqe2HNq7Acdv13XCK/mC5f0JmxGqeUNQdeta8HD8qGBu3YdYrv5Bf7xl8WjlGaUOLr3uceZUuSv8amRZUghZ+/GQsi8tPZLzHk0xOePmKhRg95HUZrja7cQIgw+iKY/Vp1UoUJRqk1iQv/86RHz3c5a/GqyhGyWnXfuy16tPxmNQ4IpI/hVJof+7iiA3IucMtLHZnGH/VpNuZ1kv97GJJbUX3XfTIjyN2jmA9zFP5d/mE10YYzG7XcZ0hWj5BPhpM1jojwVyTRhMseJAX7MVvqQ7HT7LjvoJSYm5xk+0ptsWodAuol7uYjGszIu+EFvpuYmweZa6ewcnf/T5fXb6hXfqCZf43gumrXx5ACUMC4IWBOI0mFE28ITRmw9ZjL2CodxFsbTGRYp3Arb0SMcF1KUsiYBXxLasXFaEtrE244QD+oc9FEWNPLdgCDcwEhalaK9OP7MJF7jXc2y+zOPfUPCdCHoSV6F5Y/MnPkrpwprrIn/yp2E4/4QTe2VTXG7ZJa/aCGh8eAo9nBANQi7sGElr83SU0oy80MvVWUmxnaWc8UDgASkC/dGQNCfZzsZeho0+Y2smcETJlD/7+D1c8YC3LevAtYXDOOO9ApaY+SpPloKp/zdoZdkf+ggGfyytvTEw0gZUygZnBplefaIry9lASpv6XXkowVFFP5kGf0ZAhPOr2ET3DTyoBXP7u7MJrRAtBEex6OaysVaJ2DDEj8JknpdwatuWPduygMt",
"iv": "Fk/2eSQ2hANwpQhAI94/BQ"
}
```
- `ciphertext` - unpadded base64-encoded(AES-GCM ciphertext concatenated with
the authentication tag)
- `iv` - unpadded base64-encoded(initialization vector)
This means that for AES-GCM implementations that require the authentication tag
to be explicitly processed (e.g. CryptoKit on iOS) that it can be sourced from
the last 16 bytes of the unpadded base64-decoded `ciphertext`.
**7.** The user should authenticate/confirm that the established channel is
secure by means of a checksum that is shown on both devices.
If the checksum shown is not the same on both defives then it means that the
devices have not directly exchanged keys with one another and are subject to a man-in-the-middle.
The checksum is 12 numeric digits in the form `1234-5678-9012` and should be
displayed on both devices for the user to visually verify.
The checksum should be derived in a similar manner to step **4** above, however
only 40 bit should be derived this time. The salt and info are the same as before.
The decimal representation of the 40 bits is calculated using the method
described in https://spec.matrix.org/v1.4/client-server-api/#sas-method-decimal.
Steps **1** and **2** can happen simultaneously or in any order.
## Potential issues
This proposal introduces yet another key that Matrix client implementations need
awareness of. It's also not clear to me where exactly this would fit in the spec
documents.
## Alternatives
### Send-to-Device messaging
The combination of this proposal and
[MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886) look
similar in some regards to the existing
[Send-to-device messaging](https://spec.matrix.org/v1.6/client-server-api/#send-to-device-messaging)
capability.
Discussion on this as an alternative has been moved to
[MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886) as it
has received more engagement on that proposal.
### Naming convention
The algorithm name is arbitrary.
Alternative key exchange algorithms to X25519 could be used. Alternative
symmetric ciphers to AES-GCM could be used. The purpose of the `algorithm` field
is allow for alternative algorithms in the future.
An earlier iteration of this proposal used the algorithm name
`m.rendezvous.v1.curve25519-aes-sha256` but that has been superseded.
## Security considerations
Algorithm selection and implementation are crucial.
## Unstable prefix
Whilst in development the unstable algorithm name of
`org.matrix.msc3903.rendezvous.v2.curve25519-aes-sha256` should be used.
## Dependencies
Although this proposal could be used over any communication channel, the
anticipated use case is over [MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886).
Furthermore without the
[MSC3906](https://github.com/matrix-org/matrix-spec-proposals/pull/3906)
proposal, there are no other implementations/uses of the proposal.