After a long gap, an SRTP video stream resumes but the receiver discards every packet as an authentication failure; how can rollover-counter desynchronisation cause this, and how is it prevented?
answer
- the ROC is inside the tag input
- state moves only on a verified packet
- 2^15 packets of one-way loss
- late joiners and recreated contexts
- SRTCP still verifies: keys are fine
basics
~20 sSRTP's tag check depends on the rollover counter, which is never sent. If the receiver's ROC is wrong, every tag fails, and because ROC only advances on a verified packet, the receiver never recovers by itself.
solid answer
~50 sFor SRTP's default HMAC-SHA1 transform, the tag input is the authenticated portion of the packet concatenated with `ROC`, and the index also drives the keystream. A receiver whose `ROC` differs from the sender's computes the wrong tag for **every** packet. Because RFC 3711 updates `ROC` and `s_l` only after a packet authenticates, nothing ever authenticates and the state never corrects: 100% loss on that SSRC while the keys are fine. Causes: one-way loss of 2^15 packets or more while the sender kept sending; a receiver that dropped its crypto context and recreated it assuming ROC zero; a late joiner never told the current ROC; a sender that wrongly reset ROC at a re-key. Prevention: signal ROC to late joiners through key management, keep contexts alive, keep the initial SEQ in the lower half, and on SDES start a fresh context (new master key, ROC zero) whenever the media endpoint changes.
go deeper
Recall that SRTP's rollover counter is never sent, so both ends must agree on it, and that a disagreement makes packets fail authentication.
Explain why the ROC is in the tag input, why ROC only advances after authentication, and how those two rules together turn one wrong value into total loss.
Diagnose from signals: total failure on one SSRC, flat replay discards, SRTCP still verifying. Name the causes, from 2^15 one-way loss to recreated contexts and late joiners, and the fix for each.
Decide how a calling platform keeps ROC agreement across holds, relays, endpoint moves and late joiners, and whether bounded ROC trial is worth its small cost in forgery resistance.
## Why one wrong number kills the whole stream An SRTP packet's **48-bit index** is `i = 2^16 × ROC + SEQ`. The 16-bit `SEQ` is in the RTP header; the 32-bit **rollover counter** (ROC) is not — each end keeps its own copy. The receiver estimates the index from its stored ROC and `s_l` (the highest sequence number seen), choosing among ROC−1, ROC and ROC+1. The index is used in three places, and the ROC part matters in each: - **The authentication tag.** For SRTP the tag input is the authenticated portion — RTP header plus encrypted payload — concatenated with ROC. Wrong ROC, wrong tag. - **The keystream.** AES counter mode builds its starting block from the salting key, the SSRC and the index; the AES-GCM profiles of RFC 7714 build their 12-octet IV from SSRC, ROC and SEQ. - **Session keys**, when a non-zero key-derivation rate is configured, because derivation divides the index by that rate. Now the trap. RFC 3711 updates ROC and `s_l` **only after a packet has been authenticated**. That rule is what stops a forged packet from bumping the counter. But it also means that once the receiver's ROC is off by one, no packet ever authenticates, so the state never moves, so the next packet is estimated with the same wrong ROC. The stream is dead until something outside SRTP fixes it. ## The symptom | Signal | ROC desynchronisation | Wrong keys | Attack or corruption | |---|---|---|---| | Authentication failures on the SSRC | Every packet | Every packet | Scattered | | Replay discards | Flat | Flat | May spike | | SRTCP from the same master key | Still verifies | Fails too | Mostly verifies | | When it started | After a gap, a join or an endpoint change | From call setup or a re-key | Any time | The SRTCP row is the useful tell: SRTCP carries its own explicit index rather than an implied ROC, so if its packets authenticate while SRTP fails completely, the master key is right and the index is wrong. ## How the ROC gets out of step 1. **A long one-way gap.** RFC 3711 says synchronisation is lost only after **2^15 packets** (32,768) are lost or reordered. A receiver that stops receiving while the sender keeps transmitting crosses that line after about 65.5 seconds at 500 packets per second (32,768 ÷ 500), or about 10.9 minutes at 50 packets per second (32,768 ÷ 50 = 655 s). If the sender simply stopped during the gap, `SEQ` did not advance and nothing goes wrong. 2. **A recreated crypto context.** RFC 4568 (SDES) points out that ROC cannot be recovered once a context is removed, unless it is zero. Context removal follows the RTP member-table rules — an SRTCP BYE or an inactivity time-out — so a participant that wants its context kept MUST send SRTCP at regular intervals. A receiver that timed out a held call and rebuilt the context with ROC zero, while the sender's ROC is 3, fails everything. 3. **A late joiner.** RFC 3711: a receiver joining an ongoing session MUST be given the current ROC out of band, through key management. SDES has no way to signal ROC; it simply has no concept of a late joiner — each SSRC MUST start with ROC zero. 4. **A media endpoint that changed underneath.** A media relay or gateway that hands the stream to a different endpoint, which never held the old context, starts from the wrong ROC. RFC 4568 therefore requires a **new master key** whenever an offer or answer changes the media address or port, which creates a new context with ROC zero on both sides. 5. **A sender bug at re-key.** After a re-key ROC MUST NOT be reset to zero; a sender that resets it desynchronises every receiver. 6. **A random start near the wrap.** If the initial `SEQ` is near 65,535 and the first packets are lost across the wrap, the receiver misses the first ROC increment. RFC 4568 asks that the initial `SEQ` SHOULD be in 0..2^15−1. ## Prevention and recovery - **Signal, do not guess, for joiners:** give late joiners the current ROC through key management; under SDES, start a new context instead. - **Keep contexts alive** across holds with regular SRTCP, and do not expire an SRTP context on a timer shorter than the call's longest legitimate silence. - **Start a fresh crypto context** when the media endpoint changes — under SDES, a new master key in the new offer or answer — so both sides agree ROC is zero. A re-key inside an existing context keeps ROC running; it resets nothing. - **Bounded trial.** Some receivers try neighbouring ROC values when every tag fails. RFC 5764 notes, about trying several key sets, that each extra candidate weakens an n-bit tag by log2 of the number of candidates, and that the same trial technique is already used for rollover-counter management. Keep the number of candidates small. - **Monitor per SSRC**: a jump from zero to 100% authentication failure, with replay discards flat, is the signature to alert on.
- A call on hold for 15 minutes resumes silently in one direction. The holding side sent nothing during the hold. Is ROC desynchronisation likely?Not from the gap itself: if the sender sent nothing, SEQ did not advance and the receiver's estimate is still right. Look instead at whether either side discarded and rebuilt its crypto context during the hold, for example on an inactivity time-out without SRTCP keeping it alive, or whether a re-offer moved the media endpoint without a fresh master key.
- Why does RFC 3711 not let the receiver simply advance ROC when it sees a wrap, before checking the tag?Because the sequence number of an unverified packet is attacker-controlled. If ROC moved on an unauthenticated packet, one forged packet with a well-chosen sequence number could push the receiver's ROC ahead of the sender's and kill the stream. Updating only after authentication trades self-recovery for that protection.
saying these in an interview costs you the question
- The receiver re-learns the rollover counter from the next packet's header.
- A wrong ROC only breaks the replay window; the tag still verifies.
- Any long silence on a call desynchronises the ROC, even if nothing was sent.
- Re-keying resets the ROC to zero, so a re-key always fixes the stream.
- 100% authentication failure always means the two ends hold different keys.