mirror of
https://github.com/rustdesk/hbb_common.git
synced 2026-10-11 19:23:59 +00:00
tcp: key exchange version 1, one stream key per direction
Version 1 of the key exchange splits the exchanged key into a subkey per direction, the way Noise splits its cipher states after the handshake, and leaves the nonce layout and the handshake messages as they are. Each subkey is a keyed BLAKE2b over the handshake transcript: both ephemeral public keys, the version the responder advertised and the one the initiator picked, so a change to any of it in transit leaves the two sides with different keys. The original scheme is version 0, which is also what an absent field means. Negotiated through new fields old peers do not see: the side that speaks first advertises the newest version it has (`KeyExchange.version` from the server, `IdPk.kx_version` inside the signed identity from the controlled side), the other side answers with the highest both have, and the pair runs that. Any old peer on either end keeps today's stream byte for byte. The controlled side's advertisement sits inside the signature; the server's is repeated in `RendezvousMessage.kx_advertised` on its first message after the exchange, inside the encrypted channel, and a client that was shown a different value in the clear refuses the stream. `Encrypt::new` is unchanged; `new_split`, `set_key_split` and `check_kx_advertised` are added beside it, and `box_pk_of` for a responder that kept only the secret half of its ephemeral pair. The tests pin the version 0 output as well as the split and the echo. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
d9895ff9cb
commit
e272fede36
@@ -8,6 +8,9 @@ message IdPk {
|
||||
// a WebRTC peer's DTLS channel can be bound to its verified identity (defeats a rendezvous/relay
|
||||
// that swaps SDP fingerprints). Empty for non-WebRTC handshakes.
|
||||
string dtls_fingerprint = 3;
|
||||
// Newest key exchange version the signer speaks; absent, i.e. 0, is the original scheme.
|
||||
// Inside the signed identity so a rendezvous or relay cannot lower it.
|
||||
uint32 kx_version = 4;
|
||||
}
|
||||
|
||||
message RegisterPeer {
|
||||
@@ -232,6 +235,9 @@ message OnlineResponse {
|
||||
|
||||
message KeyExchange {
|
||||
repeated bytes keys = 1;
|
||||
// From the server: the newest key exchange version it speaks. From the client: the version it
|
||||
// picked, the highest both speak. Absent, i.e. 0, is the original scheme.
|
||||
uint32 version = 2;
|
||||
}
|
||||
|
||||
message HealthCheck {
|
||||
@@ -291,4 +297,9 @@ message RendezvousMessage {
|
||||
HttpProxyResponse http_proxy_response = 28;
|
||||
IceCandidate ice_candidate = 29;
|
||||
}
|
||||
// From the server, on its first message after a key exchange: the version it advertised,
|
||||
// repeated inside the encrypted channel where nothing in transit can alter it. A client that
|
||||
// was shown a different value in the clear knows the handshake was altered and refuses the
|
||||
// stream. Absent from servers that predate versions.
|
||||
uint32 kx_advertised = 30;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user