ouisync icon indicating copy to clipboard operation
ouisync copied to clipboard

Improve protocol security

Open madadam opened this issue 3 years ago • 5 comments

The protocol currently has several security weaknesses that should be addressed:

  • [x] 1. The initial handshake is neither encrypted, nor authenticated
  • [ ] 2. Message headers are not encrypted
  • [x] 3. Message header is not tied to the corresponding message body in any way
  • [x] 4. Message channel id depends only on the repository id and so is the same for all replicas sharing the same repository

1. The initial handshake is neither encrypted, nor authenticated

Problem

After establishing a connection, the peers exchange their runtime ids. This exchange is not encrypted and the ids themselves are not authenticated, so an attacker can eavesdrop such id and then presents it as his own. This is by itself not enough to impersonate another replica (the runtime id is not tied to the replica identity) but this can be used as a basis for more subtle attacks (explained later).

Suggested solution

Use a simple NN noise protocol for the initial handshake and authenticate the runtime ids using the following protocol:

  1. The peers first exchange a randomly generated nonces
  2. Each pear then interprets their runtime id as a secret signing key and uses it to sign the received nonce (or both nonces (in the same order)). Then it sends the corresponding public key + the signature of the nonce(s) to the other peer.
  3. The peers then verify the signatures and proceed only if they match

The encryption prevents eavesdropping, but because it's not authenticated, man-in-the-middle is still possible. But by authenticating the runtime ids it's impossible for an attacker to take someone else's runtime ids and pretend it's their own because they won't be able to provide a matching signature.

2. Message headers are not encrypted

Problem

The message headers consisting of the message channel id and the message payload length are currently not encrypted and thus an attacker can easily read them. The message channel id can be potentially used to break plausible deniability (explained later). The message length can be used to decode partial structure of the communication which can potentially simplify brute force attacks. Ideally the communication should be indistinguishable from a random noise.

Suggested solution

Encrypt the headers using the same NN noise protocol as described in the previous section. Note: only encrypt the headers this way. The payloads are already encrypted using a different noise protocol and encrypting them twice would just waste cycles.

Note: this would protect the headers from eavesdropping but would still leave them vulnerable to some man-in-the-middle. This will be addressed in the following section.

3. Message header is not tied to the corresponding message body in any way

Problem

A man-in-the-middle can replace the channel id of a message with a different channel id and cause the message to be applied to a wrong repository. They would be able to do this even after we apply the previous solution (encrypting the headers) because the encryption is not authenticated.

Suggested solution

Put the message channel id as the additional authenticated data when encrypting the message payload. That way a message whose channel id has been tampered with would be detected on decryption and can be discarded.

4. Message channel id depends only on the repository id and so is the same for all replicas sharing the same repository

Problem

The message channel id is computed by hashing the repository id with a fixed salt. That means that if a replica is sharing a repository with two or more replicas, it will use the same channel id to communicate with all of them. This can be used by an attacker to break plausible deniability: say the attacker knows that some replica X is sharing some repository R. Then they can eavesdrop / man-in-the-middle on some other replica Y and by observing they use the same message channel they can prove that Y is also sharing the same repository R.

Suggested solution

The channel id should be generated by hashing the repository id + the two runtime ids of the peers (in consistent order). That way the channel id would be unique per each (replica, replica, repository) triple. Note that this requires addressing the problem number one first because without it an attacker would be able to eavesdrop on X to steal their runtime id, then man-in-the-middle to Y, present the stolen runtime id to them thus obtaining the same channel id as Y used to talk to X and thus proving Y also shares R.

madadam avatar Apr 13 '22 15:04 madadam

The problem in #1

so an attacker can eavesdrop such id and then presents it as his own.

should now be solved since commit e22e43ee8ece802735986525e57b6362453e9615 where the runtime IDs are still visible/unencrypted but they are essentially ephemeral public keys for which the private key is only held by the replica claiming to have that particular runtime ID. The proof that a peer owns the private part of the keypair is done during the handshake.

inetic avatar Jul 05 '22 07:07 inetic

Problem #4 should be addressed by a6fafb2085958fce46af5896a22dea66893aacac

inetic avatar Dec 07 '22 15:12 inetic

Another idea for 2:

We can encrypt the message length using the same encryption we use for the message body. The length is fixed size (2 bytes) so we can just read 2 bytes from the stream, decrypt it, decode as u16 and use that to read the remainder of the message.

This wouldn't be sufficient to protect the framing information (where one message ends and another begins) because that is revealed by the message channel id which is identical for every message and so an attacker can just look for repeated patterns.

madadam avatar Dec 08 '22 13:12 madadam

Idea for concealing the message channel id:

Prefix each messages with a randomly generated fixed-size nonce (newly generated for every message) . Then the message channel id would be computed as hash(nonce + repo_id + ...). That way the resulting channel id would be different for every message and so the framing couldn't be deduced by detecting repeated patterns.

madadam avatar Dec 08 '22 13:12 madadam

https://redmine.equalit.ie/issues/31639

IvanaBlzvc avatar May 08 '25 10:05 IvanaBlzvc