Skip to content

Call E2EE

Purpose

Call E2EE protects media so the backend and transport provider cannot decrypt audio/video content. The backend coordinates signaling and room access, but devices own the call session key.

Key Lifecycle

Verify peer identity
        -> create one fresh call session key
        -> encrypt that key separately for each peer device
        -> send encrypted key material through call signaling
        -> each receiver decrypts locally
        -> LiveKit media uses the shared session key for E2EE
        -> key is cleared when call state is cleaned up

Key Agreement Policy

Case Behavior
Modern devices Prefer P-256 key agreement backed by Secure Enclave.
Legacy devices Fall back to RSA-2048 wrapping when needed.
Group calls Use one call session key, wrapped separately for every participant device.
Rejoin/invite Reuse the active call session key and wrap it for the new/requesting participant.

Identity Verification Before Encryption

Before a session key is wrapped for another device, the app verifies peer public-key data through Key Transparency and checks the local trust cache.

Runtime behavior:

  • normal verified key set: continue silently
  • verified key set changed: warn before trust cache update
  • outgoing proof failure: user can currently override after warning
  • invite/rejoin proof failure: block the flow

This is a current implementation trade-off. The target security posture is simpler: verified key or no encrypted call setup.

Media Encryption

After the app has a valid session key and a LiveKit room token:

connect to room
        -> create media key provider
        -> set call session key
        -> enable LiveKit E2EE
        -> publish local audio/video tracks

If the user rotates or overrides the active key from the call UI, the media layer updates the current E2EE key during the call.

Reconnect Behavior

LiveKit reconnect is separate from manual rejoin:

LiveKit reconnect completes
        -> app refreshes participant status
        -> if local user is still joined: sync participant list
        -> if local user is not joined: attempt media recovery using stored room token and current session key

Security Notes

  • The backend receives encrypted call-key payloads, not the raw media session key.
  • The same session key should not outlive the call lifecycle.
  • Peer key changes are user-visible because they may indicate a new device or an attack.
  • The outgoing override path is weaker than invite/rejoin and should be treated as a known hardening target.