srt_protocol/protocol/encryption/
stream.rs

1use std::fmt::Debug;
2
3use aes::cipher::StreamCipher;
4use cipher::KeyIvInit;
5
6type Aes128Ctr = ctr::Ctr64BE<aes::Aes128>;
7type Aes192Ctr = ctr::Ctr64BE<aes::Aes192>;
8type Aes256Ctr = ctr::Ctr64BE<aes::Aes256>;
9
10use crate::{
11    packet::*,
12    settings::{KeySettings, KeySize},
13};
14
15use super::key::*;
16
17#[derive(Debug, Eq, PartialEq)]
18pub enum KeyMaterialError {
19    NoKeys,
20    InvalidSaltLength,
21    InvalidKeyFlags(KeyFlags, KeySize, usize),
22    InvalidInitializationVector(WrapInitializationVector),
23    InvalidRefreshResponse(KeyingMaterialMessage),
24}
25
26#[derive(Clone, Debug, Eq, PartialEq)]
27pub struct StreamEncryptionKeys {
28    salt: Salt,
29    even_key: Option<EncryptionKey>,
30    odd_key: Option<EncryptionKey>,
31}
32
33impl StreamEncryptionKeys {
34    pub fn new(salt: Salt) -> Self {
35        Self {
36            salt,
37            even_key: None,
38            odd_key: None,
39        }
40    }
41
42    pub fn new_random(key_size: KeySize) -> Self {
43        Self {
44            salt: Salt::new_random(),
45            even_key: Some(EncryptionKey::new_random(key_size)),
46            odd_key: Some(EncryptionKey::new_random(key_size)),
47        }
48    }
49
50    pub fn commission_next_key(
51        &mut self,
52        active_sek: DataEncryption,
53        key_settings: &KeySettings,
54    ) -> Option<KeyingMaterialMessage> {
55        use DataEncryption::*;
56        let new_random_key = EncryptionKey::new_random;
57        match active_sek {
58            Even => self.odd_key = Some(new_random_key(key_settings.key_size)),
59            Odd => self.even_key = Some(new_random_key(key_settings.key_size)),
60            None => return Option::None,
61        }
62        self.wrap_with(key_settings)
63    }
64
65    pub fn first_active_sek(&self) -> DataEncryption {
66        if self.even_key.is_some() {
67            DataEncryption::Even
68        } else if self.odd_key.is_some() {
69            DataEncryption::Odd
70        } else {
71            DataEncryption::None
72        }
73    }
74
75    pub fn unwrap_from(
76        key_settings: &KeySettings,
77        key_material: &KeyingMaterialMessage,
78    ) -> Result<Self, KeyMaterialError> {
79        use KeyMaterialError::*;
80        // TODO: revisit errors, KeyingMaterialMessage has a lot of fields that ought be validated
81        let salt = Salt::try_from(key_material.salt.as_slice()).map_err(|_| InvalidSaltLength)?;
82        let kek = KeyEncryptionKey::new(key_settings, &salt);
83
84        if key_material.key_flags.bits().count_ones() as usize * key_settings.key_size.as_usize()
85            + 8
86            != key_material.wrapped_keys.len()
87        {
88            return Err(KeyMaterialError::InvalidKeyFlags(
89                key_material.key_flags,
90                key_settings.key_size,
91                key_material.wrapped_keys.len(),
92            ));
93        }
94
95        let wrapped_keys = key_material.wrapped_keys.as_slice();
96        let keys = kek
97            .decrypt_wrapped_keys(wrapped_keys)
98            .map_err(InvalidInitializationVector)?;
99
100        let key_flags = key_material.key_flags;
101        let key_size = kek.len();
102        let even_key = if key_flags.contains(KeyFlags::EVEN) {
103            Some(EncryptionKey::try_from(&keys[0..key_size]).unwrap())
104        } else {
105            None
106        };
107        let odd_key = if key_flags.contains(KeyFlags::ODD) {
108            Some(EncryptionKey::try_from(&keys[keys.len() - key_size..]).unwrap())
109        } else {
110            None
111        };
112
113        Ok(StreamEncryptionKeys {
114            salt,
115            even_key,
116            odd_key,
117        })
118    }
119
120    pub fn wrap_with(&self, key_settings: &KeySettings) -> Option<KeyingMaterialMessage> {
121        let kek = KeyEncryptionKey::new(key_settings, &self.salt);
122
123        let mut keys = Vec::new();
124        if let Some(k) = &self.even_key {
125            keys.extend(k.as_bytes());
126        }
127        if let Some(k) = &self.odd_key {
128            keys.extend(k.as_bytes());
129        }
130
131        let wrapped_keys = kek.encrypt_wrapped_keys(keys.as_slice());
132
133        Some(KeyingMaterialMessage {
134            pt: PacketType::KeyingMaterial,
135            key_flags: match (&self.even_key, &self.odd_key) {
136                (Some(_), Some(_)) => KeyFlags::EVEN | KeyFlags::ODD,
137                (Some(_), None) => KeyFlags::EVEN,
138                (None, Some(_)) => KeyFlags::ODD,
139                (None, None) => return None,
140            },
141            keki: 0, // xxx
142            cipher: CipherType::Ctr,
143            auth: Auth::None,
144            salt: self.salt.as_slice().to_vec(),
145            wrapped_keys,
146        })
147    }
148
149    pub fn decrypt(
150        &self,
151        sek_selection: DataEncryption,
152        seq_number: SeqNumber,
153        data: &mut [u8],
154    ) -> Option<usize> {
155        let sek = self.get_key(sek_selection)?;
156        let iv = self.salt.generate_strean_iv_for(seq_number);
157
158        let nonce = iv.as_bytes();
159        use EncryptionKey::*;
160        match sek {
161            Bytes16(key) => Aes128Ctr::new(key.into(), nonce[..].into()).apply_keystream(data),
162            Bytes24(key) => Aes192Ctr::new(key.into(), nonce[..].into()).apply_keystream(data),
163            Bytes32(key) => Aes256Ctr::new(key.into(), nonce[..].into()).apply_keystream(data),
164        };
165
166        Some(data.len())
167    }
168
169    pub fn encrypt(
170        &self,
171        sek_selection: DataEncryption,
172        seq_number: SeqNumber,
173        data: &mut [u8],
174    ) -> Option<usize> {
175        let sek = self.get_key(sek_selection)?;
176        let iv = self.salt.generate_strean_iv_for(seq_number);
177
178        let nonce = iv.as_bytes();
179        use EncryptionKey::*;
180        match sek {
181            Bytes16(key) => Aes128Ctr::new(key.into(), nonce[..].into()).apply_keystream(data),
182            Bytes24(key) => Aes192Ctr::new(key.into(), nonce[..].into()).apply_keystream(data),
183            Bytes32(key) => Aes256Ctr::new(key.into(), nonce[..].into()).apply_keystream(data),
184        };
185
186        Some(data.len())
187    }
188
189    fn get_key(&self, active: DataEncryption) -> Option<&EncryptionKey> {
190        use crate::packet::DataEncryption::*;
191        match active {
192            Even => self.even_key.as_ref(),
193            Odd => self.odd_key.as_ref(),
194            None => Option::None,
195        }
196    }
197}
198
199#[cfg(test)]
200mod test {
201    use super::*;
202    use assert_matches::assert_matches;
203
204    fn key_settings() -> KeySettings {
205        KeySettings {
206            key_size: KeySize::AES128,
207            passphrase: "password123".into(),
208        }
209    }
210
211    #[test]
212    fn wrap_keys() {
213        let salt = b"\x00\x00\x00\x00\x00\x00\x00\x00\x85\x2c\x3c\xcd\x02\x65\x1a\x22";
214        let stream_encryption = StreamEncryptionKeys {
215            salt: Salt::try_from(salt).unwrap(),
216            odd_key: None,
217            even_key: EncryptionKey::try_from(b"\r\xab\xc8n/2\xb4\xa7\xb9\xbb\xa2\xf31*\xe4\"")
218                .ok(),
219        };
220
221        let kek = KeyEncryptionKey::new(&key_settings(), &stream_encryption.salt);
222        assert_eq!(
223            kek.as_bytes(),
224            b"\xe9\xa0\xa4\x30\x2f\x59\xd0\x63\xc8\x83\x32\xbe\x35\x88\x82\x08"
225        );
226
227        let expected_wrapped_keys =
228            b"31ea\x11\xe8\xb0P\xfe\x99\x9f\xd5h\xc2b\xfb\x1a3\xcc\xc8\x9cNw\xca";
229        let expected_keying_material = KeyingMaterialMessage {
230            pt: PacketType::KeyingMaterial,
231            key_flags: KeyFlags::EVEN,
232            keki: 0,
233            cipher: CipherType::Ctr,
234            auth: Auth::None,
235            salt: salt.to_vec(),
236            wrapped_keys: expected_wrapped_keys.to_vec(),
237        };
238
239        let keying_material = stream_encryption.wrap_with(&key_settings());
240        assert_eq!(
241            &keying_material.as_ref().unwrap().wrapped_keys[..],
242            &expected_wrapped_keys[..]
243        );
244
245        assert_eq!(keying_material.unwrap(), expected_keying_material);
246    }
247
248    #[test]
249    fn bad_password() {
250        let key_settings = &KeySettings {
251            key_size: KeySize::AES128,
252            passphrase: "badpassword".into(),
253        };
254        let key_material = KeyingMaterialMessage {
255            pt: PacketType::KeyingMaterial,
256            key_flags: KeyFlags::ODD,
257            keki: 0,
258            cipher: CipherType::Ctr,
259            auth: Auth::None,
260            salt: b"\x00\x00\x00\x00\x00\x00\x00\x00\x85\x2c\x3c\xcd\x02\x65\x1a\x22"[..].into(),
261            wrapped_keys: b"31ea\x11\xe8\xb0P\xfe\x99\x9f\xd5h\xc2b\xfb\x1a3\xcc\xc8\x9cNw\xca"[..]
262                .into(),
263        };
264
265        let res = StreamEncryptionKeys::unwrap_from(key_settings, &key_material);
266
267        assert_matches!(res, Err(_));
268    }
269
270    #[test]
271    fn wrap_key2() {
272        let salt = b"\x00\x00\x00\x00\x00\x00\x00\x00n\xd5+\x196\nq8";
273        let stream_encryption = StreamEncryptionKeys {
274            salt: Salt::try_from(salt).unwrap(),
275            odd_key: EncryptionKey::try_from(b"\r\xab\xc8n/2\xb4\xa7\xb9\xbb\xa2\xf31*\xe4\"").ok(),
276            even_key: None,
277        };
278
279        let kek = KeyEncryptionKey::new(&key_settings(), &stream_encryption.salt);
280        assert_eq!(
281            kek.as_bytes(),
282            b"\xde#\x1b\xfd9\x93z\xfb\xc3w\xa7\x80\xee\x80'\xa3"
283        );
284
285        let keying_material = KeyingMaterialMessage {
286            pt: PacketType::KeyingMaterial,
287            key_flags: KeyFlags::ODD,
288            keki: 0,
289            cipher: CipherType::Ctr,
290            auth: Auth::None,
291            salt: salt.to_vec(),
292            wrapped_keys: b"U\x06\xe9\xfd\xdfd\xf1'nr\xf4\xe9f\x81#(\xb7\xb5D\x19{\x9b\xcdx"
293                .to_vec(),
294        };
295
296        let stream_encryption =
297            StreamEncryptionKeys::unwrap_from(&key_settings(), &keying_material).unwrap();
298
299        assert_eq!(
300            stream_encryption.wrap_with(&key_settings()),
301            Some(keying_material)
302        );
303    }
304}