Skip to main content

schul_cloud_api/requests/
about.rs

1use crate::errors::Errors;
2use crate::request_types::about;
3use crate::request_types::about::{EncryptedPrivateKeyData, RSAPrivateKey, RSAPublicKey};
4use crate::requests::post_request;
5use crate::state::{EncryptionState, State};
6use crate::types::user::companies::Company;
7use crate::types::user::general::UserInfo;
8use crate::types::user::others::User;
9use crate::Result;
10use base64::Engine;
11use openssl::hash::MessageDigest;
12use openssl::rsa::Padding;
13use openssl::symm::Cipher;
14
15const BASE64: base64::engine::GeneralPurpose = base64::engine::general_purpose::STANDARD;
16
17pub async fn get_user_info(state: &State) -> Result<UserInfo> {
18    Ok(post_request::<about::UserInfoResponse>(state, "/users/me", about::UserInfoRequest::new(state, false)?).await?.user)
19}
20pub async fn get_companies(state: &State) -> Result<Vec<Company>> {
21    Ok(post_request::<about::CompanyResponse>(state, "/company/member", about::CompanyRequest::new(state)?).await?.companies)
22}
23pub async fn get_encryption_state(state: &State, passphrase: String) -> Result<EncryptionState> {
24    // load the encryption key
25    let encrypt = post_request::<about::PrivateKeyResponse>(state,
26                                                            "/security/get_private_key",
27                                                            about::PrivateKeyRequest::new(state, "jwk", "encryption")?).await?;
28    // private key info is stored as a string containing JSON data.
29    let encrypted_private_key_info: EncryptedPrivateKeyData = serde_json::from_str(&*encrypt.keys.private_key)?;
30
31    // derive key decryption AES key
32    let derivation_properties = encrypted_private_key_info.key_derivation_properties
33        .ok_or(Errors::ValueError("API didn't respond with key derivation properties".to_string()))?;
34    let mut derived_key = vec![0;32];
35    let salt = BASE64.decode(derivation_properties.salt)?;
36    openssl::pkcs5::pbkdf2_hmac(passphrase.as_bytes(), &*salt, derivation_properties.iterations, MessageDigest::sha256(), &mut *derived_key)?;
37
38    // load the encryption keys
39    let iv = BASE64.decode(encrypted_private_key_info.iv)?;
40    let encrypted_private_encrypt = BASE64.decode(encrypted_private_key_info.ciphertext)?;
41    let decrypted_encrypt = openssl::symm::decrypt(Cipher::aes_256_cbc(), &*derived_key, Some(&*iv), &*encrypted_private_encrypt)?;
42    let private_encrypt = RSAPrivateKey::from_decrypted(decrypted_encrypt)?.to_key()?;
43    let public_encrypt = RSAPublicKey::from_str(&*encrypt.keys.public_key)?.to_key()?;
44
45    // load signing key
46    let sign = post_request::<about::PrivateKeyResponse>(state,
47                                                         "/security/get_private_key",
48                                                         about::PrivateKeyRequest::new(state, "jwk", "signing")?).await?;
49    let encrypted_sing: EncryptedPrivateKeyData = serde_json::from_str(&*sign.keys.private_key).map_err(|e| Errors::JsonDeserializeError(e))?;
50    let encrypted_kek = encrypted_sing.encryptedKEK.ok_or(Errors::ValueError("No Key Encryption Key (KEK)".to_string()))?;
51    let encrypted_kek = BASE64.decode(encrypted_kek)?;
52
53    // decrypt kek
54    let mut decrypted_kek = vec![0; private_encrypt.size() as usize];
55    if private_encrypt.private_decrypt(&*encrypted_kek, &mut *decrypted_kek, Padding::PKCS1_OAEP)? != 32 {
56        return Err(Errors::ValueError("decrypted AES key is not 256 bits long".to_string()));
57    };
58    decrypted_kek.truncate(32);
59
60    //decrypt RSA key
61    let iv = BASE64.decode(encrypted_sing.iv)?;
62    let encrypted_signing_key = BASE64.decode(encrypted_sing.ciphertext)?;
63    let decrypted_signing_key = openssl::symm::decrypt(Cipher::aes_256_cbc(), &*decrypted_kek, Some(&*iv), &*encrypted_signing_key)?;
64    let private_sign= RSAPrivateKey::from_decrypted(decrypted_signing_key)?.to_key()?;
65    let public_sign = RSAPublicKey::from_str(&*sign.keys.public_key)?.to_key()?;
66    Ok(EncryptionState::new(private_encrypt, public_encrypt, private_sign, public_sign))
67}
68pub async fn get_other_user_info(state: &State, user_id: String) -> Result<User> {
69    Ok(post_request::<about::OtherUserInfoResponse>(state,
70                                                    "/users/info",
71                                                    about::OtherUserInfoRequest::new(state, user_id, true)?)
72        .await?.user)
73}