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                .app_msg
75                .unwrap();
76            assert_eq!(&decrypted[..], &msg[..]);
77        })
78        .await
79    }
80
81    // Ensures encrypting an application message is durable
82    #[apply(all_cred_cipher)]
83    async fn can_encrypt_consecutive_messages(case: TestContext) {
84        let [alice, bob] = case.sessions().await;
85        Box::pin(async move {
86            let conversation = case.create_conversation([&alice, &bob]).await;
87
88            let msg = b"Hello bob";
89            let encrypted = conversation.guard().await.encrypt_message(msg).await.unwrap();
90            assert_ne!(&msg[..], &encrypted[..]);
91            let decrypted = conversation
92                .guard_of(&bob)
93                .await
94                .decrypt_message(encrypted)
95                .await
96                .unwrap()
97                .app_msg
98                .unwrap();
99            assert_eq!(&decrypted[..], &msg[..]);
100
101            let msg = b"Hello bob again";
102            let encrypted = conversation.guard().await.encrypt_message(msg).await.unwrap();
103            assert_ne!(&msg[..], &encrypted[..]);
104            let decrypted = conversation
105                .guard_of(&bob)
106                .await
107                .decrypt_message(encrypted)
108                .await
109                .unwrap()
110                .app_msg
111                .unwrap();
112            assert_eq!(&decrypted[..], &msg[..]);
113        })
114        .await
115    }
116}