1use std::collections::VecDeque;
9
10use openmls_traits::crypto::OpenMlsCrypto;
11
12use openmls_traits::types::Ciphersuite;
13
14use crate::ciphersuite::{AeadNonce, *};
15#[cfg(feature = "virtual-clients-draft")]
16use crate::tree::dual_use_ratchet::DualUseRatchet;
17use crate::tree::secret_tree::*;
18
19use super::*;
20
21pub(crate) type Generation = u32;
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
36pub struct SenderRatchetConfiguration {
37 out_of_order_tolerance: Generation,
38 maximum_forward_distance: Generation,
39}
40
41impl SenderRatchetConfiguration {
42 pub fn new(out_of_order_tolerance: Generation, maximum_forward_distance: Generation) -> Self {
44 Self {
45 out_of_order_tolerance,
46 maximum_forward_distance,
47 }
48 }
49 pub fn out_of_order_tolerance(&self) -> Generation {
51 self.out_of_order_tolerance
52 }
53
54 pub fn maximum_forward_distance(&self) -> Generation {
56 self.maximum_forward_distance
57 }
58}
59
60impl Default for SenderRatchetConfiguration {
61 fn default() -> Self {
62 Self::new(5, 1000)
63 }
64}
65
66pub(crate) type RatchetKeyMaterial = (AeadKey, AeadNonce);
69
70#[derive(Serialize, Deserialize)]
80#[cfg_attr(any(feature = "test-utils", test), derive(PartialEq, Clone))]
81#[cfg_attr(any(feature = "crypto-debug", test), derive(Debug))]
82pub(crate) enum SenderRatchet {
83 EncryptionRatchet(RatchetSecret),
84 DecryptionRatchet(DecryptionRatchet),
85 #[cfg(feature = "virtual-clients-draft")]
86 DualUse(DualUseRatchet),
87}
88
89impl SenderRatchet {
90 #[cfg(test)]
91 pub(crate) fn generation(&self) -> Generation {
92 match self {
93 SenderRatchet::EncryptionRatchet(enc_ratchet) => enc_ratchet.generation(),
94 SenderRatchet::DecryptionRatchet(dec_ratchet) => dec_ratchet.generation(),
95 #[cfg(feature = "virtual-clients-draft")]
96 SenderRatchet::DualUse(dual_ratchet) => dual_ratchet.generation(),
97 }
98 }
99}
100
101#[derive(Debug, Serialize, Deserialize, Default)]
106#[cfg_attr(any(feature = "test-utils", test), derive(PartialEq, Clone))]
107pub(crate) struct RatchetSecret {
108 secret: Secret,
109 generation: Generation,
110}
111
112impl RatchetSecret {
113 pub(crate) fn initial_ratchet_secret(secret: Secret) -> Self {
116 Self {
117 secret,
118 generation: 0,
119 }
120 }
121
122 pub(crate) fn generation(&self) -> Generation {
124 self.generation
125 }
126
127 pub(crate) fn ratchet_forward(
130 &mut self,
131 crypto: &impl OpenMlsCrypto,
132 ciphersuite: Ciphersuite,
133 ) -> Result<(Generation, RatchetKeyMaterial), SecretTreeError> {
134 log::trace!("Ratcheting forward in generation {}.", self.generation);
135 log_crypto!(trace, " with secret {:x?}", self.secret);
136
137 if self.generation == u32::MAX {
139 return Err(SecretTreeError::RatchetTooLong);
140 }
141 let nonce = derive_tree_secret(
142 ciphersuite,
143 &self.secret,
144 "nonce",
145 self.generation,
146 ciphersuite.aead_nonce_length(),
147 crypto,
148 )?;
149 let key = derive_tree_secret(
150 ciphersuite,
151 &self.secret,
152 "key",
153 self.generation,
154 ciphersuite.aead_key_length(),
155 crypto,
156 )?;
157 self.secret = derive_tree_secret(
158 ciphersuite,
159 &self.secret,
160 "secret",
161 self.generation,
162 ciphersuite.hash_length(),
163 crypto,
164 )?;
165 let generation = self.generation;
166 self.generation += 1;
167 Ok((
168 generation,
169 (
170 AeadKey::from_secret(key, ciphersuite),
171 AeadNonce::from_secret(nonce),
172 ),
173 ))
174 }
175
176 #[cfg(test)]
177 pub(crate) fn set_generation(&mut self, generation: Generation) {
178 self.generation = generation
179 }
180}
181
182#[derive(Serialize, Deserialize)]
187#[cfg_attr(any(feature = "test-utils", test), derive(PartialEq, Clone))]
188#[cfg_attr(any(feature = "crypto-debug", test), derive(Debug))]
189pub struct DecryptionRatchet {
190 past_secrets: VecDeque<Option<RatchetKeyMaterial>>,
191 ratchet_head: RatchetSecret,
192}
193
194impl DecryptionRatchet {
195 pub(crate) fn new(secret: Secret) -> Self {
197 Self {
198 past_secrets: VecDeque::new(),
199 ratchet_head: RatchetSecret::initial_ratchet_secret(secret),
200 }
201 }
202
203 #[cfg(test)]
205 pub(crate) fn generation(&self) -> Generation {
206 self.ratchet_head.generation()
207 }
208
209 #[cfg(test)]
210 pub(crate) fn ratchet_secret_mut(&mut self) -> &mut RatchetSecret {
211 &mut self.ratchet_head
212 }
213
214 pub(crate) fn secret_for_decryption(
217 &mut self,
218 ciphersuite: Ciphersuite,
219 crypto: &impl OpenMlsCrypto,
220 generation: Generation,
221 configuration: &SenderRatchetConfiguration,
222 ) -> Result<RatchetKeyMaterial, SecretTreeError> {
223 log::debug!("secret_for_decryption");
224 let head_generation = self.ratchet_head.generation();
225 if head_generation < u32::MAX - configuration.maximum_forward_distance()
227 && generation > head_generation + configuration.maximum_forward_distance()
228 {
229 return Err(SecretTreeError::TooDistantInTheFuture);
230 }
231 if generation < head_generation
233 && (head_generation - generation) > configuration.out_of_order_tolerance()
234 {
235 log::error!(" Generation is too far in the past (broke out of order tolerance ({}) {generation} < {head_generation}).", configuration.out_of_order_tolerance());
236 return Err(SecretTreeError::TooDistantInThePast);
237 }
238 if generation >= head_generation {
240 for _ in 0..(generation - head_generation) {
242 let ratchet_secrets = self
244 .ratchet_head
245 .ratchet_forward(crypto, ciphersuite)
246 .map(|(_, key_material)| key_material)?;
247 self.past_secrets.push_front(Some(ratchet_secrets));
249 }
250 let ratchet_secrets = self
251 .ratchet_head
252 .ratchet_forward(crypto, ciphersuite)
253 .map(|(_, key_material)| key_material)?;
254 self.past_secrets.push_front(None);
256 self.past_secrets
257 .truncate(configuration.out_of_order_tolerance() as usize);
258 Ok(ratchet_secrets)
259 } else {
260 let window_index = ((head_generation - generation) as i32) - 1;
263 let index = if window_index >= 0 {
266 window_index as usize
267 } else {
268 log::error!(" Generation is too far in the past (not in the window).");
269 return Err(SecretTreeError::TooDistantInThePast);
270 };
271 self.past_secrets
273 .get_mut(index)
274 .ok_or(SecretTreeError::IndexOutOfBounds)?
275 .take()
279 .ok_or(SecretTreeError::SecretReuseError)
282 }
283 }
284}