1use openmls_traits::crypto::OpenMlsCrypto;
2use openmls_traits::types::Ciphersuite;
3use tls_codec::{
4 Deserialize, Serialize, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
5};
6
7use super::{
8 codec::deserialize_ciphertext_content, mls_auth_content::FramedContentAuthData,
9 mls_auth_content_in::VerifiableAuthenticatedContentIn, mls_content_in::FramedContentBodyIn,
10};
11
12use crate::{
13 binary_tree::array_representation::LeafNodeIndex,
14 error::LibraryError,
15 framing::mls_content_in::FramedContentIn,
16 tree::{secret_tree::SecretType, sender_ratchet::SenderRatchetConfiguration},
17};
18
19use super::*;
20
21#[derive(
37 Debug, PartialEq, Eq, Clone, TlsSerialize, TlsSize, TlsDeserialize, TlsDeserializeBytes,
38)]
39pub struct PrivateMessageIn {
40 group_id: GroupId,
41 epoch: GroupEpoch,
42 content_type: ContentType,
43 authenticated_data: VLBytes,
44 encrypted_sender_data: VLBytes,
45 ciphertext: VLBytes,
46}
47
48pub(crate) struct DecryptedContent {
50 pub(crate) verifiable: VerifiableAuthenticatedContentIn,
51 #[cfg(feature = "virtual-clients-draft")]
52 pub(crate) emulator_sender_leaf_index: Option<LeafNodeIndex>,
53}
54
55impl PrivateMessageIn {
56 pub fn aad(&self) -> &[u8] {
60 self.authenticated_data.as_slice()
61 }
62
63 pub(crate) fn sender_data(
65 &self,
66 message_secrets: &MessageSecrets,
67 crypto: &impl OpenMlsCrypto,
68 ciphersuite: Ciphersuite,
69 ) -> Result<MlsSenderData, MessageDecryptionError> {
70 log::debug!("Decrypting PrivateMessage");
71 let sender_data_key = message_secrets
73 .sender_data_secret()
74 .derive_aead_key(crypto, ciphersuite, self.ciphertext.as_slice())
75 .map_err(LibraryError::unexpected_crypto_error)?;
76 let sender_data_nonce = message_secrets
78 .sender_data_secret()
79 .derive_aead_nonce(ciphersuite, crypto, self.ciphertext.as_slice())
80 .map_err(LibraryError::unexpected_crypto_error)?;
81 let mls_sender_data_aad =
83 MlsSenderDataAad::new(self.group_id.clone(), self.epoch, self.content_type);
84 let mls_sender_data_aad_bytes = mls_sender_data_aad
85 .tls_serialize_detached()
86 .map_err(LibraryError::missing_bound_check)?;
87 log_crypto!(
89 trace,
90 "Decryption key for sender data: {sender_data_key:x?}"
91 );
92 log_crypto!(trace, "Decryption of sender data mls_sender_data_aad_bytes: {mls_sender_data_aad_bytes:x?} - sender_data_nonce: {sender_data_nonce:x?}");
93 let sender_data_bytes = sender_data_key
94 .aead_open(
95 crypto,
96 self.encrypted_sender_data.as_slice(),
97 &mls_sender_data_aad_bytes,
98 &sender_data_nonce,
99 )
100 .map_err(|_| {
101 log::error!("Sender data decryption error");
102 MessageDecryptionError::AeadError
103 })?;
104 log::trace!(" Successfully decrypted sender data.");
105 MlsSenderData::tls_deserialize(&mut sender_data_bytes.as_slice())
106 .map_err(|_| MessageDecryptionError::MalformedContent)
107 }
108
109 #[inline]
112 fn decrypt(
113 &self,
114 crypto: &impl OpenMlsCrypto,
115 ratchet_key: AeadKey,
116 ratchet_nonce: &AeadNonce,
117 ) -> Result<PrivateMessageContentIn, MessageDecryptionError> {
118 let private_message_content_aad_bytes = PrivateContentAad {
120 group_id: self.group_id.clone(),
121 epoch: self.epoch,
122 content_type: self.content_type,
123 authenticated_data: VLByteSlice(self.authenticated_data.as_slice()),
124 }
125 .tls_serialize_detached()
126 .map_err(LibraryError::missing_bound_check)?;
127 log_crypto!(
129 trace,
130 "Decryption key for private message: {ratchet_key:x?}"
131 );
132 log_crypto!(trace, "Decryption of private message private_message_content_aad_bytes: {private_message_content_aad_bytes:x?} - ratchet_nonce: {ratchet_nonce:x?}");
133 log::trace!("Decrypting ciphertext {:x?}", self.ciphertext);
134 let private_message_content_bytes = ratchet_key
135 .aead_open(
136 crypto,
137 self.ciphertext.as_slice(),
138 &private_message_content_aad_bytes,
139 ratchet_nonce,
140 )
141 .map_err(|_| {
142 log::error!(" Ciphertext decryption error");
143 MessageDecryptionError::AeadError
144 })?;
145 log_content!(
146 trace,
147 " Successfully decrypted PublicMessage bytes: {:x?}",
148 private_message_content_bytes
149 );
150 deserialize_ciphertext_content(
151 &mut private_message_content_bytes.as_slice(),
152 self.content_type(),
153 )
154 .map_err(|_| MessageDecryptionError::MalformedContent)
155 }
156
157 #[allow(clippy::too_many_arguments)]
165 pub(crate) fn to_verifiable_content(
166 &self,
167 ciphersuite: Ciphersuite,
168 crypto: &impl OpenMlsCrypto,
169 message_secrets: &mut MessageSecrets,
170 sender_index: LeafNodeIndex,
171 sender_ratchet_configuration: &SenderRatchetConfiguration,
172 sender_data: MlsSenderData,
173 #[cfg(feature = "virtual-clients-draft")] emulator_ctx: Option<
174 &crate::framing::private_message::EmulatorReuseGuardCtx<'_>,
175 >,
176 ) -> Result<DecryptedContent, MessageDecryptionError> {
177 let secret_type = SecretType::from(&self.content_type);
178 let (ratchet_key, ratchet_nonce) = message_secrets
180 .secret_tree_mut()
181 .secret_for_decryption(
182 ciphersuite,
183 crypto,
184 sender_index,
185 secret_type,
186 sender_data.generation,
187 sender_ratchet_configuration,
188 )
189 .map_err(|e| {
190 log::error!(
191 " Ciphertext generation out of bounds {}\n\t{e:?}",
192 sender_data.generation
193 );
194 MessageDecryptionError::SecretTreeError(e)
195 })?;
196
197 #[cfg(feature = "virtual-clients-draft")]
200 let emulator_sender_leaf_index = if let Some(ctx) = emulator_ctx {
201 let prp_key = ctx.reuse_guard_secret.derive_prp_key(
202 crypto,
203 ctx.emulation_ciphersuite,
204 ratchet_nonce.raw_bytes(),
205 )?;
206 let x = crypto
207 .ff1_aes128_decrypt(
208 &prp_key,
209 u32::from_be_bytes(sender_data.reuse_guard.bytes()),
210 )
211 .map_err(|e| {
212 log::error!("vc: FF1 inversion of reuse_guard failed: {e:?}");
213 crate::components::vc_derivation_info::VirtualClientsError::CryptoError(
214 openmls_traits::types::CryptoError::CryptoLibraryError,
215 )
216 })?;
217 let n_e = u64::from(ctx.emulation_group_size.leaf_count());
218 if n_e == 0 {
219 log::error!("vc: emulation_group_size is zero (corrupt state)");
220 return Err(LibraryError::custom(
221 "EmulationEpochState has zero emulation_group_size",
222 )
223 .into());
224 }
225 Some(LeafNodeIndex::new((u64::from(x) % n_e) as u32))
226 } else {
227 None
228 };
229
230 let prepared_nonce = ratchet_nonce.xor_with_reuse_guard(&sender_data.reuse_guard);
232 let private_message_content = self.decrypt(crypto, ratchet_key, &prepared_nonce)?;
233
234 let sender = Sender::from_sender_data(sender_data);
236 log_content!(
237 trace,
238 " Successfully decoded PublicMessage with: {:x?}",
239 private_message_content.content
240 );
241
242 let verifiable = VerifiableAuthenticatedContentIn::new(
243 WireFormat::PrivateMessage,
244 FramedContentIn {
245 group_id: self.group_id.clone(),
246 epoch: self.epoch,
247 sender,
248 authenticated_data: self.authenticated_data.clone(),
249 body: private_message_content.content,
250 },
251 Some(message_secrets.serialized_context().to_vec()),
252 private_message_content.auth,
253 );
254 Ok(DecryptedContent {
255 verifiable,
256 #[cfg(feature = "virtual-clients-draft")]
257 emulator_sender_leaf_index,
258 })
259 }
260
261 pub fn group_id(&self) -> &GroupId {
263 &self.group_id
264 }
265
266 pub fn epoch(&self) -> GroupEpoch {
268 self.epoch
269 }
270
271 pub fn content_type(&self) -> ContentType {
273 self.content_type
274 }
275
276 #[cfg(test)]
278 pub(crate) fn set_ciphertext(&mut self, ciphertext: Vec<u8>) {
279 self.ciphertext = ciphertext.into();
280 }
281}
282
283#[derive(Debug, Clone)]
306pub(crate) struct PrivateMessageContentIn {
307 pub(crate) content: FramedContentBodyIn,
312 pub(crate) auth: FramedContentAuthData,
313}
314
315#[cfg(any(feature = "test-utils", test))]
318impl From<PrivateMessageIn> for PrivateMessage {
319 fn from(value: PrivateMessageIn) -> Self {
320 Self {
321 group_id: value.group_id,
322 epoch: value.epoch,
323 content_type: value.content_type,
324 authenticated_data: value.authenticated_data,
325 encrypted_sender_data: value.encrypted_sender_data,
326 ciphertext: value.ciphertext,
327 }
328 }
329}
330
331#[cfg(any(feature = "test-utils", test))]
332impl From<PrivateMessage> for PrivateMessageIn {
333 fn from(value: PrivateMessage) -> Self {
334 Self {
335 group_id: value.group_id,
336 epoch: value.epoch,
337 content_type: value.content_type,
338 authenticated_data: value.authenticated_data,
339 encrypted_sender_data: value.encrypted_sender_data,
340 ciphertext: value.ciphertext,
341 }
342 }
343}