Skip to content
File

Blob: firmware/crates/esp32-radio/src/platform/crypto/srtp.rs

rust152 lines
1use super::{key::Key, native};
2use radio_webrtc::crypto::{
3 AeadAes128GcmCipher, AeadAes256GcmCipher, Aes128CmSha1_80Cipher, CryptoError, SrtpProvider,
4 SupportedAeadAes128Gcm, SupportedAeadAes256Gcm, SupportedAes128CmSha1_80,
5};
6 
7#[derive(Debug)]
8pub(super) struct Provider;
9#[derive(Debug)]
10struct Cipher(Key);
11 
12fn failed() -> CryptoError {
13 CryptoError::Other("ESP-IDF AES operation failed".into())
14}
15 
16impl Aes128CmSha1_80Cipher for Cipher {
17 fn encrypt(&mut self, iv: &[u8; 16], input: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
18 native::ctr(self.0.bytes(), iv, input, out).map_err(|_| failed())
19 }
20 fn decrypt(&mut self, iv: &[u8; 16], input: &[u8], out: &mut [u8]) -> Result<(), CryptoError> {
21 Aes128CmSha1_80Cipher::encrypt(self, iv, input, out)
22 }
23}
24 
25impl Cipher {
26 fn encrypt_gcm(
27 &self,
28 iv: &[u8; 12],
29 aad: &[u8],
30 input: &[u8],
31 out: &mut [u8],
32 ) -> Result<(), CryptoError> {
33 native::gcm(false, self.0.bytes(), iv, aad, input, out).map_err(|_| failed())
34 }
35 fn decrypt_gcm(
36 &self,
37 iv: &[u8; 12],
38 aads: &[&[u8]],
39 input: &[u8],
40 out: &mut [u8],
41 ) -> Result<usize, CryptoError> {
42 let clear = input.len().checked_sub(16).ok_or_else(failed)?;
43 // SRTP may supply the header and rollover counter as separate AAD parts.
44 let joined;
45 let aad = if let [one] = aads {
46 *one
47 } else {
48 joined = aads.concat();
49 &joined
50 };
51 native::gcm(true, self.0.bytes(), iv, aad, input, out).map_err(|_| failed())?;
52 Ok(clear)
53 }
54}
55impl AeadAes128GcmCipher for Cipher {
56 fn encrypt(
57 &mut self,
58 iv: &[u8; 12],
59 aad: &[u8],
60 input: &[u8],
61 out: &mut [u8],
62 ) -> Result<(), CryptoError> {
63 self.encrypt_gcm(iv, aad, input, out)
64 }
65 fn decrypt(
66 &mut self,
67 iv: &[u8; 12],
68 aads: &[&[u8]],
69 input: &[u8],
70 out: &mut [u8],
71 ) -> Result<usize, CryptoError> {
72 self.decrypt_gcm(iv, aads, input, out)
73 }
74}
75impl AeadAes256GcmCipher for Cipher {
76 fn encrypt(
77 &mut self,
78 iv: &[u8; 12],
79 aad: &[u8],
80 input: &[u8],
81 out: &mut [u8],
82 ) -> Result<(), CryptoError> {
83 self.encrypt_gcm(iv, aad, input, out)
84 }
85 fn decrypt(
86 &mut self,
87 iv: &[u8; 12],
88 aads: &[&[u8]],
89 input: &[u8],
90 out: &mut [u8],
91 ) -> Result<usize, CryptoError> {
92 self.decrypt_gcm(iv, aads, input, out)
93 }
94}
95 
96impl SupportedAes128CmSha1_80 for Provider {
97 fn create_cipher(&self, key: [u8; 16], _encrypt: bool) -> Box<dyn Aes128CmSha1_80Cipher> {
98 Box::new(Cipher(Key::new(&key).expect("AES-128 key")))
99 }
100}
101impl SupportedAeadAes128Gcm for Provider {
102 fn create_cipher(&self, key: [u8; 16], _encrypt: bool) -> Box<dyn AeadAes128GcmCipher> {
103 Box::new(Cipher(Key::new(&key).expect("AES-128 key")))
104 }
105}
106impl SupportedAeadAes256Gcm for Provider {
107 fn create_cipher(&self, key: [u8; 32], _encrypt: bool) -> Box<dyn AeadAes256GcmCipher> {
108 Box::new(Cipher(Key::new(&key).expect("AES-256 key")))
109 }
110}
111 
112fn ecb_round(key: &[u8], input: &[u8], out: &mut [u8]) -> Result<(), ()> {
113 // Match the upstream helper's two-block result, including PKCS#7 padding.
114 let input: &[u8; 16] = input.try_into().map_err(|_| ())?;
115 if out.len() < 32 {
116 return Err(());
117 }
118 let mut first = [0; 16];
119 let mut padding = [0; 16];
120 native::ecb(key, input, &mut first)?;
121 native::ecb(key, &[0x10; 16], &mut padding)?;
122 out[..16].copy_from_slice(&first);
123 out[16..32].copy_from_slice(&padding);
124 Ok(())
125}
126 
127impl SrtpProvider for Provider {
128 fn aes_128_cm_sha1_80(&self) -> &'static dyn SupportedAes128CmSha1_80 {
129 &Provider
130 }
131 fn aead_aes_128_gcm(&self) -> &'static dyn SupportedAeadAes128Gcm {
132 &Provider
133 }
134 fn aead_aes_256_gcm(&self) -> &'static dyn SupportedAeadAes256Gcm {
135 &Provider
136 }
137 fn srtp_aes_128_ecb_round(&self, key: &[u8], input: &[u8], out: &mut [u8]) {
138 if ecb_round(key, input, out).is_err() {
139 str0m_rust_crypto::default_provider()
140 .srtp_provider
141 .srtp_aes_128_ecb_round(key, input, out);
142 }
143 }
144 fn srtp_aes_256_ecb_round(&self, key: &[u8], input: &[u8], out: &mut [u8]) {
145 if ecb_round(key, input, out).is_err() {
146 str0m_rust_crypto::default_provider()
147 .srtp_provider
148 .srtp_aes_256_ecb_round(key, input, out);
149 }
150 }
151}