Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSC3903: X25519 Elliptic-curve Diffie-Hellman ephemeral for establishing secure channel between two Matrix clients #3903

Closed
wants to merge 16 commits into from
Closed
137 changes: 137 additions & 0 deletions proposals/3903-x25519-ecdhe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# MSC3903: X25519 Elliptic-curve Diffie-Hellman ephemeral for establishing secure channel between two Matrix clients
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire MSC is essentially re-specifying ECIES (some more resources: [1], [2]).

MIT-licensed ECIES implementations in Rust, Python, TypeScript and Golang available here.


In MSCyyyy (to be published) 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.

**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.v1.curve25519-aes-sha256",
"key": "gRr3uZSpm2qz37CkqnrhZTW3H0JQvc6l4HYOtBULNSU="
}
```

The `key` is the base64-encoded value for `publicA` (the x co-ordinate of the curve).

It's critical that the initiator public key `publicA` is transmitted via a trusted medium such as a QR code or some other
uhoreg marked this conversation as resolved.
Show resolved Hide resolved
already-authenticated channel, and not via the unauthenticated channel.

**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.v1.curve25519-aes-sha256",
"key": "E03zK4t29xyiXlt54kOVpIzNtGytjQSvaHXF8n8tTBs="
}
```

Unlike `publicA` the recipient public key `publicB` does not need to be transmitted via a trusted medium.
uhoreg marked this conversation as resolved.
Show resolved Hide resolved
**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>|<base64-encoded initiator public key>|<base64-encoded recipient public key>`.

For the above example keys the info would be: `m.rendezvous.v1.curve25519-aes-sha256|gRr3uZSpm2qz37CkqnrhZTW3H0JQvc6l4HYOtBULNSU=|E03zK4t29xyiXlt54kOVpIzNtGytjQSvaHXF8n8tTBs=`.
hughns marked this conversation as resolved.
Show resolved Hide resolved

**5.** Subsequent payloads are then sent encrypted using 256 bit AES-GCM using a 256 bit random initialisation vector/salt.

**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` - base64-encoded AES-GCM encrypted data
- `iv` - base64-encoded initialization vector/salt

Steps **1** and **2** can happen simultaneously or in any order.

**7.** The user should confirm that the established channel is secure by means of a checksum derived from the shared key.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is CRAPPY, HORRIBLE UX! WHY? Why another visual comparison, another “I don't get what should I do now.” moment for users? Matrix already has too much visual comparison in its UX.

You already have a secure channel by means of QR code. Utilize it well, so users don't have to compare checksums.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The QR code is only secure in the sense that you can be sure that its contents were generated by the device that you're trying to communicate with. But it is not secret, as it is sometimes possible that someone else can scan the QR code as well. So unless you have another step (in this case, a visual comparison) to verify that the other public key was transmitted correctly, you cannot be sure that the channel is secure.

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.

## 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it sounds like this is duplicating Olm sessions over to-device? Early on in this proposal there should be something to address that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, acknowledged.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, no. It's actually that you could achieve this with to-device messaging instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MSC3886 vs to-device messaging is one thing, and I appreciate you creating a comparison of the two. But I think we still need a comparison between this and Olm. I think a natural question is why can't we just do Olm over MSC3886?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this^

Copy link
Member Author

@hughns hughns Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur that the feasibility of Olm over MSC3886 should be assessed.


### Send-to-Device messaging

Whilst to-device messaging already provides a mechanism for secure communication between two Matrix clients/devices, a
key consideration for the anticipated login with QR capability is that one of the clients is not yet authenticated with
a Homeserver.

Furthermore the client might not know which Homeserver the user wishes to connect to.

Conceptually, one could create a new type of "guest" login that would allow the unauthenticated client to connect to a
Homeserver for the purposes of communicating with an existing authenticated client via to-device messages.

Some considerations for this:

Where the "actual" Homeserver is not known then the "guest" Homeserver nominated by the new client would need to be federated
with the "actual" Homeserver.

The "guest" Homeserver would probably want to automatically clean up the "guest" accounts after a short period of time.

The "actual" Homeserver operator might not want to open up full "guest" access so a second type of "guest" account might
be required.

Does the new device/client need to accept the T&Cs of the "guest" Homeserver?

### 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.

## Security considerations

Algorithm selection and implementation are crucial.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this protects against replay attacks. That might be OK if the thing built on top of it can detect if a message is replayed (e.g. if messages have a definite order, so a replayed message would be flagged as being out of place), but I think it should be mentioned.

## Unstable prefix

TBD

## Dependencies

Although this proposal can be used over any other insecure channel, the anticipated use case is over
hughns marked this conversation as resolved.
Show resolved Hide resolved
[MSC3886](https://github.com/matrix-org/matrix-spec-proposals/pull/3886).

Furthermore without the (as yet unpublished) MSCyyyy proposal, there are no other implementations/uses of the proposal.