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
157 changes: 157 additions & 0 deletions proposals/3903-x25519-ecdhe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
# 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 [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.
Comment on lines +3 to +11
Copy link
Member

Choose a reason for hiding this comment

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

The reference to MSC3906 should be clarified by stating what kind of relationship it has with this MSC.

Suggested change
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.
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, followed by exchanging some messages over
a secure channel.
[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, which satisfies the
requirements of MSC3906.


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.
Comment on lines +20 to +21
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
The proposal is to use X25519 to agree a shared secret that is then used to
perform AES.
The proposal is to use X25519 to agree on 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`.
Copy link
Member

Choose a reason for hiding this comment

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

nit: please use markdown's built-in numbering/bullet system

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
**1a.** The initiator generates a ephemeral Curve25519 private key `privateA`.
**1a.** The initiator generates an 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
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
**1c.** The initiator shares it's key with the recipient via a trusted medium
**1c.** The initiator shares its 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:
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public key `publicB` and shares is using the same structure of payload:
public key `publicB` and shares it 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.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
devices have not directly exchanged keys with one another and are subject to a man-in-the-middle.
devices have not directly exchanged keys with one another and are subject to a
man-in-the-middle attack.


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

Choose a reason for hiding this comment

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

The info should be different, otherwise the checksum will leak bits of the encryption key. You can prepend the info with checksum|.

Copy link
Member

Choose a reason for hiding this comment

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

Yep. As it stands, this looks like a gaping hole.


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

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.

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

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.