1use aes::cipher::BlockEncrypt;
2use aes::Aes256;
3use aes::{cipher::generic_array::GenericArray, Aes128};
4use aes_gcm::KeyInit;
5
6use crate::error::{Error, Result};
7
8pub const LABEL_SRTP_ENCRYPTION: u8 = 0x00;
9pub const LABEL_SRTP_AUTHENTICATION_TAG: u8 = 0x01;
10pub const LABEL_SRTP_SALT: u8 = 0x02;
11pub const LABEL_SRTCP_ENCRYPTION: u8 = 0x03;
12pub const LABEL_SRTCP_AUTHENTICATION_TAG: u8 = 0x04;
13pub const LABEL_SRTCP_SALT: u8 = 0x05;
14
15pub(crate) const SRTCP_INDEX_SIZE: usize = 4;
16
17pub(crate) fn aes_cm_key_derivation(
18 label: u8,
19 master_key: &[u8],
20 master_salt: &[u8],
21 index_over_kdr: usize,
22 out_len: usize,
23) -> Result<Vec<u8>> {
24 if index_over_kdr != 0 {
25 return Err(Error::UnsupportedIndexOverKdr);
27 }
28
29 let n_master_key = master_key.len();
35 let n_master_salt = master_salt.len();
36
37 let mut prf_in = vec![0u8; n_master_key];
38 prf_in[..n_master_salt].copy_from_slice(master_salt);
39
40 prf_in[7] ^= label;
41
42 let key = GenericArray::from_slice(master_key);
44 let block = Aes128::new(key);
45
46 let mut out = vec![0u8; ((out_len + n_master_key) / n_master_key) * n_master_key];
47 for (i, n) in (0..out_len).step_by(n_master_key).enumerate() {
48 prf_in[n_master_key - 2] = ((i >> 8) & 0xFF) as u8;
50 prf_in[n_master_key - 1] = (i & 0xFF) as u8;
51
52 out[n..n + n_master_key].copy_from_slice(&prf_in);
53 let out_key = GenericArray::from_mut_slice(&mut out[n..n + 16]);
54 block.encrypt_block(out_key);
55 }
56
57 Ok(out[..out_len].to_vec())
58}
59
60const AES_256_BS: usize = 16;
63pub(crate) fn aes_256_cm_key_derivation(
64 label: u8,
65 master_key: &[u8],
66 master_salt: &[u8],
67 index_over_kdr: usize,
68 out_len: usize,
69) -> Result<Vec<u8>> {
70 if index_over_kdr != 0 {
71 return Err(Error::UnsupportedIndexOverKdr);
73 }
74
75 if master_key.len() != 32 {
76 return Err(Error::InvalidMasterKeyLength);
77 }
78
79 if master_salt.len() > 14 {
80 return Err(Error::InvalidMasterSaltLength);
81 }
82
83 if out_len > 32 {
84 return Err(Error::UnsupportedOutLength);
85 }
86
87 let mut prf_in = [0; AES_256_BS];
88 prf_in[7] = label;
89 prf_in[8..12].copy_from_slice((index_over_kdr as u32).to_be_bytes().as_slice());
90
91 for (i, x) in prf_in.iter_mut().enumerate() {
92 *x ^= master_salt.get(i).unwrap_or(&0);
93 }
94
95 let key = GenericArray::from_slice(master_key);
97 let block = Aes256::new(key);
98
99 let mut out = vec![0u8; ((out_len + AES_256_BS) / AES_256_BS) * AES_256_BS];
100 for (i, n) in (0..out_len).step_by(AES_256_BS).enumerate() {
101 prf_in[AES_256_BS - 2..].copy_from_slice(&((i as u16).to_be_bytes()));
102
103 out[n..n + AES_256_BS].copy_from_slice(&prf_in);
104 let out_key = GenericArray::from_mut_slice(&mut out[n..n + 16]);
105 block.encrypt_block(out_key);
106 }
107
108 Ok(out[..out_len].to_vec())
109}
110
111pub(crate) fn generate_counter(
122 sequence_number: u16,
123 rollover_counter: u32,
124 ssrc: u32,
125 session_salt: &[u8],
126) -> [u8; 16] {
127 assert!(session_salt.len() <= 16);
128
129 let mut counter = [0; 16];
130
131 let ssrc_be = ssrc.to_be_bytes();
132 let rollover_be = rollover_counter.to_be_bytes();
133 let seq_be = ((sequence_number as u32) << 16).to_be_bytes();
134
135 counter[4..8].copy_from_slice(&ssrc_be);
136 counter[8..12].copy_from_slice(&rollover_be);
137 counter[12..16].copy_from_slice(&seq_be);
138
139 for i in 0..session_salt.len() {
140 counter[i] ^= session_salt[i];
141 }
142
143 counter
144}
145
146#[cfg(test)]
147mod test {
148 use super::*;
149 use crate::protection_profile::*;
150
151 #[test]
152 fn test_valid_session_keys() -> Result<()> {
153 let master_key = vec![
155 0xE1, 0xF9, 0x7A, 0x0D, 0x3E, 0x01, 0x8B, 0xE0, 0xD6, 0x4F, 0xA3, 0x2C, 0x06, 0xDE,
156 0x41, 0x39,
157 ];
158 let master_salt = vec![
159 0x0E, 0xC6, 0x75, 0xAD, 0x49, 0x8A, 0xFE, 0xEB, 0xB6, 0x96, 0x0B, 0x3A, 0xAB, 0xE6,
160 ];
161
162 let expected_session_key = vec![
163 0xC6, 0x1E, 0x7A, 0x93, 0x74, 0x4F, 0x39, 0xEE, 0x10, 0x73, 0x4A, 0xFE, 0x3F, 0xF7,
164 0xA0, 0x87,
165 ];
166 let expected_session_salt = vec![
167 0x30, 0xCB, 0xBC, 0x08, 0x86, 0x3D, 0x8C, 0x85, 0xD4, 0x9D, 0xB3, 0x4A, 0x9A, 0xE1,
168 ];
169 let expected_session_auth_tag = vec![
170 0xCE, 0xBE, 0x32, 0x1F, 0x6F, 0xF7, 0x71, 0x6B, 0x6F, 0xD4, 0xAB, 0x49, 0xAF, 0x25,
171 0x6A, 0x15, 0x6D, 0x38, 0xBA, 0xA4,
172 ];
173
174 let session_key = aes_cm_key_derivation(
175 LABEL_SRTP_ENCRYPTION,
176 &master_key,
177 &master_salt,
178 0,
179 master_key.len(),
180 )?;
181 assert_eq!(
182 session_key, expected_session_key,
183 "Session Key:\n{session_key:?} \ndoes not match expected:\n{expected_session_key:?}\nMaster Key:\n{master_key:?}\nMaster Salt:\n{master_salt:?}\n",
184 );
185
186 let session_salt = aes_cm_key_derivation(
187 LABEL_SRTP_SALT,
188 &master_key,
189 &master_salt,
190 0,
191 master_salt.len(),
192 )?;
193 assert_eq!(
194 session_salt, expected_session_salt,
195 "Session Salt {session_salt:?} does not match expected {expected_session_salt:?}"
196 );
197
198 let auth_key_len = ProtectionProfile::Aes128CmHmacSha1_80.auth_key_len();
199
200 let session_auth_tag = aes_cm_key_derivation(
201 LABEL_SRTP_AUTHENTICATION_TAG,
202 &master_key,
203 &master_salt,
204 0,
205 auth_key_len,
206 )?;
207 assert_eq!(
208 session_auth_tag, expected_session_auth_tag,
209 "Session Auth Tag {session_auth_tag:?} does not match expected {expected_session_auth_tag:?}",
210 );
211
212 Ok(())
213 }
214
215 #[test]
218 fn test_index_over_kdr() -> Result<()> {
219 let result = aes_cm_key_derivation(LABEL_SRTP_AUTHENTICATION_TAG, &[], &[], 1, 0);
220 assert!(result.is_err());
221
222 Ok(())
223 }
224
225 #[test]
226 fn test_aes_256_cm_key_derivation() -> Result<()> {
227 let master_key = vec![
229 0xF0, 0xF0, 0x49, 0x14, 0xB5, 0x13, 0xF2, 0x76, 0x3A, 0x1B, 0x1F, 0xA1, 0x30, 0xF1,
230 0x0E, 0x29, 0x98, 0xF6, 0xF6, 0xE4, 0x3E, 0x43, 0x09, 0xD1, 0xE6, 0x22, 0xA0, 0xE3,
231 0x32, 0xB9, 0xF1, 0xB6,
232 ];
233 let master_salt = vec![
234 0x3B, 0x04, 0x80, 0x3D, 0xE5, 0x1E, 0xE7, 0xC9, 0x64, 0x23, 0xAB, 0x5B, 0x78, 0xD2,
235 ];
236
237 let expected_session_key = vec![
238 0x5B, 0xA1, 0x06, 0x4E, 0x30, 0xEC, 0x51, 0x61, 0x3C, 0xAD, 0x92, 0x6C, 0x5A, 0x28,
239 0xEF, 0x73, 0x1E, 0xC7, 0xFB, 0x39, 0x7F, 0x70, 0xA9, 0x60, 0x65, 0x3C, 0xAF, 0x06,
240 0x55, 0x4C, 0xD8, 0xC4,
241 ];
242 let expected_session_salt = vec![
243 0xFA, 0x31, 0x79, 0x16, 0x85, 0xCA, 0x44, 0x4A, 0x9E, 0x07, 0xC6, 0xC6, 0x4E, 0x93,
244 ];
245 let expected_session_auth_tag = vec![
246 0xFD, 0x9C, 0x32, 0xD3, 0x9E, 0xD5, 0xFB, 0xB5, 0xA9, 0xDC, 0x96, 0xB3, 0x08, 0x18,
247 0x45, 0x4D, 0x13, 0x13, 0xDC, 0x05,
248 ];
249
250 let session_key = aes_256_cm_key_derivation(
251 LABEL_SRTP_ENCRYPTION,
252 &master_key,
253 &master_salt,
254 0,
255 master_key.len(),
256 )?;
257 assert_eq!(
258 session_key, expected_session_key,
259 "Session Key:\n{session_key:?} \ndoes not match expected:\n{expected_session_key:?}\nMaster Key:\n{master_key:?}\nMaster Salt:\n{master_salt:?}\n",
260 );
261
262 let session_salt = aes_256_cm_key_derivation(
263 LABEL_SRTP_SALT,
264 &master_key,
265 &master_salt,
266 0,
267 master_salt.len(),
268 )?;
269 assert_eq!(
270 session_salt, expected_session_salt,
271 "Session Salt {session_salt:?} does not match expected {expected_session_salt:?}"
272 );
273
274 let auth_key_len = ProtectionProfile::Aes128CmHmacSha1_80.auth_key_len();
275
276 let session_auth_tag = aes_256_cm_key_derivation(
277 LABEL_SRTP_AUTHENTICATION_TAG,
278 &master_key,
279 &master_salt,
280 0,
281 auth_key_len,
282 )?;
283 assert_eq!(
284 session_auth_tag, expected_session_auth_tag,
285 "Session Auth Tag {session_auth_tag:?} does not match expected {expected_session_auth_tag:?}",
286 );
287
288 Ok(())
289 }
290}