core_crypto/mls/conversation/
encrypt.rs1use mls_crypto_provider::MlsCryptoProvider;
11use openmls::prelude::MlsMessageOutBody;
12
13use super::MlsConversation;
14use crate::context::CentralContext;
15use crate::prelude::Client;
16use crate::{mls::ConversationId, CryptoError, CryptoResult, MlsError};
17
18impl MlsConversation {
20 #[cfg_attr(test, crate::durable)]
23 pub async fn encrypt_message(
24 &mut self,
25 client: &Client,
26 message: impl AsRef<[u8]>,
27 backend: &MlsCryptoProvider,
28 ) -> CryptoResult<Vec<u8>> {
29 let signer = &self
30 .find_current_credential_bundle(client)
31 .await
32 .map_err(|_| CryptoError::IdentityInitializationError)?
33 .signature_key;
34 let encrypted = self
35 .group
36 .create_message(backend, signer, message.as_ref())
37 .map_err(MlsError::from)?;
38
39 debug_assert!(matches!(encrypted.body, MlsMessageOutBody::PrivateMessage(_)));
41
42 let encrypted = encrypted.to_bytes().map_err(MlsError::from)?;
43
44 self.persist_group_when_changed(&backend.keystore(), false).await?;
45 Ok(encrypted)
46 }
47}
48
49impl CentralContext {
50 #[cfg_attr(test, crate::idempotent)]
63 pub async fn encrypt_message(
64 &self,
65 conversation: &ConversationId,
66 message: impl AsRef<[u8]>,
67 ) -> CryptoResult<Vec<u8>> {
68 let client = self.mls_client().await?;
69 self.get_conversation(conversation)
70 .await?
71 .write()
72 .await
73 .encrypt_message(&client, message, &self.mls_provider().await?)
74 .await
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use wasm_bindgen_test::*;
81
82 use crate::test_utils::*;
83
84 wasm_bindgen_test_configure!(run_in_browser);
85
86 #[apply(all_cred_cipher)]
87 #[wasm_bindgen_test]
88 async fn can_encrypt_app_message(case: TestCase) {
89 run_test_with_client_ids(case.clone(), ["alice", "bob"], move |[alice_central, bob_central]| {
90 Box::pin(async move {
91 let id = conversation_id();
92 alice_central
93 .context
94 .new_conversation(&id, case.credential_type, case.cfg.clone())
95 .await
96 .unwrap();
97 alice_central.invite_all(&case, &id, [&bob_central]).await.unwrap();
98
99 let msg = b"Hello bob";
100 let encrypted = alice_central.context.encrypt_message(&id, msg).await.unwrap();
101 assert_ne!(&msg[..], &encrypted[..]);
102 let decrypted = bob_central
103 .context
104 .decrypt_message(&id, encrypted)
105 .await
106 .unwrap()
107 .app_msg
108 .unwrap();
109 assert_eq!(&decrypted[..], &msg[..]);
110 })
111 })
112 .await
113 }
114
115 #[apply(all_cred_cipher)]
117 #[wasm_bindgen_test]
118 async fn can_encrypt_consecutive_messages(case: TestCase) {
119 run_test_with_client_ids(case.clone(), ["alice", "bob"], move |[alice_central, bob_central]| {
120 Box::pin(async move {
121 let id = conversation_id();
122 alice_central
123 .context
124 .new_conversation(&id, case.credential_type, case.cfg.clone())
125 .await
126 .unwrap();
127 alice_central.invite_all(&case, &id, [&bob_central]).await.unwrap();
128
129 let msg = b"Hello bob";
130 let encrypted = alice_central.context.encrypt_message(&id, msg).await.unwrap();
131 assert_ne!(&msg[..], &encrypted[..]);
132 let decrypted = bob_central
133 .context
134 .decrypt_message(&id, encrypted)
135 .await
136 .unwrap()
137 .app_msg
138 .unwrap();
139 assert_eq!(&decrypted[..], &msg[..]);
140
141 let msg = b"Hello bob again";
142 let encrypted = alice_central.context.encrypt_message(&id, msg).await.unwrap();
143 assert_ne!(&msg[..], &encrypted[..]);
144 let decrypted = bob_central
145 .context
146 .decrypt_message(&id, encrypted)
147 .await
148 .unwrap()
149 .app_msg
150 .unwrap();
151 assert_eq!(&decrypted[..], &msg[..]);
152 })
153 })
154 .await
155 }
156}