Skip to content
File

Blob: firmware/vendor/str0m/src/crypto/srtp.rs

rust530 lines
1use std::fmt;
2 
3use self::aes_128_cm_sha1_80::AesKey;
4 
5use super::CryptoProvider;
6 
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum SrtpProfile {
9 #[cfg(feature = "_internal_test_exports")]
10 PassThrough,
11 Aes128CmSha1_80,
12 AeadAes128Gcm,
13 AeadAes256Gcm,
14}
15 
16#[allow(dead_code)]
17impl SrtpProfile {
18 // All the profiles we support, ordered from most preferred to least.
19 pub(crate) const ALL: &'static [SrtpProfile] = &[
20 SrtpProfile::AeadAes256Gcm,
21 SrtpProfile::AeadAes128Gcm,
22 SrtpProfile::Aes128CmSha1_80,
23 ];
24 
25 /// The length of keying material to extract from the DTLS session in bytes.
26 #[rustfmt::skip]
27 pub(crate) fn keying_material_len(&self) -> usize {
28 match self {
29 #[cfg(feature = "_internal_test_exports")]
30 SrtpProfile::PassThrough => 0,
31 // MASTER_KEY_LEN * 2 + MASTER_SALT * 2
32 // TODO: This is a duplication of info that is held in srtp.rs, because we
33 // don't want a dependency in that direction.
34 SrtpProfile::Aes128CmSha1_80 => 16 * 2 + 14 * 2,
35 SrtpProfile::AeadAes128Gcm => 16 * 2 + 12 * 2,
36 SrtpProfile::AeadAes256Gcm => 32 * 2 + 12 * 2,
37 }
38 }
39}
40 
41pub enum SrtpCrypto {
42 #[cfg(any(feature = "openssl", feature = "openssl-dimpl"))]
43 OpenSsl(super::ossl::OsslSrtpCryptoImpl),
44 #[cfg(not(any(feature = "openssl", feature = "openssl-dimpl")))]
45 OpenSsl(DummySrtpCryptoImpl),
46 #[cfg(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows"))]
47 WinCrypto(super::wincrypto::WinCryptoSrtpCryptoImpl),
48 #[cfg(not(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows")))]
49 WinCrypto(DummySrtpCryptoImpl),
50 #[cfg(feature = "dimpl")]
51 AwsLc(super::aws_lc::AwsLcImpl),
52 #[cfg(not(feature = "dimpl"))]
53 AwsLc(DummySrtpCryptoImpl),
54}
55 
56#[allow(clippy::unit_arg)]
57impl SrtpCrypto {
58 #[cfg(any(feature = "openssl", feature = "openssl-dimpl"))]
59 pub fn new_openssl() -> SrtpCrypto {
60 Self::OpenSsl(super::ossl::OsslSrtpCryptoImpl)
61 }
62 
63 #[cfg(not(any(feature = "openssl", feature = "openssl-dimpl")))]
64 pub fn new_openssl() -> SrtpCrypto {
65 Self::OpenSsl(DummySrtpCryptoImpl(CryptoProvider::OpenSsl))
66 }
67 
68 #[cfg(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows"))]
69 pub fn new_wincrypto() -> SrtpCrypto {
70 Self::WinCrypto(super::wincrypto::WinCryptoSrtpCryptoImpl)
71 }
72 
73 #[cfg(not(all(any(feature = "wincrypto", feature = "wincrypto-dimpl"), target_os = "windows")))]
74 pub fn new_wincrypto() -> SrtpCrypto {
75 Self::WinCrypto(DummySrtpCryptoImpl(CryptoProvider::WinCrypto))
76 }
77 
78 #[cfg(feature = "dimpl")]
79 pub fn new_rust_crypto() -> SrtpCrypto {
80 Self::AwsLc(super::aws_lc::AwsLcImpl)
81 }
82 
83 #[cfg(not(feature = "dimpl"))]
84 pub fn new_rust_crypto() -> SrtpCrypto {
85 Self::AwsLc(DummySrtpCryptoImpl(CryptoProvider::Dimpl))
86 }
87 
88 // TODO: Can we avoice dynamic dispatch in this signature? The parameters are:
89 // 1. As few "touch points" beteen rtp/srtp.rs and here as possible.
90 // 2. Clear contract towards the actual impl.
91 // 3. Choice of impl passed all the way from RtcConfig.
92 pub fn new_aes_128_cm_sha1_80(
93 &self,
94 key: AesKey,
95 encrypt: bool,
96 ) -> Box<dyn aes_128_cm_sha1_80::CipherCtx> {
97 match self {
98 SrtpCrypto::OpenSsl(v) => Box::new(v.new_aes_128_cm_sha1_80(key, encrypt)),
99 SrtpCrypto::WinCrypto(v) => Box::new(v.new_aes_128_cm_sha1_80(key, encrypt)),
100 SrtpCrypto::AwsLc(v) => Box::new(v.new_aes_128_cm_sha1_80(key, encrypt)),
101 }
102 }
103 
104 pub fn new_aead_aes_128_gcm(
105 &self,
106 key: aead_aes_128_gcm::AeadKey,
107 encrypt: bool,
108 ) -> Box<dyn aead_aes_128_gcm::CipherCtx> {
109 match self {
110 SrtpCrypto::OpenSsl(v) => Box::new(v.new_aead_aes_128_gcm(key, encrypt)),
111 SrtpCrypto::WinCrypto(v) => Box::new(v.new_aead_aes_128_gcm(key, encrypt)),
112 SrtpCrypto::AwsLc(v) => Box::new(v.new_aead_aes_128_gcm(key, encrypt)),
113 }
114 }
115 
116 pub fn new_aead_aes_256_gcm(
117 &self,
118 key: aead_aes_256_gcm::AeadKey,
119 encrypt: bool,
120 ) -> Box<dyn aead_aes_256_gcm::CipherCtx> {
121 match self {
122 SrtpCrypto::OpenSsl(v) => Box::new(v.new_aead_aes_256_gcm(key, encrypt)),
123 SrtpCrypto::WinCrypto(v) => Box::new(v.new_aead_aes_256_gcm(key, encrypt)),
124 SrtpCrypto::AwsLc(v) => Box::new(v.new_aead_aes_256_gcm(key, encrypt)),
125 }
126 }
127 
128 pub fn srtp_aes_128_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]) {
129 match self {
130 SrtpCrypto::OpenSsl(v) => v.srtp_aes_128_ecb_round(key, input, output),
131 SrtpCrypto::WinCrypto(v) => v.srtp_aes_128_ecb_round(key, input, output),
132 SrtpCrypto::AwsLc(v) => v.srtp_aes_128_ecb_round(key, input, output),
133 }
134 }
135 
136 pub fn srtp_aes_256_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]) {
137 match self {
138 SrtpCrypto::OpenSsl(v) => v.srtp_aes_256_ecb_round(key, input, output),
139 SrtpCrypto::WinCrypto(v) => v.srtp_aes_256_ecb_round(key, input, output),
140 SrtpCrypto::AwsLc(v) => v.srtp_aes_256_ecb_round(key, input, output),
141 }
142 }
143}
144 
145pub trait SrtpCryptoImpl {
146 type Aes128CmSha1_80: aes_128_cm_sha1_80::CipherCtx;
147 type AeadAes128Gcm: aead_aes_128_gcm::CipherCtx;
148 type AeadAes256Gcm: aead_aes_256_gcm::CipherCtx;
149 
150 fn new_aes_128_cm_sha1_80(&self, key: AesKey, encrypt: bool) -> Self::Aes128CmSha1_80 {
151 <Self::Aes128CmSha1_80 as aes_128_cm_sha1_80::CipherCtx>::new(key, encrypt)
152 }
153 
154 fn new_aead_aes_128_gcm(
155 &self,
156 key: aead_aes_128_gcm::AeadKey,
157 encrypt: bool,
158 ) -> Self::AeadAes128Gcm {
159 <Self::AeadAes128Gcm as aead_aes_128_gcm::CipherCtx>::new(key, encrypt)
160 }
161 
162 fn new_aead_aes_256_gcm(
163 &self,
164 key: aead_aes_256_gcm::AeadKey,
165 encrypt: bool,
166 ) -> Self::AeadAes256Gcm {
167 <Self::AeadAes256Gcm as aead_aes_256_gcm::CipherCtx>::new(key, encrypt)
168 }
169 
170 fn srtp_aes_128_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]);
171 
172 fn srtp_aes_256_ecb_round(&self, key: &[u8], input: &[u8], output: &mut [u8]);
173}
174 
175pub mod aes_128_cm_sha1_80 {
176 use std::panic::UnwindSafe;
177 
178 use subtle::ConstantTimeEq;
179 
180 use crate::crypto::CryptoError;
181 
182 pub const KEY_LEN: usize = 16;
183 pub const SALT_LEN: usize = 14;
184 pub const HMAC_KEY_LEN: usize = 20;
185 pub const HMAC_TAG_LEN: usize = 10;
186 pub type AesKey = [u8; 16];
187 pub type RtpSalt = [u8; 14];
188 pub type RtpIv = [u8; 16];
189 
190 pub trait CipherCtx: UnwindSafe + Send + Sync {
191 fn new(key: AesKey, encrypt: bool) -> Self
192 where
193 Self: Sized;
194 
195 fn encrypt(
196 &mut self,
197 iv: &RtpIv,
198 input: &[u8],
199 output: &mut [u8],
200 ) -> Result<(), CryptoError>;
201 
202 fn decrypt(
203 &mut self,
204 iv: &RtpIv,
205 input: &[u8],
206 output: &mut [u8],
207 ) -> Result<(), CryptoError>;
208 }
209 
210 pub fn rtp_hmac(key: &[u8], buf: &mut [u8], srtp_index: u64, hmac_start: usize) {
211 let roc = (srtp_index >> 16) as u32;
212 let tag = crate::crypto::sha1_hmac(key, &[&buf[..hmac_start], &roc.to_be_bytes()]);
213 buf[hmac_start..(hmac_start + HMAC_TAG_LEN)].copy_from_slice(&tag[0..HMAC_TAG_LEN]);
214 }
215 
216 pub fn rtp_verify(key: &[u8], buf: &[u8], srtp_index: u64, cmp: &[u8]) -> bool {
217 let roc = (srtp_index >> 16) as u32;
218 let tag = crate::crypto::sha1_hmac(key, &[buf, &roc.to_be_bytes()]);
219 
220 tag[0..HMAC_TAG_LEN].ct_eq(cmp).into()
221 }
222 
223 pub fn rtp_iv(salt: RtpSalt, ssrc: u32, srtp_index: u64) -> RtpIv {
224 let mut iv = [0; 16];
225 let ssrc_be = ssrc.to_be_bytes();
226 let srtp_be = srtp_index.to_be_bytes();
227 iv[4..8].copy_from_slice(&ssrc_be);
228 for i in 0..8 {
229 iv[i + 6] ^= srtp_be[i];
230 }
231 for i in 0..14 {
232 iv[i] ^= salt[i];
233 }
234 iv
235 }
236 
237 pub fn rtcp_hmac(key: &[u8], buf: &mut [u8], hmac_index: usize) {
238 let tag = crate::crypto::sha1_hmac(key, &[&buf[0..hmac_index]]);
239 
240 buf[hmac_index..(hmac_index + HMAC_TAG_LEN)].copy_from_slice(&tag[0..HMAC_TAG_LEN]);
241 }
242 
243 pub fn rtcp_verify(key: &[u8], buf: &[u8], cmp: &[u8]) -> bool {
244 let tag = crate::crypto::sha1_hmac(key, &[buf]);
245 
246 tag[0..HMAC_TAG_LEN].ct_eq(cmp).into()
247 }
248}
249 
250pub mod aead_aes_128_gcm {
251 use std::panic::UnwindSafe;
252 
253 use crate::crypto::CryptoError;
254 
255 pub const KEY_LEN: usize = 16;
256 pub const SALT_LEN: usize = 12;
257 pub const RTCP_AAD_LEN: usize = 12;
258 pub const TAG_LEN: usize = 16;
259 pub const IV_LEN: usize = 12;
260 pub type AeadKey = [u8; KEY_LEN];
261 pub type RtpSalt = [u8; SALT_LEN];
262 pub type RtpIv = [u8; SALT_LEN];
263 
264 pub trait CipherCtx: UnwindSafe + Send + Sync {
265 fn new(key: AeadKey, encrypt: bool) -> Self
266 where
267 Self: Sized;
268 
269 fn encrypt(
270 &mut self,
271 iv: &[u8; IV_LEN],
272 aad: &[u8],
273 input: &[u8],
274 output: &mut [u8],
275 ) -> Result<(), CryptoError>;
276 
277 fn decrypt(
278 &mut self,
279 iv: &[u8; IV_LEN],
280 aads: &[&[u8]],
281 input: &[u8],
282 output: &mut [u8],
283 ) -> Result<usize, CryptoError>;
284 }
285 
286 pub fn rtp_iv(salt: RtpSalt, ssrc: u32, roc: u32, seq: u16) -> RtpIv {
287 // See: https://www.rfc-editor.org/rfc/rfc7714#section-8.1
288 
289 // TODO: See if this is faster if rewritten for u128
290 let mut iv = [0; SALT_LEN];
291 
292 let ssrc_be = ssrc.to_be_bytes();
293 let roc_be = roc.to_be_bytes();
294 let seq_be = seq.to_be_bytes();
295 
296 iv[2..6].copy_from_slice(&ssrc_be);
297 iv[6..10].copy_from_slice(&roc_be);
298 iv[10..12].copy_from_slice(&seq_be);
299 
300 // XOR with salt
301 for i in 0..SALT_LEN {
302 iv[i] ^= salt[i];
303 }
304 
305 iv
306 }
307 
308 pub fn rtcp_iv(salt: RtpSalt, ssrc: u32, srtp_index: u32) -> RtpIv {
309 // See: https://www.rfc-editor.org/rfc/rfc7714#section-9.1
310 // TODO: See if this is faster if rewritten for u128
311 let mut iv = [0; SALT_LEN];
312 
313 let ssrc_be = ssrc.to_be_bytes();
314 let srtp_be = srtp_index.to_be_bytes();
315 
316 iv[2..6].copy_from_slice(&ssrc_be);
317 iv[8..12].copy_from_slice(&srtp_be);
318 
319 // XOR with salt
320 for i in 0..SALT_LEN {
321 iv[i] ^= salt[i];
322 }
323 
324 iv
325 }
326}
327 
328pub mod aead_aes_256_gcm {
329 use std::panic::UnwindSafe;
330 
331 use crate::crypto::CryptoError;
332 
333 pub const KEY_LEN: usize = 32;
334 pub const SALT_LEN: usize = 12;
335 pub const RTCP_AAD_LEN: usize = 12;
336 pub const TAG_LEN: usize = 16;
337 pub const IV_LEN: usize = 12;
338 pub type AeadKey = [u8; KEY_LEN];
339 pub type RtpSalt = [u8; SALT_LEN];
340 pub type RtpIv = [u8; SALT_LEN];
341 
342 pub trait CipherCtx: UnwindSafe + Send + Sync {
343 fn new(key: AeadKey, encrypt: bool) -> Self
344 where
345 Self: Sized;
346 
347 fn encrypt(
348 &mut self,
349 iv: &[u8; IV_LEN],
350 aad: &[u8],
351 input: &[u8],
352 output: &mut [u8],
353 ) -> Result<(), CryptoError>;
354 
355 fn decrypt(
356 &mut self,
357 iv: &[u8; IV_LEN],
358 aads: &[&[u8]],
359 input: &[u8],
360 output: &mut [u8],
361 ) -> Result<usize, CryptoError>;
362 }
363 
364 pub fn rtp_iv(salt: RtpSalt, ssrc: u32, roc: u32, seq: u16) -> RtpIv {
365 // See: https://www.rfc-editor.org/rfc/rfc7714#section-8.1
366 
367 // TODO: See if this is faster if rewritten for u128
368 let mut iv = [0; SALT_LEN];
369 
370 let ssrc_be = ssrc.to_be_bytes();
371 let roc_be = roc.to_be_bytes();
372 let seq_be = seq.to_be_bytes();
373 
374 iv[2..6].copy_from_slice(&ssrc_be);
375 iv[6..10].copy_from_slice(&roc_be);
376 iv[10..12].copy_from_slice(&seq_be);
377 
378 // XOR with salt
379 for i in 0..SALT_LEN {
380 iv[i] ^= salt[i];
381 }
382 
383 iv
384 }
385 
386 pub fn rtcp_iv(salt: RtpSalt, ssrc: u32, srtp_index: u32) -> RtpIv {
387 // See: https://www.rfc-editor.org/rfc/rfc7714#section-9.1
388 // TODO: See if this is faster if rewritten for u128
389 let mut iv = [0; SALT_LEN];
390 
391 let ssrc_be = ssrc.to_be_bytes();
392 let srtp_be = srtp_index.to_be_bytes();
393 
394 iv[2..6].copy_from_slice(&ssrc_be);
395 iv[8..12].copy_from_slice(&srtp_be);
396 
397 // XOR with salt
398 for i in 0..SALT_LEN {
399 iv[i] ^= salt[i];
400 }
401 
402 iv
403 }
404}
405 
406impl fmt::Display for SrtpProfile {
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 match self {
409 #[cfg(feature = "_internal_test_exports")]
410 SrtpProfile::PassThrough => write!(f, "PassThrough"),
411 SrtpProfile::Aes128CmSha1_80 => write!(f, "SRTP_AES128_CM_SHA1_80"),
412 SrtpProfile::AeadAes128Gcm => write!(f, "SRTP_AEAD_AES_128_GCM"),
413 SrtpProfile::AeadAes256Gcm => write!(f, "SRTP_AEAD_AES_256_GCM"),
414 }
415 }
416}
417 
418pub struct DummySrtpCryptoImpl(CryptoProvider);
419 
420impl SrtpCryptoImpl for DummySrtpCryptoImpl {
421 type Aes128CmSha1_80 = ();
422 type AeadAes128Gcm = ();
423 type AeadAes256Gcm = ();
424 
425 fn new_aes_128_cm_sha1_80(&self, _: AesKey, _: bool) -> Self::Aes128CmSha1_80 {
426 panic!("Must enable feature: {}", self.0)
427 }
428 
429 fn new_aead_aes_128_gcm(&self, _: aead_aes_128_gcm::AeadKey, _: bool) -> Self::AeadAes128Gcm {
430 panic!("Must enable feature: {}", self.0)
431 }
432 
433 fn new_aead_aes_256_gcm(&self, _: aead_aes_256_gcm::AeadKey, _: bool) -> Self::AeadAes256Gcm {
434 panic!("Must enable feature: {}", self.0)
435 }
436 
437 fn srtp_aes_128_ecb_round(&self, _: &[u8], _: &[u8], _: &mut [u8]) {
438 panic!("Must enable feature: {}", self.0)
439 }
440 
441 fn srtp_aes_256_ecb_round(&self, _: &[u8], _: &[u8], _: &mut [u8]) {
442 panic!("Must enable feature: {}", self.0)
443 }
444}
445 
446impl aes_128_cm_sha1_80::CipherCtx for () {
447 fn new(_: AesKey, _: bool) -> Self
448 where
449 Self: Sized,
450 {
451 unreachable!()
452 }
453 
454 fn encrypt(
455 &mut self,
456 _: &aes_128_cm_sha1_80::RtpIv,
457 _: &[u8],
458 _: &mut [u8],
459 ) -> Result<(), super::CryptoError> {
460 unreachable!()
461 }
462 
463 fn decrypt(
464 &mut self,
465 _: &aes_128_cm_sha1_80::RtpIv,
466 _: &[u8],
467 _: &mut [u8],
468 ) -> Result<(), super::CryptoError> {
469 unreachable!()
470 }
471}
472 
473impl aead_aes_128_gcm::CipherCtx for () {
474 fn new(_: aead_aes_128_gcm::AeadKey, _: bool) -> Self
475 where
476 Self: Sized,
477 {
478 unreachable!()
479 }
480 
481 fn encrypt(
482 &mut self,
483 _: &[u8; aead_aes_128_gcm::IV_LEN],
484 _: &[u8],
485 _: &[u8],
486 _: &mut [u8],
487 ) -> Result<(), super::CryptoError> {
488 unreachable!()
489 }
490 
491 fn decrypt(
492 &mut self,
493 _: &[u8; aead_aes_128_gcm::IV_LEN],
494 _: &[&[u8]],
495 _: &[u8],
496 _: &mut [u8],
497 ) -> Result<usize, super::CryptoError> {
498 unreachable!()
499 }
500}
501 
502impl aead_aes_256_gcm::CipherCtx for () {
503 fn new(_: aead_aes_256_gcm::AeadKey, _: bool) -> Self
504 where
505 Self: Sized,
506 {
507 unreachable!()
508 }
509 
510 fn encrypt(
511 &mut self,
512 _: &[u8; aead_aes_256_gcm::IV_LEN],
513 _: &[u8],
514 _: &[u8],
515 _: &mut [u8],
516 ) -> Result<(), super::CryptoError> {
517 unreachable!()
518 }
519 
520 fn decrypt(
521 &mut self,
522 _: &[u8; aead_aes_256_gcm::IV_LEN],
523 _: &[&[u8]],
524 _: &[u8],
525 _: &mut [u8],
526 ) -> Result<usize, super::CryptoError> {
527 unreachable!()
528 }
529}