Skip to main content

rtc_srtp/context/
mod.rs

1#[cfg(test)]
2mod context_test;
3#[cfg(test)]
4mod srtcp_test;
5#[cfg(test)]
6mod srtp_test;
7
8use std::collections::HashMap;
9
10use shared::replay_detector::*;
11
12use crate::cipher::cipher_aead_aes_gcm::*;
13use crate::cipher::cipher_aes_cm_hmac_sha1::*;
14use crate::cipher::*;
15use crate::option::*;
16use crate::protection_profile::*;
17use shared::error::{Error, Result};
18
19/// SRTCP protection and unprotection.
20pub mod srtcp;
21/// SRTP protection and unprotection.
22pub mod srtp;
23
24const MAX_ROC: u32 = u32::MAX;
25const SEQ_NUM_MEDIAN: u16 = 1 << 15;
26const SEQ_NUM_MAX: u16 = u16::MAX;
27
28/// Encrypt/Decrypt state for a single SRTP SSRC
29#[derive(Default)]
30pub(crate) struct SrtpSsrcState {
31    ssrc: u32,
32    index: u64,
33    rollover_has_processed: bool,
34    replay_detector: Option<Box<dyn ReplayDetector>>,
35}
36
37/// Encrypt/Decrypt state for a single SRTCP SSRC
38#[derive(Default)]
39pub(crate) struct SrtcpSsrcState {
40    srtcp_index: usize,
41    ssrc: u32,
42    replay_detector: Option<Box<dyn ReplayDetector>>,
43}
44
45impl SrtpSsrcState {
46    pub fn next_rollover_count(&self, sequence_number: u16) -> (u32, i32, bool) {
47        let local_roc = (self.index >> 16) as u32;
48        let local_seq = self.index as u16;
49
50        let mut guess_roc = local_roc;
51
52        let diff = if self.rollover_has_processed {
53            let seq = (sequence_number as i32).wrapping_sub(local_seq as i32);
54            // When local_roc is equal to 0, and entering seq-local_seq > SEQ_NUM_MEDIAN
55            // judgment, it will cause guess_roc calculation error
56            if self.index > SEQ_NUM_MEDIAN as _ {
57                if local_seq < SEQ_NUM_MEDIAN {
58                    if seq > SEQ_NUM_MEDIAN as i32 {
59                        guess_roc = local_roc.wrapping_sub(1);
60                        seq.wrapping_sub(SEQ_NUM_MAX as i32 + 1)
61                    } else {
62                        seq
63                    }
64                } else if local_seq - SEQ_NUM_MEDIAN > sequence_number {
65                    guess_roc = local_roc.wrapping_add(1);
66                    seq.wrapping_add(SEQ_NUM_MAX as i32 + 1)
67                } else {
68                    seq
69                }
70            } else {
71                // local_roc is equal to 0
72                seq
73            }
74        } else {
75            0i32
76        };
77
78        (guess_roc, diff, (guess_roc == 0 && local_roc == MAX_ROC))
79    }
80
81    /// https://tools.ietf.org/html/rfc3550#appendix-A.1
82    pub fn update_rollover_count(&mut self, sequence_number: u16, diff: i32) {
83        if !self.rollover_has_processed {
84            self.index |= sequence_number as u64;
85            self.rollover_has_processed = true;
86        } else {
87            self.index = self.index.wrapping_add(diff as _);
88        }
89    }
90}
91
92/// Context represents a SRTP cryptographic context
93/// Context can only be used for one-way operations
94/// it must either used ONLY for encryption or ONLY for decryption
95pub struct Context {
96    cipher: Box<dyn Cipher>,
97
98    srtp_ssrc_states: HashMap<u32, SrtpSsrcState>,
99    srtcp_ssrc_states: HashMap<u32, SrtcpSsrcState>,
100
101    new_srtp_replay_detector: ContextOption,
102    new_srtcp_replay_detector: ContextOption,
103}
104
105impl Context {
106    /// CreateContext creates a new SRTP Context
107    pub fn new(
108        master_key: &[u8],
109        master_salt: &[u8],
110        profile: ProtectionProfile,
111        srtp_ctx_opt: Option<ContextOption>,
112        srtcp_ctx_opt: Option<ContextOption>,
113    ) -> Result<Context> {
114        let key_len = profile.key_len();
115        let salt_len = profile.salt_len();
116
117        if master_key.len() != key_len {
118            return Err(Error::SrtpMasterKeyLength(key_len, master_key.len()));
119        } else if master_salt.len() != salt_len {
120            return Err(Error::SrtpSaltLength(salt_len, master_salt.len()));
121        }
122
123        let cipher: Box<dyn Cipher> = match profile {
124            ProtectionProfile::Aes128CmHmacSha1_32
125            | ProtectionProfile::Aes128CmHmacSha1_80
126            | ProtectionProfile::Aes256CmHmacSha1_80
127            | ProtectionProfile::Aes256CmHmacSha1_32 => {
128                Box::new(CipherAesCmHmacSha1::new(profile, master_key, master_salt)?)
129            }
130
131            ProtectionProfile::AeadAes128Gcm | ProtectionProfile::AeadAes256Gcm => {
132                // `CipherAeadAesGcm::new` selects AES-128 vs AES-256 from the
133                // profile itself, so both GCM profiles share one arm.
134                Box::new(CipherAeadAesGcm::new(profile, master_key, master_salt)?)
135            }
136        };
137
138        let srtp_ctx_opt = if let Some(ctx_opt) = srtp_ctx_opt {
139            ctx_opt
140        } else {
141            srtp_no_replay_protection()
142        };
143
144        let srtcp_ctx_opt = if let Some(ctx_opt) = srtcp_ctx_opt {
145            ctx_opt
146        } else {
147            srtcp_no_replay_protection()
148        };
149
150        Ok(Context {
151            cipher,
152            srtp_ssrc_states: HashMap::new(),
153            srtcp_ssrc_states: HashMap::new(),
154            new_srtp_replay_detector: srtp_ctx_opt,
155            new_srtcp_replay_detector: srtcp_ctx_opt,
156        })
157    }
158
159    fn get_srtp_ssrc_state(&mut self, ssrc: u32) -> &mut SrtpSsrcState {
160        // `or_insert_with` so the replay detector (a boxed sliding-window
161        // detector backed by a heap-allocated bit buffer) is only constructed on
162        // the first packet for a given SSRC. `or_insert` would build — and then
163        // immediately drop — a fresh detector on every decrypted packet.
164        let new_srtp_replay_detector = &self.new_srtp_replay_detector;
165        self.srtp_ssrc_states
166            .entry(ssrc)
167            .or_insert_with(|| SrtpSsrcState {
168                ssrc,
169                replay_detector: Some(new_srtp_replay_detector()),
170                ..Default::default()
171            })
172    }
173
174    fn get_srtcp_ssrc_state(&mut self, ssrc: u32) -> &mut SrtcpSsrcState {
175        let new_srtcp_replay_detector = &self.new_srtcp_replay_detector;
176        self.srtcp_ssrc_states
177            .entry(ssrc)
178            .or_insert_with(|| SrtcpSsrcState {
179                ssrc,
180                replay_detector: Some(new_srtcp_replay_detector()),
181                ..Default::default()
182            })
183    }
184
185    /// roc returns SRTP rollover counter value of specified SSRC.
186    fn get_roc(&self, ssrc: u32) -> Option<u32> {
187        self.srtp_ssrc_states
188            .get(&ssrc)
189            .map(|s| (s.index >> 16) as _)
190    }
191
192    /// set_roc sets SRTP rollover counter value of specified SSRC.
193    fn set_roc(&mut self, ssrc: u32, roc: u32) {
194        let state = self.get_srtp_ssrc_state(ssrc);
195        state.index = (roc as u64) << 16;
196        state.rollover_has_processed = false;
197    }
198
199    /// index returns SRTCP index value of specified SSRC.
200    fn get_index(&self, ssrc: u32) -> Option<usize> {
201        self.srtcp_ssrc_states.get(&ssrc).map(|s| s.srtcp_index)
202    }
203
204    /// set_index sets SRTCP index value of specified SSRC.
205    fn set_index(&mut self, ssrc: u32, index: usize) {
206        self.get_srtcp_ssrc_state(ssrc).srtcp_index = index % (MAX_SRTCP_INDEX + 1);
207    }
208}