interop/clients/corecrypto/
native.rs

1use color_eyre::eyre::Result;
2use std::cell::Cell;
3use std::sync::Arc;
4use tls_codec::Serialize;
5
6use core_crypto::prelude::*;
7
8use crate::util::MlsTransportSuccessProvider;
9use crate::{
10    CIPHERSUITE_IN_USE,
11    clients::{EmulatedClient, EmulatedClientProtocol, EmulatedClientType, EmulatedMlsClient},
12};
13
14#[derive(Debug)]
15pub(crate) struct CoreCryptoNativeClient {
16    cc: CoreCrypto,
17    client_id: Vec<u8>,
18    #[cfg(feature = "proteus")]
19    prekey_last_id: Cell<u16>,
20}
21
22#[allow(dead_code)]
23impl CoreCryptoNativeClient {
24    pub(crate) async fn new() -> Result<Self> {
25        Self::internal_new(false).await
26    }
27
28    async fn internal_new(deferred: bool) -> Result<Self> {
29        let client_id = uuid::Uuid::new_v4();
30
31        let ciphersuites = vec![CIPHERSUITE_IN_USE.into()];
32        let cid = if !deferred {
33            Some(client_id.as_hyphenated().to_string().as_bytes().into())
34        } else {
35            None
36        };
37        let key = core_crypto::DatabaseKey::generate();
38        let configuration =
39            MlsClientConfiguration::try_new("whatever".into(), key, cid, ciphersuites, None, Some(100))?;
40
41        let cc = CoreCrypto::from(Session::try_new_in_memory(configuration).await?);
42
43        cc.provide_transport(Arc::new(MlsTransportSuccessProvider::default()))
44            .await;
45
46        Ok(Self {
47            cc,
48            client_id: client_id.into_bytes().into(),
49            #[cfg(feature = "proteus")]
50            prekey_last_id: Cell::new(0),
51        })
52    }
53}
54
55#[async_trait::async_trait(?Send)]
56impl EmulatedClient for CoreCryptoNativeClient {
57    fn client_name(&self) -> &str {
58        "CoreCrypto::native"
59    }
60
61    fn client_type(&self) -> EmulatedClientType {
62        EmulatedClientType::Native
63    }
64
65    fn client_id(&self) -> &[u8] {
66        self.client_id.as_slice()
67    }
68
69    fn client_protocol(&self) -> EmulatedClientProtocol {
70        EmulatedClientProtocol::MLS | EmulatedClientProtocol::PROTEUS
71    }
72
73    async fn wipe(mut self) -> Result<()> {
74        drop(self.cc);
75        Ok(())
76    }
77}
78
79#[async_trait::async_trait(?Send)]
80impl EmulatedMlsClient for CoreCryptoNativeClient {
81    async fn get_keypackage(&self) -> Result<Vec<u8>> {
82        let transaction = self.cc.new_transaction().await?;
83        let start = std::time::Instant::now();
84        let kp = transaction
85            .get_or_create_client_keypackages(CIPHERSUITE_IN_USE.into(), MlsCredentialType::Basic, 1)
86            .await?
87            .pop()
88            .unwrap();
89
90        log::info!(
91            "KP Init Key [took {}ms]: Client {} [{}] - {}",
92            start.elapsed().as_millis(),
93            self.client_name(),
94            hex::encode(&self.client_id),
95            hex::encode(kp.hpke_init_key()),
96        );
97        transaction.finish().await?;
98
99        Ok(kp.tls_serialize_detached()?)
100    }
101
102    async fn add_client(&self, conversation_id: &[u8], kp: &[u8]) -> Result<()> {
103        let conversation_id = conversation_id.to_vec();
104        let transaction = self.cc.new_transaction().await?;
105        if !transaction.conversation_exists(&conversation_id).await? {
106            let config = MlsConversationConfiguration {
107                ciphersuite: CIPHERSUITE_IN_USE.into(),
108                ..Default::default()
109            };
110            transaction
111                .new_conversation(&conversation_id, MlsCredentialType::Basic, config)
112                .await?;
113        }
114
115        use tls_codec::Deserialize as _;
116
117        let kp = KeyPackageIn::tls_deserialize(&mut &kp[..])?;
118        transaction
119            .conversation(&conversation_id)
120            .await?
121            .add_members(vec![kp])
122            .await?;
123        transaction.finish().await?;
124
125        Ok(())
126    }
127
128    async fn kick_client(&self, conversation_id: &[u8], client_id: &[u8]) -> Result<()> {
129        let transaction = self.cc.new_transaction().await?;
130        transaction
131            .conversation(&conversation_id.to_owned())
132            .await?
133            .remove_members(&[client_id.to_owned().into()])
134            .await?;
135        transaction.finish().await?;
136
137        Ok(())
138    }
139
140    async fn process_welcome(&self, welcome: &[u8]) -> Result<Vec<u8>> {
141        let transaction = self.cc.new_transaction().await?;
142
143        let result = transaction
144            .process_raw_welcome_message(welcome.into(), MlsCustomConfiguration::default())
145            .await?
146            .id;
147        transaction.finish().await?;
148        Ok(result)
149    }
150
151    async fn encrypt_message(&self, conversation_id: &[u8], message: &[u8]) -> Result<Vec<u8>> {
152        let transaction = self.cc.new_transaction().await?;
153        let result = transaction
154            .conversation(&conversation_id.to_vec())
155            .await?
156            .encrypt_message(message)
157            .await?;
158        transaction.finish().await?;
159        Ok(result)
160    }
161
162    async fn decrypt_message(&self, conversation_id: &[u8], message: &[u8]) -> Result<Option<Vec<u8>>> {
163        let transaction = self.cc.new_transaction().await?;
164        let result = transaction
165            .conversation(&conversation_id.to_vec())
166            .await?
167            .decrypt_message(message)
168            .await?
169            .app_msg;
170        transaction.finish().await?;
171        Ok(result)
172    }
173}
174
175#[cfg(feature = "proteus")]
176#[async_trait::async_trait(?Send)]
177impl crate::clients::EmulatedProteusClient for CoreCryptoNativeClient {
178    async fn init(&mut self) -> Result<()> {
179        let transaction = self.cc.new_transaction().await?;
180        transaction.proteus_init().await?;
181        Ok(transaction.finish().await?)
182    }
183
184    async fn get_prekey(&self) -> Result<Vec<u8>> {
185        let transaction = self.cc.new_transaction().await?;
186        let prekey_last_id = self.prekey_last_id.get() + 1;
187        self.prekey_last_id.replace(prekey_last_id);
188        let result = transaction.proteus_new_prekey(prekey_last_id).await?;
189        transaction.finish().await?;
190        Ok(result)
191    }
192
193    async fn session_from_prekey(&self, session_id: &str, prekey: &[u8]) -> Result<()> {
194        let transaction = self.cc.new_transaction().await?;
195        let _ = transaction.proteus_session_from_prekey(session_id, prekey).await?;
196        transaction.finish().await?;
197        Ok(())
198    }
199
200    async fn session_from_message(&self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
201        let transaction = self.cc.new_transaction().await?;
202        let (_, ret) = transaction.proteus_session_from_message(session_id, message).await?;
203        transaction.finish().await?;
204        Ok(ret)
205    }
206
207    async fn encrypt(&self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
208        let transaction = self.cc.new_transaction().await?;
209        let result = transaction.proteus_encrypt(session_id, plaintext).await?;
210        transaction.finish().await?;
211        Ok(result)
212    }
213
214    async fn decrypt(&self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
215        let transaction = self.cc.new_transaction().await?;
216        let result = transaction.proteus_decrypt(session_id, ciphertext).await?;
217        transaction.finish().await?;
218        Ok(result)
219    }
220
221    async fn fingerprint(&self) -> Result<String> {
222        Ok(self.cc.proteus_fingerprint().await?)
223    }
224}