interop/clients/corecrypto/
native.rs1use 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}