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
12#[cfg(feature = "virtual-clients-draft")]
13use crate::binary_tree::array_representation::LeafNodeIndex;
14use crate::{
15 error::LibraryError, framing::mls_content_in::FramedContentIn,
16 tree::sender_ratchet::RatchetKeyMaterial,
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 pub(crate) fn to_verifiable_content(
165 &self,
166 crypto: &impl OpenMlsCrypto,
167 message_secrets: &MessageSecrets,
168 ratchet_key_material: RatchetKeyMaterial,
169 sender_data: MlsSenderData,
170 #[cfg(feature = "virtual-clients-draft")] emulator_ctx: Option<
171 &crate::framing::private_message::EmulatorReuseGuardCtx<'_>,
172 >,
173 ) -> Result<DecryptedContent, MessageDecryptionError> {
174 let (ratchet_key, ratchet_nonce) = ratchet_key_material;
175
176 #[cfg(feature = "virtual-clients-draft")]
179 let emulator_sender_leaf_index = if let Some(ctx) = emulator_ctx {
180 let prp_key = ctx.reuse_guard_secret.derive_prp_key(
181 crypto,
182 ctx.emulation_ciphersuite,
183 ratchet_nonce.raw_bytes(),
184 )?;
185 let x = crypto
186 .ff1_aes128_decrypt(
187 &prp_key,
188 u32::from_be_bytes(sender_data.reuse_guard.bytes()),
189 )
190 .map_err(|e| {
191 log::error!("vc: FF1 inversion of reuse_guard failed: {e:?}");
192 crate::components::vc_derivation_info::VirtualClientsError::CryptoError(
193 openmls_traits::types::CryptoError::CryptoLibraryError,
194 )
195 })?;
196 let n_e = u64::from(ctx.emulation_group_size.leaf_count());
197 if n_e == 0 {
198 log::error!("vc: emulation_group_size is zero (corrupt state)");
199 return Err(LibraryError::custom(
200 "VcDerivationEpochState has zero emulation_group_size",
201 )
202 .into());
203 }
204 Some(LeafNodeIndex::new((u64::from(x) % n_e) as u32))
205 } else {
206 None
207 };
208
209 let prepared_nonce = ratchet_nonce.xor_with_reuse_guard(&sender_data.reuse_guard);
211 let private_message_content = self.decrypt(crypto, ratchet_key, &prepared_nonce)?;
212
213 let sender = Sender::from_sender_data(sender_data);
215 log_content!(
216 trace,
217 " Successfully decoded PublicMessage with: {:x?}",
218 private_message_content.content
219 );
220
221 let verifiable = VerifiableAuthenticatedContentIn::new(
222 WireFormat::PrivateMessage,
223 FramedContentIn {
224 group_id: self.group_id.clone(),
225 epoch: self.epoch,
226 sender,
227 authenticated_data: self.authenticated_data.clone(),
228 body: private_message_content.content,
229 },
230 Some(message_secrets.serialized_context().to_vec()),
231 private_message_content.auth,
232 );
233 Ok(DecryptedContent {
234 verifiable,
235 #[cfg(feature = "virtual-clients-draft")]
236 emulator_sender_leaf_index,
237 })
238 }
239
240 pub fn group_id(&self) -> &GroupId {
242 &self.group_id
243 }
244
245 pub fn epoch(&self) -> GroupEpoch {
247 self.epoch
248 }
249
250 pub fn content_type(&self) -> ContentType {
252 self.content_type
253 }
254
255 #[cfg(test)]
257 pub(crate) fn set_ciphertext(&mut self, ciphertext: Vec<u8>) {
258 self.ciphertext = ciphertext.into();
259 }
260}
261
262#[derive(Debug, Clone)]
285pub(crate) struct PrivateMessageContentIn {
286 pub(crate) content: FramedContentBodyIn,
291 pub(crate) auth: FramedContentAuthData,
292}
293
294impl From<PrivateMessage> for PrivateMessageIn {
295 fn from(value: PrivateMessage) -> Self {
296 Self {
297 group_id: value.group_id,
298 epoch: value.epoch,
299 content_type: value.content_type,
300 authenticated_data: value.authenticated_data,
301 encrypted_sender_data: value.encrypted_sender_data,
302 ciphertext: value.ciphertext,
303 }
304 }
305}
306
307#[cfg(any(feature = "test-utils", test))]
310impl From<PrivateMessageIn> for PrivateMessage {
311 fn from(value: PrivateMessageIn) -> Self {
312 Self {
313 group_id: value.group_id,
314 epoch: value.epoch,
315 content_type: value.content_type,
316 authenticated_data: value.authenticated_data,
317 encrypted_sender_data: value.encrypted_sender_data,
318 ciphertext: value.ciphertext,
319 }
320 }
321}