Skip to main content
Implementation lives in crates/protocol/src/crypto.rs. The design is WireGuard/Noise-inspired and deliberately conservative — “very high quality, boring crypto.”

Primitives

PurposePrimitiveCrate
Key agreementX25519 ECDH (ephemeral)x25519-dalek
AuthenticationPre-shared key mixed into the KDF salt
Key derivationHKDF-SHA256hkdf, sha2
Record encryptionChaCha20-Poly1305 (AEAD)chacha20poly1305

Handshake (per session)

1

Fresh ephemeral keys

Each peer generates a fresh ephemeral X25519 keypair.
2

Exchange public keys

Over the TCP bulk channel they exchange 32-byte public keys in the clear (safe for ECDH).
3

Compute the shared secret

Both compute DH(our_sk, their_pk).
4

Derive key material

HKDF-SHA256 derives keys with salt = PSK (the passphrase → authentication), ikm = shared_secret, and info = "sc-v1-kd" || sorted(pubkey_a, pubkey_b) (binds the transcript).
5

Split into four keys

The 128-byte output splits into input-i2r, input-r2i, bulk-i2r, bulk-r2i (i2r = initiator→responder). Each channel + direction gets its own key, so counters/nonces can never collide.

Why this is secure

ChaCha20-Poly1305 is an AEAD; any tampering fails the Poly1305 tag and the packet is rejected.
Without the correct PSK, the two peers derive different keys and every open() fails. An attacker who intercepts and replaces the ephemeral keys still can’t derive the session keys without the PSK. This is why mDNS discovery is safe — discovery only finds a candidate address; the PSK still proves identity.
Keys are ephemeral per session, so compromising one session’s keys doesn’t expose past or future sessions.
A unique key per direction + a monotonic counter (UDP: the packet seq; TCP: an implicit ordered counter) guarantees no (key, nonce) pair is ever reused — the cardinal AEAD rule.

Threat model

  • Passive eavesdropper on the LAN/Wi-Fi.
  • Active attacker who forges/replays/tampers packets (rejected by AEAD + counter).
  • Imposter advertising the same mDNS service (rejected without the PSK).

Operational guidance

Use a long, random PSK, identical on both machines, and never commit it. The config file holds the PSK in plaintext at ~/Library/Application Support/shareclick/config.toml (macOS) or %APPDATA%\shareclick\config.toml (Windows). Protect it with normal file permissions.

Tests

crypto.rs unit tests assert: round-trip both directions; wrong PSK fails; tampered ciphertext fails; wrong counter fails; tag-only overhead; and that the input and bulk channels use independent keys (a ciphertext from one cannot be opened by the other).