Skip to main content

core_crypto/mls/conversation/mutable/
encrypt.rs

1//! The methods in this module are concerned with message encryption.
2
3use openmls::prelude::MlsMessageOutBody;
4
5use super::{ConversationMut, Result};
6use crate::OpenMlsError;
7
8impl ConversationMut {
9    /// Encrypts a raw payload then serializes it to the TLS wire format.
10    ///
11    /// Can only be called when there is no pending commit and no pending proposal.
12    ///
13    /// # Arguments
14    /// * `message` - the message as a byte array
15    ///
16    /// # Return type
17    /// This method will return an encrypted TLS serialized message.
18    ///
19    /// # Errors
20    /// If the conversation can't be found, an error will be returned. Other errors are originating
21    /// from OpenMls and the KeyStore
22    pub async fn encrypt_message(&mut self, message: impl AsRef<[u8]>) -> Result<Vec<u8>> {
23        #[cfg(debug_assertions)]
24        {
25            let group = &self.group().await;
26            debug_assert!(
27                group.pending_commit().is_none(),
28                "precondition failed; a pending commit exists"
29            );
30            debug_assert!(
31                group.pending_proposals().next().is_none(),
32                "precondition failed; a pending proposal exists"
33            );
34        }
35
36        let backend = self.crypto_provider().await?;
37        let credential = self.credential().await?;
38        let signer = credential.signature_key();
39
40        self.mutate_group(async |_, group, _| {
41            let encrypted = group
42                .create_message(&backend, signer, message.as_ref())
43                .map_err(OpenMlsError::wrap("creating encrypted message"))?;
44            // all application messages must be encrypted
45            debug_assert!(matches!(encrypted.body, MlsMessageOutBody::PrivateMessage(_)));
46            encrypted
47                .to_bytes()
48                .map_err(OpenMlsError::wrap("constructing byte vector of encrypted message"))
49                .map_err(Into::into)
50        })
51        .await
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use crate::test_utils::*;
58
59    #[apply(all_cred_cipher)]
60    async fn can_encrypt_app_message(case: TestContext) {
61        let [alice, bob] = case.sessions().await;
62        Box::pin(async move {
63            let conversation = case.create_conversation([&alice, &bob]).await;
64
65            let msg = b"Hello bob";
66            let encrypted = conversation.guard().await.encrypt_message(msg).await.unwrap();
67            assert_ne!(&msg[..], &encrypted[..]);
68            let decrypted = conversation
69                .guard_of(&bob)
70                .await
71                .decrypt_message(encrypted)
72                .await
73                .unwrap();
74            let decrypted = &decrypted.as_text().unwrap().plaintext;
75            assert_eq!(&decrypted[..], &msg[..]);
76        })
77        .await
78    }
79
80    // Ensures encrypting an application message is durable
81    #[apply(all_cred_cipher)]
82    async fn can_encrypt_consecutive_messages(case: TestContext) {
83        let [alice, bob] = case.sessions().await;
84        Box::pin(async move {
85            let conversation = case.create_conversation([&alice, &bob]).await;
86
87            let msg = b"Hello bob";
88            let encrypted = conversation.guard().await.encrypt_message(msg).await.unwrap();
89            assert_ne!(&msg[..], &encrypted[..]);
90            let decrypted = conversation
91                .guard_of(&bob)
92                .await
93                .decrypt_message(encrypted)
94                .await
95                .unwrap();
96            let decrypted = &decrypted.as_text().unwrap().plaintext;
97            assert_eq!(&decrypted[..], &msg[..]);
98
99            let msg = b"Hello bob again";
100            let encrypted = conversation.guard().await.encrypt_message(msg).await.unwrap();
101            assert_ne!(&msg[..], &encrypted[..]);
102            let decrypted = conversation
103                .guard_of(&bob)
104                .await
105                .decrypt_message(encrypted)
106                .await
107                .unwrap();
108            let decrypted = &decrypted.as_text().unwrap().plaintext;
109            assert_eq!(&decrypted[..], &msg[..]);
110        })
111        .await
112    }
113}