core_crypto/mls/conversation/conversation_guard/
encrypt.rs1use super::ConversationGuard;
4use super::Result;
5use crate::MlsError;
6use crate::mls::conversation::ConversationWithMls as _;
7use openmls::prelude::MlsMessageOutBody;
8
9impl ConversationGuard {
10 pub async fn encrypt_message(&mut self, message: impl AsRef<[u8]>) -> Result<Vec<u8>> {
23 let backend = self.mls_provider().await?;
24 let credential = self.credential_bundle().await?;
25 let signer = credential.signature_key();
26 let mut inner = self.conversation_mut().await;
27 let encrypted = inner
28 .group
29 .create_message(&backend, signer, message.as_ref())
30 .map_err(MlsError::wrap("creating message"))?;
31
32 debug_assert!(matches!(encrypted.body, MlsMessageOutBody::PrivateMessage(_)));
34
35 let encrypted = encrypted
36 .to_bytes()
37 .map_err(MlsError::wrap("constructing byte vector of encrypted message"))?;
38
39 inner.persist_group_when_changed(&backend.keystore(), false).await?;
40 Ok(encrypted)
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use wasm_bindgen_test::*;
47
48 use crate::test_utils::*;
49
50 wasm_bindgen_test_configure!(run_in_browser);
51
52 #[apply(all_cred_cipher)]
53 #[wasm_bindgen_test]
54 async fn can_encrypt_app_message(case: TestCase) {
55 run_test_with_client_ids(case.clone(), ["alice", "bob"], move |[alice_central, bob_central]| {
56 Box::pin(async move {
57 let id = conversation_id();
58 alice_central
59 .context
60 .new_conversation(&id, case.credential_type, case.cfg.clone())
61 .await
62 .unwrap();
63 alice_central.invite_all(&case, &id, [&bob_central]).await.unwrap();
64
65 let msg = b"Hello bob";
66 let encrypted = alice_central
67 .context
68 .conversation(&id)
69 .await
70 .unwrap()
71 .encrypt_message(msg)
72 .await
73 .unwrap();
74 assert_ne!(&msg[..], &encrypted[..]);
75 let decrypted = bob_central
76 .context
77 .conversation(&id)
78 .await
79 .unwrap()
80 .decrypt_message(encrypted)
81 .await
82 .unwrap()
83 .app_msg
84 .unwrap();
85 assert_eq!(&decrypted[..], &msg[..]);
86 })
87 })
88 .await
89 }
90
91 #[apply(all_cred_cipher)]
93 #[wasm_bindgen_test]
94 async fn can_encrypt_consecutive_messages(case: TestCase) {
95 run_test_with_client_ids(case.clone(), ["alice", "bob"], move |[alice_central, bob_central]| {
96 Box::pin(async move {
97 let id = conversation_id();
98 alice_central
99 .context
100 .new_conversation(&id, case.credential_type, case.cfg.clone())
101 .await
102 .unwrap();
103 alice_central.invite_all(&case, &id, [&bob_central]).await.unwrap();
104 let mut alice_conversation = alice_central.context.conversation(&id).await.unwrap();
105
106 let msg = b"Hello bob";
107 let encrypted = alice_conversation.encrypt_message(msg).await.unwrap();
108 assert_ne!(&msg[..], &encrypted[..]);
109 let decrypted = bob_central
110 .context
111 .conversation(&id)
112 .await
113 .unwrap()
114 .decrypt_message(encrypted)
115 .await
116 .unwrap()
117 .app_msg
118 .unwrap();
119 assert_eq!(&decrypted[..], &msg[..]);
120
121 let msg = b"Hello bob again";
122 let encrypted = alice_conversation.encrypt_message(msg).await.unwrap();
123 assert_ne!(&msg[..], &encrypted[..]);
124 let decrypted = bob_central
125 .context
126 .conversation(&id)
127 .await
128 .unwrap()
129 .decrypt_message(encrypted)
130 .await
131 .unwrap()
132 .app_msg
133 .unwrap();
134 assert_eq!(&decrypted[..], &msg[..]);
135 })
136 })
137 .await
138 }
139}