srt_protocol/settings/
encryption.rs

1use std::fmt::{self, Debug, Display, Formatter};
2
3pub use crate::{
4    options::{KeySize, Passphrase},
5    packet::{DataEncryption, KeyingMaterialMessage},
6    protocol::encryption::{
7        key::WrapInitializationVector,
8        key::{EncryptionKey, Salt},
9        stream::{KeyMaterialError, StreamEncryptionKeys},
10    },
11};
12
13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct KeySettings {
15    pub key_size: KeySize,
16    pub passphrase: Passphrase,
17}
18
19// https://datatracker.ietf.org/doc/html/draft-sharabayko-srt-00#section-6
20// https://github.com/Haivision/srt/blob/master/docs/features/encryption.md
21#[derive(Clone, Debug, Eq, PartialEq)]
22pub struct KeyMaterialRefreshSettings {
23    period: usize,
24
25    pre_announcement_period: usize,
26}
27
28impl Default for KeyMaterialRefreshSettings {
29    fn default() -> Self {
30        Self {
31            pre_announcement_period: 4_000,
32            period: 1 << 25, // 2^25
33        }
34    }
35}
36
37#[derive(Debug, Eq, PartialEq)]
38pub struct KeyMaterialRefreshSettingsError(usize, usize);
39
40impl Display for KeyMaterialRefreshSettingsError {
41    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
42        write!(f, "KM Refresh Period ({}) must be non-zero and greater than 1/2 the KM Pre Announce Period ({}).", self.0, self.1)
43    }
44}
45
46impl KeyMaterialRefreshSettings {
47    pub fn new(
48        period: usize,
49        pre_announcement_period: usize,
50    ) -> Result<Self, KeyMaterialRefreshSettingsError> {
51        if period > 0 && period / pre_announcement_period >= 2 {
52            Ok(Self {
53                period,
54                pre_announcement_period,
55            })
56        } else {
57            Err(KeyMaterialRefreshSettingsError(
58                period,
59                pre_announcement_period,
60            ))
61        }
62    }
63
64    pub fn period(&self) -> usize {
65        self.period
66    }
67
68    pub fn pre_announcement_period(&self) -> usize {
69        self.pre_announcement_period
70    }
71
72    /// KM Refresh Period specifies the number of packets to be sent
73    /// before switching to the new SEK
74    ///
75    /// The recommended KM Refresh Period is after 2^25 packets encrypted
76    /// with the same SEK are sent.
77    pub fn with_period(self, period: usize) -> Result<Self, KeyMaterialRefreshSettingsError> {
78        Self::new(period, self.pre_announcement_period)
79    }
80
81    /// KM Pre-Announcement Period specifies when a new key is announced
82    /// in a number of packets before key switchover.  The same value is
83    /// used to determine when to decommission the old key after
84    /// switchover.
85    ///
86    /// The recommended KM Pre-Announcement Period is 4000 packets (i.e.
87    /// a new key is generated, wrapped, and sent at 2^25 minus 4000
88    /// packets; the old key is decommissioned at 2^25 plus 4000
89    /// packets).
90    pub fn with_pre_announcement_period(
91        self,
92        pre_announcement_period: usize,
93    ) -> Result<Self, KeyMaterialRefreshSettingsError> {
94        Self::new(self.period, pre_announcement_period)
95    }
96}
97
98#[derive(Clone, Debug, Eq, PartialEq)]
99pub struct CipherSettings {
100    pub key_settings: KeySettings,
101    pub key_refresh: KeyMaterialRefreshSettings,
102    pub stream_keys: StreamEncryptionKeys,
103}
104
105impl CipherSettings {
106    pub fn new_random(key_settings: &KeySettings, km_refresh: &KeyMaterialRefreshSettings) -> Self {
107        Self {
108            key_settings: key_settings.clone(),
109            key_refresh: km_refresh.clone(),
110            stream_keys: StreamEncryptionKeys::new_random(key_settings.key_size),
111        }
112    }
113
114    pub fn new(
115        key_settings: &KeySettings,
116        km_refresh: &KeyMaterialRefreshSettings,
117        key_material: &KeyingMaterialMessage,
118    ) -> Result<Self, KeyMaterialError> {
119        Ok(Self {
120            stream_keys: StreamEncryptionKeys::unwrap_from(key_settings, key_material)?,
121            key_settings: key_settings.clone(),
122            key_refresh: km_refresh.clone(),
123        })
124    }
125
126    pub fn wrap_keying_material(&self) -> Option<KeyingMaterialMessage> {
127        self.stream_keys.wrap_with(&self.key_settings)
128    }
129}