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