Identity model
Every Crosslink device (host or client) has a long-term Ed25519 identity:
The identity is:
- Generated once per installation
- Persisted across restarts
- Used to sign all key material
- Verifiable by any peer
Pairing authentication
Step 1: Code generation
The host generates a single-use pairing code:
Step 2: Code resolution
The client sends the code to the signaling service:
Step 3: Fingerprint verification
The client verifies the host fingerprint from the QR code matches:
This is the primary MITM defense during pairing. If the fingerprints don’t match, an attacker is likely intercepting the signaling traffic.
Step 4: Signed claims
Both parties exchange signed public keys:
Step 5: Challenge-response
The host sends a challenge, and the client signs it:
Step 6: SAS verification
Both parties derive the same Short Authentication String from their Ed25519 identity public keys (order-independent, so both sides compute the same value regardless of role):
The user must visually confirm both sides show the same digits.
Session authentication
Once paired, sessions are authenticated via:
- Encrypted frames — Only parties with the session key can read/write
- Sequence numbers — Prevent replay attacks
- Nonce uniqueness — Prevent frame substitution
Key hierarchy
Revocation
Host revocation
The host can revoke a client’s access by:
- Calling
server.revokeDevice(deviceId)
- This prevents future sessions from being established — revocation is re-checked on every handshake, so reconnection is refused even though the device still holds a valid Ed25519 key
Client revocation
The client can forget a paired host by:
- Calling
client.forget(appId)
- This removes the paired-app record
- Future pairing requires a new QR scan
Security properties