1use std::{convert::TryFrom, fmt, time::SystemTime};
2
3use aes::cipher::block_padding::{Iso7816, Padding};
4use base64::prelude::*;
5use libsignal_core::ServiceIdKind;
6use libsignal_protocol::{
7 group_decrypt, message_decrypt_prekey, message_decrypt_signal,
8 message_encrypt, process_sender_key_distribution_message,
9 sealed_sender_decrypt_to_usmc, sealed_sender_encrypt,
10 CiphertextMessageType, DeviceId, IdentityKeyStore, KyberPreKeyStore,
11 PlaintextContent, Pni, PreKeySignalMessage, PreKeyStore, ProtocolAddress,
12 ProtocolStore, PublicKey, SealedSenderDecryptionResult, SenderCertificate,
13 SenderKeyDistributionMessage, SenderKeyStore, ServiceId, SessionNotFound,
14 SessionStore, SessionUsabilityRequirements, SignalMessage,
15 SignalProtocolError, SignedPreKeyStore, Timestamp,
16 UnidentifiedSenderMessageContent,
17};
18use prost::Message;
19use rand::{rng, CryptoRng, Rng};
20use uuid::Uuid;
21
22use crate::{
23 content::{Content, Metadata},
24 envelope::Envelope,
25 proto::PniSignatureMessage,
26 push_service::{ServiceError, DEFAULT_DEVICE_ID},
27 sender::OutgoingPushMessage,
28 session_store::SessionStoreExt,
29 utils::BASE64_RELAXED,
30 ServiceIdExt,
31};
32
33#[derive(Clone)]
37pub struct ServiceCipher<S> {
38 protocol_store: S,
39 trust_roots: Vec<PublicKey>,
40 local_address: ProtocolAddress,
41}
42
43impl<S> fmt::Debug for ServiceCipher<S> {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 f.debug_struct("ServiceCipher")
46 .field("protocol_store", &"...")
47 .field("trust_root", &"...")
48 .field("local_address", &self.local_address)
49 .finish()
50 }
51}
52
53fn debug_envelope(envelope: &Envelope) -> String {
54 if envelope.content.is_none() {
55 "Envelope { empty }".to_string()
56 } else {
57 format!(
58 "Envelope {{ \
59 source_address: {:?}, \
60 source_device: {:?}, \
61 server_guid: {:?}, \
62 client_timestamp: {:?}, \
63 content: {} bytes, \
64 }}",
65 envelope.parse_source_service_id(),
66 envelope.source_device_id(),
67 envelope.server_guid(),
68 envelope.client_timestamp(),
69 envelope.content().len(),
70 )
71 }
72}
73
74impl<S> ServiceCipher<S>
75where
76 S: ProtocolStore + SenderKeyStore + SessionStoreExt + Clone,
77{
78 pub fn new(
79 protocol_store: S,
80 trust_roots: Vec<PublicKey>,
81 local_address: ProtocolAddress,
82 ) -> Self {
83 Self {
84 protocol_store,
85 trust_roots,
86 local_address,
87 }
88 }
89
90 #[tracing::instrument(skip(envelope, csprng), fields(envelope = debug_envelope(&envelope)))]
106 pub async fn open_envelope<R: Rng + CryptoRng>(
107 &mut self,
108 envelope: Envelope,
109 csprng: &mut R,
110 ) -> Result<Option<Content>, ServiceError> {
111 let local_service: ServiceId =
112 ServiceId::parse_from_service_id_string(self.local_address.name())
113 .expect("valid protocol address name");
114
115 if envelope.content.is_some() {
116 let plaintext = self.decrypt(&envelope, csprng).await?;
117 let was_plaintext = plaintext.metadata.was_plaintext;
118
119 tracing::Span::current()
120 .record("envelope_metadata", plaintext.metadata.to_string());
121
122 if let Some(bytes) =
125 &plaintext.message.sender_key_distribution_message
126 {
127 let skdm = SenderKeyDistributionMessage::try_from(&bytes[..])?;
128 let sender = plaintext.metadata.protocol_address()?;
129 process_sender_key_distribution_message(
130 &sender,
131 &skdm,
132 &mut self.protocol_store,
133 )
134 .await?;
135 tracing::info!(
136 distribution_id = %skdm.distribution_id()?,
137 sender = %sender,
138 "applied sender key distribution message"
139 );
140 }
141
142 let Some(content) = &plaintext.message.content else {
143 if let Some(pni) = plaintext.metadata.pni_verified {
147 tracing::warn!(
148 ?pni,
149 "dropped verified PNI signature: content-less message"
150 );
151 }
152 tracing::warn!("empty decrypted content");
153 return Ok(None);
154 };
155
156 if was_plaintext {
162 let crate::proto::content::Content::DecryptionErrorMessage(dme) =
163 content
164 else {
165 tracing::error!(
166 ?envelope,
167 "Received a plaintext envelope with a non-decryption error message."
168 );
169 return Ok(None);
170 };
171 tracing::warn!(
172 ?envelope,
173 "Received a decryption error message: {}.",
174 String::from_utf8_lossy(dme)
175 );
176 }
177
178 if matches!(content, crate::proto::content::Content::SyncMessage(_))
179 && plaintext.metadata.sender.aci().map(Uuid::from)
180 != Some(local_service.raw_uuid())
181 && local_service.kind() == ServiceIdKind::Aci
182 {
183 tracing::warn!("Source is not ourself.");
184 return Ok(None);
185 }
186
187 let content =
188 Content::from_proto(plaintext.message, plaintext.metadata);
189 Ok(Some(content?))
190 } else {
191 Ok(None)
192 }
193 }
194
195 async fn verify_pni_signature(
197 &self,
198 sender: ServiceId,
199 sender_device: DeviceId,
200 pni_signature: &PniSignatureMessage,
201 ) -> Option<Pni> {
202 let Some(sender_aci) = sender.aci() else {
203 tracing::warn!("ignoring PNI signature: source is not an ACI");
204 return None;
205 };
206
207 let Some(pni) =
208 Pni::parse_from_service_id_binary(pni_signature.pni.as_deref()?)
209 else {
210 tracing::warn!("ignoring PNI signature: unparseable PNI");
211 return None;
212 };
213 let signature = pni_signature.signature.as_deref()?;
214
215 let aci_address = sender_aci.to_protocol_address(sender_device).ok()?;
216 let aci_identity = self
217 .protocol_store
218 .get_identity(&aci_address)
219 .await
220 .ok()
221 .flatten()?;
222
223 let pni_address = pni.to_protocol_address(sender_device).ok()?;
224 let pni_identity =
225 match self.protocol_store.get_identity(&pni_address).await {
226 Ok(Some(id)) => id,
227 _ => {
228 if sender_device == *DEFAULT_DEVICE_ID {
229 tracing::warn!(
230 "ignoring PNI signature: no PNI identity known"
231 );
232 return None;
233 }
234 let primary =
236 pni.to_protocol_address(*DEFAULT_DEVICE_ID).ok()?;
237 match self.protocol_store.get_identity(&primary).await {
238 Ok(Some(id)) => id,
239 _ => {
240 tracing::warn!(
241 "ignoring PNI signature: no PNI identity known"
242 );
243 return None;
244 },
245 }
246 },
247 };
248
249 let verified = pni_identity
250 .verify_alternate_identity(&aci_identity, signature)
251 .inspect_err(|e| {
252 tracing::warn!(?e, "PNI signature verification error");
253 })
254 .ok()?;
255
256 if verified {
257 tracing::info!(
258 aci = %sender_aci.service_id_string(),
259 pni = %pni.service_id_string(),
260 "verified PNI signature"
261 );
262 Some(pni)
263 } else {
264 tracing::warn!(
265 aci = %sender_aci.service_id_string(),
266 pni = %pni.service_id_string(),
267 "invalid PNI signature"
268 );
269 None
270 }
271 }
272
273 #[tracing::instrument(skip(envelope, csprng), fields(envelope = debug_envelope(envelope)))]
279 async fn decrypt<R: Rng + CryptoRng>(
280 &mut self,
281 envelope: &Envelope,
282 csprng: &mut R,
283 ) -> Result<Plaintext, ServiceError> {
284 let local_service: ServiceId =
285 ServiceId::parse_from_service_id_string(self.local_address.name())
286 .expect("valid protocol address name");
287
288 let ciphertext = if let Some(msg) = envelope.content.as_ref() {
289 msg
290 } else {
291 return Err(ServiceError::InvalidFrame {
292 reason:
293 "envelope should have either a legacy message or content.",
294 });
295 };
296
297 let server_guid = envelope.parse_server_guid();
298
299 let Some(destination_service_id) =
300 envelope.parse_destination_service_id()
301 else {
302 tracing::warn!(
303 "missing destination service id; ignoring invalid message."
304 );
305 return Err(ServiceError::InvalidFrame {
306 reason: "missing destination service id",
307 });
308 };
309
310 if destination_service_id != local_service {
311 tracing::warn!(
312 "mismatching destination service id; ignoring invalid message."
313 );
314 return Err(ServiceError::InvalidFrame {
315 reason: "mismatch destination service id",
316 });
317 }
318
319 let source_service_id = envelope.parse_source_service_id();
320
321 if destination_service_id.kind() == ServiceIdKind::Pni
322 && source_service_id.is_none()
323 {
324 tracing::warn!("received sealed sender message to our PNI; ignoring invalid message");
325 return Err(ServiceError::InvalidFrame {
326 reason: "sealed sender received on our PNI",
327 });
328 }
329
330 if let Some(source_service_id) = source_service_id {
332 if source_service_id.kind() == ServiceIdKind::Pni
333 && envelope.r#type() != Type::ServerDeliveryReceipt
334 {
335 tracing::warn!("got a message from a PNI that was not a ServerDeliveryReceipt; ignoring invalid message");
336 return Err(ServiceError::InvalidFrame {
337 reason: "PNI received a non-ServerDeliveryReceipt",
338 });
339 }
340 }
341
342 let client_timestamp = chrono::DateTime::from_timestamp_millis(
346 envelope.client_timestamp() as i64,
347 )
348 .ok_or(ServiceError::InvalidFrame {
349 reason: "unparseable timestamp",
350 });
351 let server_timestamp = chrono::DateTime::from_timestamp_millis(
352 envelope.server_timestamp() as i64,
353 )
354 .ok_or(ServiceError::InvalidFrame {
355 reason: "unparseable server timestamp",
356 });
357
358 struct DecryptedPayload {
360 data: Vec<u8>,
361 sender: ServiceId,
362 sender_device: DeviceId,
363 was_plaintext: bool,
364 unidentified_sender: bool,
365 needs_receipt: bool,
366 }
367
368 use crate::proto::envelope::Type;
369 let parts = match envelope.r#type() {
370 Type::PrekeyMessage => {
371 let source_service_id = source_service_id
372 .expect("prekey bundle format contains source_service_id");
373 let sender_device = envelope.source_device_id().try_into()?;
374 let sender = get_preferred_protocol_address(
375 &self.protocol_store,
376 &source_service_id,
377 sender_device,
378 )
379 .await?;
380
381 let mut data = message_decrypt_prekey(
382 &PreKeySignalMessage::try_from(&ciphertext[..])?,
383 &sender,
384 &self.local_address,
385 &mut self.protocol_store.clone(),
386 &mut self.protocol_store.clone(),
387 &mut self.protocol_store.clone(),
388 &self.protocol_store.clone(),
389 &mut self.protocol_store.clone(),
390 csprng,
391 )
392 .await?
393 .as_slice()
394 .to_vec();
395
396 let session_record = self
397 .protocol_store
398 .load_session(&sender)
399 .await?
400 .ok_or_else(|| {
401 SignalProtocolError::SessionNotFound(
402 SessionNotFound::new(sender, "decrypt"),
403 )
404 })?;
405
406 strip_padding_version(
407 session_record.session_version()?,
408 &mut data,
409 )?;
410 DecryptedPayload {
411 data,
412 sender: source_service_id,
413 sender_device,
414 was_plaintext: false,
415 unidentified_sender: false,
416 needs_receipt: false,
417 }
418 },
419 Type::PlaintextContent => {
420 tracing::warn!(?envelope, "Envelope with plaintext content. This usually indicates a decryption retry.");
421 let source_service_id = source_service_id
422 .expect("prekey bundle format contains source_service_id");
423 let plaintext_content =
426 PlaintextContent::try_from(&ciphertext[..])?;
427 let mut data = plaintext_content.body().to_vec();
428 strip_padding(&mut data)?;
429 DecryptedPayload {
430 data,
431 sender: source_service_id,
432 sender_device: envelope.source_device_id().try_into()?,
433 was_plaintext: true,
434 unidentified_sender: false,
435 needs_receipt: false,
436 }
437 },
438 Type::DoubleRatchet => {
439 let source_service_id = source_service_id
440 .expect("prekey bundle format contains source_service_id");
441 let sender_device = envelope.source_device_id().try_into()?;
442 let sender = get_preferred_protocol_address(
443 &self.protocol_store,
444 &source_service_id,
445 sender_device,
446 )
447 .await?;
448
449 let mut data = message_decrypt_signal(
450 &SignalMessage::try_from(&ciphertext[..])?,
451 &sender,
452 &self.local_address,
453 &mut self.protocol_store.clone(),
454 &mut self.protocol_store.clone(),
455 csprng,
456 )
457 .await?
458 .as_slice()
459 .to_vec();
460
461 let session_record = self
462 .protocol_store
463 .load_session(&sender)
464 .await?
465 .ok_or_else(|| {
466 SignalProtocolError::SessionNotFound(
467 SessionNotFound::new(sender, "decrypt"),
468 )
469 })?;
470
471 strip_padding_version(
472 session_record.session_version()?,
473 &mut data,
474 )?;
475 DecryptedPayload {
476 data,
477 sender: source_service_id,
478 sender_device,
479 was_plaintext: false,
480 unidentified_sender: false,
481 needs_receipt: false,
482 }
483 },
484 Type::UnidentifiedSender => {
485 let SealedSenderDecryptionResult {
486 sender_uuid,
487 sender_e164: _,
488 device_id,
489 mut message,
490 } = sealed_sender_decrypt(
491 ciphertext,
492 &self.trust_roots,
493 Timestamp::from_epoch_millis(envelope.client_timestamp()),
494 None,
495 self.local_address.clone(),
496 &mut self.protocol_store.clone(),
497 &mut self.protocol_store.clone(),
498 &mut self.protocol_store.clone(),
499 &mut self.protocol_store.clone(),
500 &mut self.protocol_store.clone(),
501 &mut self.protocol_store,
502 )
503 .await?;
504
505 let Some(sender) =
506 ServiceId::parse_from_service_id_string(&sender_uuid)
507 else {
508 return Err(
509 SignalProtocolError::InvalidSealedSenderMessage(
510 "invalid sender UUID".to_string(),
511 )
512 .into(),
513 );
514 };
515
516 let needs_receipt = if source_service_id.is_some() {
517 tracing::warn!(?envelope, "Received an unidentified delivery over an identified channel. Marking needs_receipt=false");
518 false
519 } else {
520 true
521 };
522
523 if sender.kind() == ServiceIdKind::Pni {
524 tracing::warn!(
525 "sealed sender used for PNI; ignoring invalid message"
526 );
527 return Err(ServiceError::InvalidFrame {
528 reason: "sealed sender used for PNI",
529 });
530 }
531
532 strip_padding(&mut message)?;
533
534 DecryptedPayload {
535 data: message,
536 sender,
537 sender_device: device_id,
538 was_plaintext: false,
539 unidentified_sender: true,
540 needs_receipt,
541 }
542 },
543 _ => {
544 return Err(ServiceError::InvalidFrame {
546 reason: "envelope has unknown type",
547 });
548 },
549 };
550
551 let message = crate::proto::Content::decode(parts.data.as_slice())?;
552 let pni_verified = if let Some(msg) = &message.pni_signature_message {
553 self.verify_pni_signature(parts.sender, parts.sender_device, msg)
554 .await
555 } else {
556 None
557 };
558 let metadata = Metadata {
559 destination: destination_service_id,
560 sender: parts.sender,
561 sender_device: parts.sender_device,
562 client_timestamp: client_timestamp?,
563 server_timestamp: server_timestamp?,
564 needs_receipt: parts.needs_receipt,
565 unidentified_sender: parts.unidentified_sender,
566 was_plaintext: parts.was_plaintext,
567 server_guid,
568 pni_verified,
569 };
570 Ok(Plaintext { metadata, message })
571 }
572
573 #[tracing::instrument(
574 skip(address, unidentified_access, content, csprng),
575 fields(
576 address = %address,
577 with_unidentified_access = unidentified_access.is_some(),
578 content_length = content.len(),
579 )
580 )]
581 pub(crate) async fn encrypt<R: Rng + CryptoRng>(
582 &mut self,
583 address: &ProtocolAddress,
584 unidentified_access: Option<&SenderCertificate>,
585 content: &[u8],
586 csprng: &mut R,
587 ) -> Result<OutgoingPushMessage, ServiceError> {
588 let mut rng = rng();
589
590 let session_record = self
591 .protocol_store
592 .load_session(address)
593 .await?
594 .ok_or_else(|| {
595 SignalProtocolError::SessionNotFound(SessionNotFound::new(
596 address.clone(),
597 "encrypt",
598 ))
599 })?;
600
601 let record_usable = session_record
602 .has_usable_sender_chain(
603 SystemTime::now(),
604 SessionUsabilityRequirements::NotStale,
605 )
606 .unwrap_or(false);
607 if !record_usable {
608 Err(SignalProtocolError::SessionNotFound(SessionNotFound::new(
609 address.clone(),
610 "encrypt",
611 )))?;
612 }
613
614 let padded_content =
615 add_padding(session_record.session_version()?, content)?;
616
617 if let Some(unindentified_access) = unidentified_access {
618 let destination_registration_id =
619 session_record.remote_registration_id()?;
620
621 let message = sealed_sender_encrypt(
622 address,
623 unindentified_access,
624 &padded_content,
625 &mut self.protocol_store.clone(),
626 &mut self.protocol_store,
627 SystemTime::now(),
628 csprng,
629 )
630 .await?;
631
632 use crate::proto::envelope::Type;
633 Ok(OutgoingPushMessage {
634 r#type: Type::UnidentifiedSender as u32,
635 destination_device_id: address.device_id(),
636 destination_registration_id,
637 content: BASE64_RELAXED.encode(message),
638 })
639 } else {
640 let message = message_encrypt(
641 &padded_content,
642 address,
643 &self.local_address,
644 &mut self.protocol_store.clone(),
645 &mut self.protocol_store.clone(),
646 SystemTime::now(),
647 &mut rng,
648 )
649 .await?;
650
651 let destination_registration_id =
652 session_record.remote_registration_id()?;
653
654 let body = BASE64_RELAXED.encode(message.serialize());
655
656 use crate::proto::envelope::Type;
657 let message_type = match message.message_type() {
658 CiphertextMessageType::PreKey => Type::PrekeyMessage,
659 CiphertextMessageType::Whisper => Type::DoubleRatchet,
660 t => panic!("Bad type: {:?}", t),
661 } as u32;
662 Ok(OutgoingPushMessage {
663 r#type: message_type,
664 destination_device_id: address.device_id(),
665 destination_registration_id,
666 content: body,
667 })
668 }
669 }
670}
671
672struct Plaintext {
673 metadata: Metadata,
674 message: crate::proto::Content,
675}
676
677#[expect(clippy::comparison_chain)]
678fn add_padding(version: u32, contents: &[u8]) -> Result<Vec<u8>, ServiceError> {
679 if version < 2 {
680 Err(ServiceError::PaddingVersion(version))
681 } else if version == 2 {
682 Ok(contents.to_vec())
683 } else {
684 let message_length = contents.len();
685 let message_length_with_terminator = contents.len() + 1;
686 let mut message_part_count = message_length_with_terminator / 160;
687 if !message_length_with_terminator.is_multiple_of(160) {
688 message_part_count += 1;
689 }
690
691 let message_length_with_padding = message_part_count * 160;
692
693 let mut buffer = vec![0u8; message_length_with_padding];
694 buffer[..message_length].copy_from_slice(contents);
695 Iso7816::raw_pad(&mut buffer, message_length);
696 Ok(buffer)
697 }
698}
699
700#[expect(clippy::comparison_chain)]
701fn strip_padding_version(
702 version: u32,
703 contents: &mut Vec<u8>,
704) -> Result<(), ServiceError> {
705 if version < 2 {
706 Err(ServiceError::InvalidFrame {
707 reason: "unknown version",
708 })
709 } else if version == 2 {
710 Ok(())
711 } else {
712 strip_padding(contents)?;
713 Ok(())
714 }
715}
716
717fn strip_padding(contents: &mut Vec<u8>) -> Result<(), ServiceError> {
718 let new_length = Iso7816::raw_unpad(contents)?.len();
719 contents.resize(new_length, 0);
720 Ok(())
721}
722
723pub async fn get_preferred_protocol_address<S: SessionStore>(
725 session_store: &S,
726 address: &ServiceId,
727 device_id: DeviceId,
728) -> Result<ProtocolAddress, libsignal_protocol::error::SignalProtocolError> {
729 let address = address.to_protocol_address(device_id);
730 if session_store.load_session(&address).await?.is_some() {
731 return Ok(address);
732 }
733
734 Ok(address)
735}
736
737#[derive(thiserror::Error)]
743#[error("error: {inner}, usmc: {}", sender.is_some())]
744pub struct SealedSenderDecryptionError {
745 pub inner: SignalProtocolError,
746 pub sender: Option<ProtocolAddress>,
747}
748
749impl fmt::Debug for SealedSenderDecryptionError {
750 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
751 f.debug_struct("SealedSenderDecryptionError")
752 .field("inner", &self.inner)
753 .field("sender", &self.sender)
754 .finish()
755 }
756}
757
758impl From<SignalProtocolError> for SealedSenderDecryptionError {
759 fn from(e: SignalProtocolError) -> Self {
760 SealedSenderDecryptionError {
761 inner: e,
762 sender: None,
763 }
764 }
765}
766
767#[allow(clippy::too_many_arguments)]
775#[tracing::instrument(
776 skip(
777 ciphertext,
778 trust_roots,
779 identity_store,
780 session_store,
781 pre_key_store,
782 signed_pre_key_store,
783 sender_key_store,
784 kyber_pre_key_store
785 ),
786 fields(
787 ciphertext = ciphertext.len(),
788 )
789)]
790async fn sealed_sender_decrypt(
791 ciphertext: &[u8],
792 trust_roots: &[PublicKey],
793 timestamp: Timestamp,
794 local_e164: Option<String>,
795 local_address: ProtocolAddress,
796 identity_store: &mut dyn IdentityKeyStore,
797 session_store: &mut dyn SessionStore,
798 pre_key_store: &mut dyn PreKeyStore,
799 signed_pre_key_store: &mut dyn SignedPreKeyStore,
800 sender_key_store: &mut dyn SenderKeyStore,
801 kyber_pre_key_store: &mut dyn KyberPreKeyStore,
802) -> Result<SealedSenderDecryptionResult, SealedSenderDecryptionError> {
803 let usmc =
804 sealed_sender_decrypt_to_usmc(ciphertext, identity_store).await?;
805
806 if !usmc
807 .sender()?
808 .validate_with_trust_roots(trust_roots, timestamp)?
809 {
810 return Err(SignalProtocolError::InvalidSealedSenderMessage(
811 "trust root validation failed".to_string(),
812 )
813 .into());
814 }
815
816 let local_service_id =
817 ServiceId::parse_from_service_id_string(local_address.name())
818 .expect("valid protocol address name");
819 let is_local_uuid = local_service_id.raw_uuid()
820 == usmc
821 .sender()?
822 .sender_uuid()?
823 .parse::<Uuid>()
824 .expect("valid uuid");
826
827 let is_local_e164 = match (local_e164, usmc.sender()?.sender_e164()?) {
828 (Some(l), Some(s)) => l == s,
829 (_, _) => false,
830 };
831
832 if (is_local_e164 || is_local_uuid)
833 && usmc.sender()?.sender_device_id()? == local_address.device_id()
834 {
835 return Err(SignalProtocolError::SealedSenderSelfSend.into());
836 }
837
838 let remote_address = ProtocolAddress::new(
839 usmc.sender()?.sender_uuid()?.to_string(),
840 usmc.sender()?.sender_device_id()?,
841 );
842
843 sealed_sender_decrypt_with_validated_usmc(
844 &usmc,
845 &remote_address,
846 &local_address,
847 identity_store,
848 session_store,
849 pre_key_store,
850 signed_pre_key_store,
851 sender_key_store,
852 kyber_pre_key_store,
853 )
854 .await
855 .map_err(|inner| SealedSenderDecryptionError {
856 inner,
857 sender: Some(remote_address),
858 })
859}
860
861#[allow(clippy::too_many_arguments)]
862async fn sealed_sender_decrypt_with_validated_usmc(
863 usmc: &UnidentifiedSenderMessageContent,
864 remote_address: &ProtocolAddress,
865 local_address: &ProtocolAddress,
866 identity_store: &mut dyn IdentityKeyStore,
867 session_store: &mut dyn SessionStore,
868 pre_key_store: &mut dyn PreKeyStore,
869 signed_pre_key_store: &mut dyn SignedPreKeyStore,
870 sender_key_store: &mut dyn SenderKeyStore,
871 kyber_pre_key_store: &mut dyn KyberPreKeyStore,
872) -> Result<SealedSenderDecryptionResult, SignalProtocolError> {
873 let mut rng = rng();
874
875 let message = match usmc.msg_type()? {
876 CiphertextMessageType::Whisper => {
877 let ctext = SignalMessage::try_from(usmc.contents()?)?;
878 message_decrypt_signal(
879 &ctext,
880 remote_address,
881 local_address,
882 session_store,
883 identity_store,
884 &mut rng,
885 )
886 .await?
887 },
888 CiphertextMessageType::PreKey => {
889 let ctext = PreKeySignalMessage::try_from(usmc.contents()?)?;
890 message_decrypt_prekey(
891 &ctext,
892 remote_address,
893 local_address,
894 session_store,
895 identity_store,
896 pre_key_store,
897 signed_pre_key_store,
898 kyber_pre_key_store,
899 &mut rng,
900 )
901 .await?
902 },
903 CiphertextMessageType::SenderKey => {
904 group_decrypt(usmc.contents()?, sender_key_store, remote_address)
905 .await?
906 },
907 CiphertextMessageType::Plaintext => {
908 let plaintext_content =
911 PlaintextContent::try_from(usmc.contents()?)?;
912 plaintext_content.body().to_vec()
913 },
914 };
915
916 Ok(SealedSenderDecryptionResult {
917 sender_uuid: usmc.sender()?.sender_uuid()?.to_string(),
918 sender_e164: usmc.sender()?.sender_e164()?.map(|s| s.to_string()),
919 device_id: usmc.sender()?.sender_device_id()?,
920 message,
921 })
922}