Group call crypto¶
Crypto - group-call-crypto
CRY-06 - status: draft - audio, video, group, screen-share
A single 32-byte call key is shared with every group-call participant, and each participant derives one SFrame key per sender keyed by that sender's participant id.
Call key. A group call MUST share one 32-byte callKey among all participants,
delivered to each recipient device in the offer's <enc> payload (see
call-offer). The same callKey is used by every member; there is no
per-pair key. A callKey not exactly 32 bytes MUST fail key derivation (no key produced).
Per-sender SFrame key derivation. Derive with HKDF-SHA256 (expand):
salt = callKey[0..16]
ikm = callKey[16..32]
info = "e2e sframe key" || participantId
L = 32
OKM = HKDF-SHA256(salt, ikm, info, 32)
The SFrame AEAD (AES-128-GCM) MUST use OKM[0..16] as the key; OKM[16..32] is unused.
Participant id normalization. participantId MUST be the sender's normalized
participant JID:
- Strip any device/resource suffix after
/; trim surrounding whitespace. - If there is no
@, or@is the first character, use the bare string unchanged. - Split into
user@domain. Ifuseralready contains:, keepuser@domainunchanged. - If
domainislidanduserhas no:suffix, address the primary device as:0, yieldinguser:0@lid. - Otherwise use
user@domain.
Direction. The info label always carries the sender's participant id, so producer and consumer derive an identical key. Each participant MUST derive its send key from its own normalized id and seal outgoing frames under it; to receive, it MUST derive a peer's key from that peer's normalized id.
Counters. Each sender MUST maintain a monotonic per-frame counter seeding the GCM nonce, carried in the SFrame header (see sframe-media). The counter MUST NOT repeat under a given sender key.
Notes. SFrame derivation differs from 1:1 E2E-SRTP: SFrame splits callKey into 16-byte
salt + 16-byte IKM (E2E-SRTP uses a 32-byte zero salt and the whole callKey as IKM);
SFrame uses AES-128-GCM with a 16-byte nonce (E2E-SRTP uses AES-128-CTR).
Requires: call-offer, group-call, srtp-master-key, sframe-media
Implemented by
| Flavor | Status | Source | Notes |
|---|---|---|---|
whatsapp-rust |
working | — | — |
zapo-caller |
working | — | — |
meowcaller |
planned | — | — |
Annotation wacrg:CRY-06 — a flavor marks its implementation site in source with this comment; a script clones the source, finds it, and attaches the commit blame/permalink.
Contributors
| Contributor | Role |
|---|---|
| wrote initial spec |
protocol history / diff - blame
Open questions - How a new participant joining mid-call obtains the existing callKey, and whether the callKey is rotated on membership change (join/leave). - Whether a non-zero SFrame key_id is ever used for in-call key rotation, or it is always 0. - Exact participant-id form (LID vs PN, device-suffix rules) used by the signaling layer to address each sender across all client versions.
References - RFC 5869 — HKDF - RFC 9605 — SFrame
Changelog¶
- 2026-06-21 — Initial spec entry.