1use openmls_traits::crypto::OpenMlsCrypto;
9use std::collections::VecDeque;
10
11use openmls_traits::types::Ciphersuite;
12
13use crate::ciphersuite::{AeadNonce, *};
14use crate::tree::secret_tree::*;
15
16use super::*;
17
18pub(crate) type Generation = u32;
20#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
33pub struct SenderRatchetConfiguration {
34 out_of_order_tolerance: Generation,
35 maximum_forward_distance: Generation,
36}
37
38impl SenderRatchetConfiguration {
39 pub fn new(out_of_order_tolerance: Generation, maximum_forward_distance: Generation) -> Self {
41 Self {
42 out_of_order_tolerance,
43 maximum_forward_distance,
44 }
45 }
46 pub fn out_of_order_tolerance(&self) -> Generation {
48 self.out_of_order_tolerance
49 }
50
51 pub fn maximum_forward_distance(&self) -> Generation {
53 self.maximum_forward_distance
54 }
55}
56
57impl Default for SenderRatchetConfiguration {
58 fn default() -> Self {
59 Self::new(5, 1000)
60 }
61}
62
63pub(crate) type RatchetKeyMaterial = (AeadKey, AeadNonce);
66
67#[derive(Serialize, Deserialize)]
74#[cfg_attr(any(feature = "test-utils", test), derive(PartialEq, Clone))]
75#[cfg_attr(any(feature = "crypto-debug", test), derive(Debug))]
76pub(crate) enum SenderRatchet {
77 EncryptionRatchet(RatchetSecret),
78 DecryptionRatchet(DecryptionRatchet),
79}
80
81impl SenderRatchet {
82 #[cfg(test)]
83 pub(crate) fn generation(&self) -> Generation {
84 match self {
85 SenderRatchet::EncryptionRatchet(enc_ratchet) => enc_ratchet.generation(),
86 SenderRatchet::DecryptionRatchet(dec_ratchet) => dec_ratchet.generation(),
87 }
88 }
89}
90
91#[derive(Debug, Serialize, Deserialize, Default)]
96#[cfg_attr(any(feature = "test-utils", test), derive(PartialEq, Clone))]
97pub(crate) struct RatchetSecret {
98 secret: Secret,
99 generation: Generation,
100}
101
102impl RatchetSecret {
103 pub(crate) fn initial_ratchet_secret(secret: Secret) -> Self {
106 Self {
107 secret,
108 generation: 0,
109 }
110 }
111
112 pub(crate) fn generation(&self) -> Generation {
114 self.generation
115 }
116
117 pub(crate) fn ratchet_forward(
120 &mut self,
121 crypto: &impl OpenMlsCrypto,
122 ciphersuite: Ciphersuite,
123 ) -> Result<(Generation, RatchetKeyMaterial), SecretTreeError> {
124 log::trace!("Ratcheting forward in generation {}.", self.generation);
125 log_crypto!(trace, " with secret {:x?}", self.secret);
126
127 if self.generation == u32::MAX {
129 return Err(SecretTreeError::RatchetTooLong);
130 }
131 let nonce = derive_tree_secret(
132 ciphersuite,
133 &self.secret,
134 "nonce",
135 self.generation,
136 ciphersuite.aead_nonce_length(),
137 crypto,
138 )?;
139 let key = derive_tree_secret(
140 ciphersuite,
141 &self.secret,
142 "key",
143 self.generation,
144 ciphersuite.aead_key_length(),
145 crypto,
146 )?;
147 self.secret = derive_tree_secret(
148 ciphersuite,
149 &self.secret,
150 "secret",
151 self.generation,
152 ciphersuite.hash_length(),
153 crypto,
154 )?;
155 let generation = self.generation;
156 self.generation += 1;
157 Ok((
158 generation,
159 (
160 AeadKey::from_secret(key, ciphersuite),
161 AeadNonce::from_secret(nonce),
162 ),
163 ))
164 }
165
166 #[cfg(test)]
167 pub(crate) fn set_generation(&mut self, generation: Generation) {
168 self.generation = generation
169 }
170}
171
172#[derive(Serialize, Deserialize)]
177#[cfg_attr(any(feature = "test-utils", test), derive(PartialEq, Clone))]
178#[cfg_attr(any(feature = "crypto-debug", test), derive(Debug))]
179pub struct DecryptionRatchet {
180 past_secrets: VecDeque<Option<RatchetKeyMaterial>>,
181 ratchet_head: RatchetSecret,
182}
183
184impl DecryptionRatchet {
185 pub(crate) fn new(secret: Secret) -> Self {
187 Self {
188 past_secrets: VecDeque::new(),
189 ratchet_head: RatchetSecret::initial_ratchet_secret(secret),
190 }
191 }
192
193 fn prune_past_secrets(&mut self, configuration: &SenderRatchetConfiguration) {
196 self.past_secrets
197 .truncate(configuration.out_of_order_tolerance() as usize)
198 }
199
200 pub(crate) fn generation(&self) -> Generation {
202 self.ratchet_head.generation()
203 }
204
205 #[cfg(test)]
206 pub(crate) fn ratchet_secret_mut(&mut self) -> &mut RatchetSecret {
207 &mut self.ratchet_head
208 }
209
210 pub(crate) fn secret_for_decryption(
213 &mut self,
214 ciphersuite: Ciphersuite,
215 crypto: &impl OpenMlsCrypto,
216 generation: Generation,
217 configuration: &SenderRatchetConfiguration,
218 ) -> Result<RatchetKeyMaterial, SecretTreeError> {
219 log::debug!("secret_for_decryption");
220 if self.generation() < u32::MAX - configuration.maximum_forward_distance()
222 && generation > self.generation() + configuration.maximum_forward_distance()
223 {
224 return Err(SecretTreeError::TooDistantInTheFuture);
225 }
226 if generation < self.generation()
228 && (self.generation() - generation) > configuration.out_of_order_tolerance()
229 {
230 log::error!(" Generation is too far in the past (broke out of order tolerance ({}) {generation} < {}).", configuration.out_of_order_tolerance(), self.generation());
231 return Err(SecretTreeError::TooDistantInThePast);
232 }
233 if generation >= self.generation() {
235 for _ in 0..(generation - self.generation()) {
237 let ratchet_secrets = {
239 self.ratchet_head
240 .ratchet_forward(crypto, ciphersuite)
241 .map(|(_, key_material)| key_material)
242 }?;
243 self.past_secrets.push_front(Some(ratchet_secrets));
245 }
246 let ratchet_secrets = {
247 self.ratchet_head
248 .ratchet_forward(crypto, ciphersuite)
249 .map(|(_, key_material)| key_material)
250 }?;
251 self.past_secrets.push_front(None);
253 self.prune_past_secrets(configuration);
254 Ok(ratchet_secrets)
255 } else {
256 let window_index = ((self.generation() - generation) as i32) - 1;
259 let index = if window_index >= 0 {
262 window_index as usize
263 } else {
264 log::error!(" Generation is too far in the past (not in the window).");
265 return Err(SecretTreeError::TooDistantInThePast);
266 };
267 self.past_secrets
269 .get_mut(index)
270 .ok_or(SecretTreeError::IndexOutOfBounds)?
271 .take()
275 .ok_or(SecretTreeError::SecretReuseError)
278 }
279 }
280}