11use openmls_traits:: crypto:: OpenMlsCrypto ;
22use openmls_traits:: types:: Ciphersuite ;
3+ use openmls_traits:: types:: HashType ;
34use tls_codec:: {
45 Deserialize , Serialize , TlsDeserialize , TlsDeserializeBytes , TlsSerialize , TlsSize ,
56} ;
@@ -70,6 +71,21 @@ impl PrivateMessageIn {
7071 let mls_sender_data_aad_bytes = mls_sender_data_aad
7172 . tls_serialize_detached ( )
7273 . map_err ( LibraryError :: missing_bound_check) ?;
74+
75+ // XMTP: Debug logging to correlate AEAD failures between sender and receiver.
76+ // We avoid logging raw secrets and instead log short, reproducible tags derived
77+ // from on-the-wire values (ciphertext and sender-data AAD).
78+ // Still for internal debug builds only!
79+ let ciphertext_tag = crypto
80+ . hash ( ciphersuite. hash_algorithm ( ) , self . ciphertext . as_slice ( ) )
81+ . unwrap_or_default ( ) ;
82+ let sender_data_aad_tag = crypto
83+ . hash ( ciphersuite. hash_algorithm ( ) , & mls_sender_data_aad_bytes)
84+ . unwrap_or_default ( ) ;
85+
86+ let ciphertext_tag_short = & ciphertext_tag[ ..ciphertext_tag. len ( ) . min ( 8 ) ] ;
87+ let sender_data_aad_tag_short = & sender_data_aad_tag[ ..sender_data_aad_tag. len ( ) . min ( 8 ) ] ;
88+
7389 // Decrypt sender data
7490 log_crypto ! (
7591 trace,
@@ -84,12 +100,35 @@ impl PrivateMessageIn {
84100 & sender_data_nonce,
85101 )
86102 . map_err ( |_| {
87- log:: error!( "Sender data decryption error" ) ;
103+ log:: error!(
104+ "XMTP DEBUG LOGS: Sender data decryption error. \
105+ group_id={:?}, epoch={:?}, content_type={:?}, \
106+ ciphertext_tag={:x?}, sender_data_aad_tag={:x?}",
107+ self . group_id,
108+ self . epoch,
109+ self . content_type,
110+ ciphertext_tag_short,
111+ sender_data_aad_tag_short,
112+ ) ;
88113 MessageDecryptionError :: AeadError
89114 } ) ?;
90115 log:: trace!( " Successfully decrypted sender data." ) ;
91- MlsSenderData :: tls_deserialize ( & mut sender_data_bytes. as_slice ( ) )
92- . map_err ( |_| MessageDecryptionError :: MalformedContent )
116+ let sender_data = MlsSenderData :: tls_deserialize ( & mut sender_data_bytes. as_slice ( ) )
117+ . map_err ( |_| MessageDecryptionError :: MalformedContent ) ?;
118+
119+ log:: info!(
120+ "XMTP DEBUG LOGS: PrivateMessage handshake recv (sender data): \
121+ group_id={:?}, epoch={:?}, leaf_index={:?}, generation={}, \
122+ ciphertext_tag={:x?}, sender_data_aad_tag={:x?}",
123+ self . group_id,
124+ self . epoch,
125+ sender_data. leaf_index,
126+ sender_data. generation,
127+ ciphertext_tag_short,
128+ sender_data_aad_tag_short,
129+ ) ;
130+
131+ Ok ( sender_data)
93132 }
94133
95134 /// Decrypt this [`PrivateMessage`] and return the
@@ -110,13 +149,32 @@ impl PrivateMessageIn {
110149 }
111150 . tls_serialize_detached ( )
112151 . map_err ( LibraryError :: missing_bound_check) ?;
152+
153+ // --- XMTP: derive short tags to correlate AEAD failures with libxmtp logs ---
154+ // These mirror what you’re already doing in sender_data().
155+ let ciphertext_tag = crypto
156+ . hash ( HashType :: Sha2_256 , self . ciphertext . as_slice ( ) )
157+ . unwrap_or_default ( ) ;
158+ let content_aad_tag = crypto
159+ . hash ( HashType :: Sha2_256 , & private_message_content_aad_bytes)
160+ . unwrap_or_default ( ) ;
161+
162+ let ciphertext_tag_short = & ciphertext_tag[ ..ciphertext_tag. len ( ) . min ( 8 ) ] ;
163+ let content_aad_tag_short = & content_aad_tag[ ..content_aad_tag. len ( ) . min ( 8 ) ] ;
164+ // --- end XMTP tags ---
165+
113166 // Decrypt payload
114167 log_crypto ! (
115168 trace,
116169 "Decryption key for private message: {ratchet_key:x?}"
117170 ) ;
118- log_crypto ! ( trace, "Decryption of private message private_message_content_aad_bytes: {private_message_content_aad_bytes:x?} - ratchet_nonce: {ratchet_nonce:x?}" ) ;
171+ log_crypto ! (
172+ trace,
173+ "Decryption of private message private_message_content_aad_bytes: \
174+ {private_message_content_aad_bytes:x?} - ratchet_nonce: {ratchet_nonce:x?}"
175+ ) ;
119176 log:: trace!( "Decrypting ciphertext {:x?}" , self . ciphertext) ;
177+
120178 let private_message_content_bytes = ratchet_key
121179 . aead_open (
122180 crypto,
@@ -125,15 +183,27 @@ impl PrivateMessageIn {
125183 ratchet_nonce,
126184 )
127185 . map_err ( |_| {
128- log:: error!( " Ciphertext decryption error" ) ;
186+ // --- XMTP: upgraded AEAD failure logging for *content* ---
187+ log:: error!(
188+ "XMTP DEBUG LOGS:Ciphertext decryption error. \
189+ stage=content, group_id={:?}, epoch={:?}, content_type={:?}, \
190+ ciphertext_tag={:x?}, content_aad_tag={:x?}",
191+ self . group_id,
192+ self . epoch,
193+ self . content_type,
194+ ciphertext_tag_short,
195+ content_aad_tag_short,
196+ ) ;
129197 debug_assert ! ( false , "Ciphertext decryption failed" ) ;
130198 MessageDecryptionError :: AeadError
131199 } ) ?;
200+
132201 log_content ! (
133202 trace,
134203 " Successfully decrypted PublicMessage bytes: {:x?}" ,
135204 private_message_content_bytes
136205 ) ;
206+
137207 deserialize_ciphertext_content (
138208 & mut private_message_content_bytes. as_slice ( ) ,
139209 self . content_type ( ) ,
@@ -174,6 +244,17 @@ impl PrivateMessageIn {
174244 } ) ?;
175245 // Prepare the nonce by xoring with the reuse guard.
176246 let prepared_nonce = ratchet_nonce. xor_with_reuse_guard ( & sender_data. reuse_guard ) ;
247+
248+ log:: info!(
249+ "XMTP DEBUG LOGS: PrivateMessage content recv (before decrypt): \
250+ group_id={:?}, epoch={:?}, leaf_index={:?}, generation={}, reuse_guard={:x?}",
251+ self . group_id,
252+ self . epoch,
253+ sender_index,
254+ sender_data. generation,
255+ sender_data. reuse_guard,
256+ ) ;
257+
177258 let private_message_content = self . decrypt ( crypto, ratchet_key, & prepared_nonce) ?;
178259
179260 // Extract sender. The sender type is always of type Member for PrivateMessage.
0 commit comments