1use alloc::string::{String, ToString};
2
3use base64ct::{Base64, Encoding};
4use sentc_crypto_common::user::{
5 ChangePasswordData,
6 DoneLoginServerInput,
7 DoneLoginServerKeysOutput,
8 DoneLoginServerOutput,
9 DoneLoginServerReturn,
10 JwtRefreshInput,
11 OtpInput,
12 PrepareLoginSaltServerOutput,
13 PrepareLoginServerInput,
14 UserPublicKeyData,
15 UserUpdateServerInput,
16 UserVerifyKeyData,
17 VerifyLoginInput,
18};
19use sentc_crypto_common::{DeviceId, UserId};
20use sentc_crypto_core::cryptomat::{DeriveMasterKeyForAuth, PwHash, Sk};
21use serde::{Deserialize, Serialize};
22
23use crate::cryptomat::{PkWrapper, SignComposerWrapper, SignKWrapper, SkWrapper, StaticKeyComposerWrapper, VerifyKWrapper};
24use crate::error::SdkUtilError;
25use crate::{client_random_value_to_string, derive_auth_key_for_auth_to_string, handle_server_response, hashed_authentication_key_to_string};
26
27pub struct DeviceKeyDataInt<Sk: SkWrapper, Pk: PkWrapper, SiK: SignKWrapper, Vk: VerifyKWrapper>
36{
37 pub private_key: Sk,
38 pub sign_key: SiK,
39 pub public_key: Pk,
40 pub verify_key: Vk,
41 pub exported_public_key: UserPublicKeyData,
42 pub exported_verify_key: UserVerifyKeyData,
43}
44
45#[derive(Serialize, Deserialize)]
46pub struct DeviceKeyDataExport
47{
48 pub private_key: String, pub public_key: String,
50 pub sign_key: String,
51 pub verify_key: String,
52 pub exported_public_key: String,
53 pub exported_verify_key: String,
54}
55
56impl<Sk: SkWrapper, Pk: PkWrapper, SiK: SignKWrapper, Vk: VerifyKWrapper> TryFrom<DeviceKeyDataInt<Sk, Pk, SiK, Vk>> for DeviceKeyDataExport
57{
58 type Error = SdkUtilError;
59
60 fn try_from(value: DeviceKeyDataInt<Sk, Pk, SiK, Vk>) -> Result<Self, Self::Error>
61 {
62 Ok(Self {
63 private_key: value.private_key.to_string()?,
64 public_key: value.public_key.to_string()?,
65 sign_key: value.sign_key.to_string()?,
66 verify_key: value.verify_key.to_string()?,
67 exported_public_key: value
68 .exported_public_key
69 .to_string()
70 .map_err(|_e| SdkUtilError::JsonToStringFailed)?,
71 exported_verify_key: value
72 .exported_verify_key
73 .to_string()
74 .map_err(|_e| SdkUtilError::JsonToStringFailed)?,
75 })
76 }
77}
78
79pub struct UserPreVerifyLogin<Sk: SkWrapper, Pk: PkWrapper, SiK: SignKWrapper, Vk: VerifyKWrapper>
80{
81 pub challenge: String,
82 pub device_keys: DeviceKeyDataInt<Sk, Pk, SiK, Vk>,
83 pub user_id: UserId,
84 pub device_id: DeviceId,
85}
86
87fn decrypt_login_challenge(private_key: &impl SkWrapper, challenge: &str) -> Result<String, SdkUtilError>
88{
89 let challenge = Base64::decode_vec(challenge).map_err(|_| SdkUtilError::DecryptingLoginChallengeFailed)?;
92
93 let decrypted = private_key.get_key().decrypt(&challenge)?;
94
95 String::from_utf8(decrypted).map_err(|_| SdkUtilError::DecryptingLoginChallengeFailed)
96}
97
98pub fn prepare_login_start(user_identifier: &str) -> Result<String, SdkUtilError>
103{
104 PrepareLoginServerInput {
105 user_identifier: user_identifier.to_string(),
106 }
107 .to_string()
108 .map_err(|_| SdkUtilError::JsonToStringFailed)
109}
110
111pub fn prepare_login<H: PwHash>(user_identifier: &str, password: &str, server_output: &str) -> Result<(String, String, H::DMK), SdkUtilError>
118{
119 let server_output: PrepareLoginSaltServerOutput = handle_server_response(server_output)?;
120
121 let salt = Base64::decode_vec(server_output.salt_string.as_str()).map_err(|_| SdkUtilError::DecodeSaltFailed)?;
122 let result = sentc_crypto_core::user::prepare_login::<H>(password, &salt, server_output.derived_encryption_key_alg.as_str())?;
123
124 let auth_key = derive_auth_key_for_auth_to_string(&result.auth_key);
126
127 let input = DoneLoginServerInput {
128 auth_key: auth_key.clone(),
129 device_identifier: user_identifier.to_string(),
130 }
131 .to_string()
132 .map_err(|_| SdkUtilError::JsonToStringFailed)?;
133
134 Ok((input, auth_key, result.master_key_encryption_key))
135}
136
137pub fn check_done_login(server_output: &str) -> Result<DoneLoginServerReturn, SdkUtilError>
138{
139 let server_output: DoneLoginServerReturn = handle_server_response(server_output)?;
140
141 Ok(server_output)
142}
143
144pub fn prepare_validate_mfa(auth_key: String, device_identifier: String, token: String) -> Result<String, SdkUtilError>
148{
149 serde_json::to_string(&OtpInput {
150 token,
151 auth_key,
152 device_identifier,
153 })
154 .map_err(|_| SdkUtilError::JsonToStringFailed)
155}
156
157pub fn done_validate_mfa<SkC: StaticKeyComposerWrapper, SiKC: SignComposerWrapper>(
161 master_key_encryption: &impl DeriveMasterKeyForAuth,
162 auth_key: String,
163 device_identifier: String,
164 server_output: &str,
165) -> Result<
166 UserPreVerifyLogin<
167 <SkC as StaticKeyComposerWrapper>::SkWrapper,
168 <SkC as StaticKeyComposerWrapper>::PkWrapper,
169 <SiKC as SignComposerWrapper>::SignKWrapper,
170 <SiKC as SignComposerWrapper>::VerifyKWrapper,
171 >,
172 SdkUtilError,
173>
174{
175 let server_output: DoneLoginServerOutput = handle_server_response(server_output)?;
176
177 done_login::<SkC, SiKC>(master_key_encryption, auth_key, device_identifier, server_output)
178}
179
180pub fn done_login<SkC: StaticKeyComposerWrapper, SiKC: SignComposerWrapper>(
188 master_key_encryption: &impl DeriveMasterKeyForAuth,
189 auth_key: String,
190 device_identifier: String,
191 server_output: DoneLoginServerOutput,
192) -> Result<
193 UserPreVerifyLogin<
194 <SkC as StaticKeyComposerWrapper>::SkWrapper,
195 <SkC as StaticKeyComposerWrapper>::PkWrapper,
196 <SiKC as SignComposerWrapper>::SignKWrapper,
197 <SiKC as SignComposerWrapper>::VerifyKWrapper,
198 >,
199 SdkUtilError,
200>
201{
202 let device_data = server_output.device_keys;
203
204 let device_keys = done_login_internally_with_device_out::<SkC, SiKC>(master_key_encryption, &device_data)?;
205
206 let challenge = decrypt_login_challenge(&device_keys.private_key, &server_output.challenge)?;
207
208 Ok(UserPreVerifyLogin {
209 device_keys,
210 challenge: serde_json::to_string(&VerifyLoginInput {
211 auth_key,
212 device_identifier,
213 challenge,
214 })
215 .map_err(|_e| SdkUtilError::JsonToStringFailed)?,
216 user_id: device_data.user_id,
217 device_id: device_data.device_id,
218 })
219}
220
221fn done_login_internally_with_device_out<SkC: StaticKeyComposerWrapper, SiKC: SignComposerWrapper>(
222 master_key_encryption: &impl DeriveMasterKeyForAuth,
223 server_output: &DoneLoginServerKeysOutput,
224) -> Result<
225 DeviceKeyDataInt<
226 <SkC as StaticKeyComposerWrapper>::SkWrapper,
227 <SkC as StaticKeyComposerWrapper>::PkWrapper,
228 <SiKC as SignComposerWrapper>::SignKWrapper,
229 <SiKC as SignComposerWrapper>::VerifyKWrapper,
230 >,
231 SdkUtilError,
232>
233{
234 let encrypted_master_key = Base64::decode_vec(server_output.encrypted_master_key.as_str()).map_err(|_| SdkUtilError::DerivedKeyWrongFormat)?;
235 let encrypted_private_key = Base64::decode_vec(server_output.encrypted_private_key.as_str()).map_err(|_| SdkUtilError::DerivedKeyWrongFormat)?;
236 let encrypted_sign_key = Base64::decode_vec(server_output.encrypted_sign_key.as_str()).map_err(|_| SdkUtilError::DerivedKeyWrongFormat)?;
237
238 let out = sentc_crypto_core::user::done_login::<SkC::Composer, SiKC::Composer>(
239 master_key_encryption,
240 &encrypted_master_key,
241 &encrypted_private_key,
242 server_output.keypair_encrypt_alg.as_str(),
243 &encrypted_sign_key,
244 server_output.keypair_sign_alg.as_str(),
245 )?;
246
247 let public_key = SkC::pk_from_pem(
249 &server_output.public_key_string,
250 &server_output.keypair_encrypt_alg,
251 server_output.keypair_encrypt_id.clone(),
252 )?;
253
254 let verify_key = SiKC::vk_from_pem(
255 &server_output.verify_key_string,
256 &server_output.keypair_sign_alg,
257 server_output.keypair_sign_id.clone(),
258 )?;
259
260 let private_key = SkC::sk_from_inner(out.private_key, server_output.keypair_encrypt_id.clone());
261
262 let sign_key = SiKC::sk_from_inner(out.sign_key, server_output.keypair_sign_id.clone());
263
264 let exported_public_key = UserPublicKeyData {
266 public_key_pem: server_output.public_key_string.to_string(),
267 public_key_alg: server_output.keypair_encrypt_alg.to_string(),
268 public_key_id: server_output.keypair_encrypt_id.clone(),
269 public_key_sig: None, public_key_sig_key_id: None,
271 };
272
273 let exported_verify_key = UserVerifyKeyData {
274 verify_key_pem: server_output.verify_key_string.to_string(),
275 verify_key_alg: server_output.keypair_sign_alg.to_string(),
276 verify_key_id: server_output.keypair_sign_id.clone(),
277 };
278
279 Ok(DeviceKeyDataInt {
280 private_key,
281 sign_key,
282 public_key,
283 verify_key,
284 exported_public_key,
285 exported_verify_key,
286 })
287}
288
289pub fn change_password<H: PwHash>(
296 old_pw: &str,
297 new_pw: &str,
298 server_output_prep_login: &str,
299 server_output_done_login: DoneLoginServerOutput,
300) -> Result<String, SdkUtilError>
301{
302 let server_output_prep_login: PrepareLoginSaltServerOutput = handle_server_response(server_output_prep_login)?;
303
304 let encrypted_master_key = Base64::decode_vec(
305 server_output_done_login
306 .device_keys
307 .encrypted_master_key
308 .as_str(),
309 )
310 .map_err(|_| SdkUtilError::DerivedKeyWrongFormat)?;
311 let old_salt = Base64::decode_vec(server_output_prep_login.salt_string.as_str()).map_err(|_| SdkUtilError::DecodeSaltFailed)?;
312
313 let output = sentc_crypto_core::user::change_password::<H>(
314 old_pw,
315 new_pw,
316 &old_salt,
317 &encrypted_master_key,
318 server_output_prep_login.derived_encryption_key_alg.as_str(),
319 )?;
320
321 let new_encrypted_master_key = Base64::encode_string(&output.encrypted_master_key);
323
324 let new_client_random_value = client_random_value_to_string(&output.client_random_value);
325
326 let new_hashed_authentication_key = hashed_authentication_key_to_string(&output.hashed_authentication_key_bytes);
328
329 let old_auth_key = derive_auth_key_for_auth_to_string(&output.old_auth_key);
330
331 let pw_change_out = ChangePasswordData {
332 new_derived_alg: output.derived_alg.to_string(),
333 new_encrypted_master_key,
334 new_client_random_value,
335 new_hashed_authentication_key,
336 new_encrypted_master_key_alg: output.encrypted_master_key_alg.to_string(),
337 old_auth_key,
338 };
339
340 pw_change_out
341 .to_string()
342 .map_err(|_| SdkUtilError::JsonToStringFailed)
343}
344
345pub fn prepare_refresh_jwt(refresh_token: String) -> Result<String, SdkUtilError>
346{
347 JwtRefreshInput {
348 refresh_token,
349 }
350 .to_string()
351 .map_err(|_| SdkUtilError::JsonToStringFailed)
352}
353
354pub fn prepare_user_identifier_update(user_identifier: String) -> Result<String, SdkUtilError>
355{
356 let input = UserUpdateServerInput {
357 user_identifier,
358 };
359
360 input
361 .to_string()
362 .map_err(|_| SdkUtilError::JsonToStringFailed)
363}