diff --git a/proposals/3903-x25519-ecdhe.md b/proposals/3903-x25519-ecdhe.md new file mode 100644 index 00000000000..905f07f0cc7 --- /dev/null +++ b/proposals/3903-x25519-ecdhe.md @@ -0,0 +1,157 @@ +# 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 +`||`. + +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.