use alloc::vec::Vec;
use sha2::{Digest, Sha256};
use crate::cryptomat::{
ClientRandomValue,
CryptoAlg,
DeriveAuthKeyForAuth,
DeriveMasterKeyForAuth,
HashedAuthenticationKey,
Pk,
PwHash,
SignK,
SignKeyComposer,
SignKeyPair,
Sk,
SkComposer,
StaticKeyPair,
SymKeyGen,
VerifyK,
};
use crate::error::Error;
pub struct RegisterOutPut<P: Pk, V: VerifyK, CRV: ClientRandomValue, HAK: HashedAuthenticationKey>
{
pub master_key_alg: &'static str,
pub client_random_value: CRV,
pub hashed_authentication_key_bytes: HAK,
pub encrypted_master_key: Vec<u8>,
pub encrypted_master_key_alg: &'static str,
pub derived_alg: &'static str,
pub public_key: P,
pub encrypted_private_key: Vec<u8>,
pub keypair_encrypt_alg: &'static str,
pub verify_key: V,
pub encrypted_sign_key: Vec<u8>,
pub keypair_sign_alg: &'static str,
}
pub struct LoginDoneOutput<S: Sk, Si: SignK>
{
pub private_key: S,
pub sign_key: Si,
}
pub struct ChangePasswordOutput<CRV: ClientRandomValue, HAK: HashedAuthenticationKey, DAK: DeriveAuthKeyForAuth>
{
pub client_random_value: CRV,
pub hashed_authentication_key_bytes: HAK,
pub encrypted_master_key: Vec<u8>,
pub encrypted_master_key_alg: &'static str,
pub derived_alg: &'static str,
pub old_auth_key: DAK,
}
pub struct ResetPasswordOutput<CRV: ClientRandomValue, HAK: HashedAuthenticationKey>
{
pub master_key_alg: &'static str,
pub client_random_value: CRV,
pub hashed_authentication_key_bytes: HAK,
pub encrypted_master_key: Vec<u8>,
pub encrypted_master_key_alg: &'static str,
pub derived_alg: &'static str,
pub encrypted_private_key: Vec<u8>,
pub encrypted_sign_key: Vec<u8>,
}
pub struct PrepareLoginOutput<DMK: DeriveMasterKeyForAuth, DAK: DeriveAuthKeyForAuth>
{
pub master_key_encryption_key: DMK,
pub auth_key: DAK,
}
#[allow(clippy::type_complexity)]
pub fn register<S: SymKeyGen, St: StaticKeyPair, Sign: SignKeyPair, H: PwHash>(
password: &str,
) -> Result<RegisterOutPut<St::PublicKey, Sign::VerifyKey, H::CRV, H::HAK>, Error>
{
let master_key = S::generate()?;
let (sk, public_key) = St::generate_static_keypair()?;
let (sign_k, verify_key) = Sign::generate_key_pair()?;
let encrypted_private_key = sk.encrypt_by_master_key(&master_key)?;
let encrypted_sign_key = sign_k.encrypt_by_master_key(&master_key)?;
let (client_random_value, hashed_authentication_key_bytes, encrypted_master_key, encrypted_master_key_alg) =
H::derived_keys_from_password(password.as_bytes(), &master_key, None)?;
Ok(RegisterOutPut {
master_key_alg: master_key.get_alg_str(),
derived_alg: client_random_value.get_alg_str(),
client_random_value,
hashed_authentication_key_bytes,
encrypted_master_key,
encrypted_master_key_alg,
encrypted_sign_key,
verify_key,
keypair_sign_alg: sign_k.get_alg_str(),
encrypted_private_key,
public_key,
keypair_encrypt_alg: sk.get_alg_str(),
})
}
pub fn prepare_login<H: PwHash>(password: &str, salt: &[u8], derived_encryption_key_alg: &str) -> Result<PrepareLoginOutput<H::DMK, H::DAK>, Error>
{
let (master_key_encryption_key, auth_key) = H::derive_keys_for_auth(password.as_bytes(), salt, derived_encryption_key_alg)?;
Ok(PrepareLoginOutput {
master_key_encryption_key,
auth_key,
})
}
pub fn done_login<SkC: SkComposer, SiC: SignKeyComposer>(
derived_encryption_key: &impl DeriveMasterKeyForAuth, encrypted_master_key: &[u8], encrypted_private_key: &[u8],
keypair_encrypt_alg: &str,
encrypted_sign_key: &[u8],
keypair_sign_alg: &str,
) -> Result<LoginDoneOutput<SkC::SecretKey, SiC::Key>, Error>
{
let master_key = derived_encryption_key.get_master_key(encrypted_master_key)?;
let private_key = SkC::decrypt_by_master_key(&master_key, encrypted_private_key, keypair_encrypt_alg)?;
let sign_key = SiC::decrypt_by_master_key(&master_key, encrypted_sign_key, keypair_sign_alg)?;
Ok(LoginDoneOutput {
private_key,
sign_key,
})
}
#[allow(clippy::type_complexity)]
pub fn change_password<H: PwHash>(
old_pw: &str,
new_pw: &str,
old_salt: &[u8],
encrypted_master_key: &[u8],
derived_encryption_key_alg: &str,
) -> Result<ChangePasswordOutput<H::CRV, H::HAK, H::DAK>, Error>
{
let prepare_login_output = prepare_login::<H>(old_pw, old_salt, derived_encryption_key_alg)?;
let master_key = prepare_login_output
.master_key_encryption_key
.get_master_key(encrypted_master_key)?;
let (client_random_value, hashed_authentication_key_bytes, encrypted_master_key, encrypted_master_key_alg) =
H::derived_keys_from_password(new_pw.as_bytes(), &master_key, Some(derived_encryption_key_alg))?;
Ok(ChangePasswordOutput {
derived_alg: client_random_value.get_alg_str(),
client_random_value,
hashed_authentication_key_bytes,
encrypted_master_key,
encrypted_master_key_alg,
old_auth_key: prepare_login_output.auth_key,
})
}
pub fn password_reset<S: SymKeyGen, H: PwHash>(
new_pw: &str,
decrypted_private_key: &impl Sk,
decrypted_sign_key: &impl SignK,
) -> Result<ResetPasswordOutput<H::CRV, H::HAK>, Error>
{
let master_key = S::generate()?;
let encrypted_private_key = decrypted_private_key.encrypt_by_master_key(&master_key)?;
let encrypted_sign_key = decrypted_sign_key.encrypt_by_master_key(&master_key)?;
let (client_random_value, hashed_authentication_key_bytes, encrypted_master_key, encrypted_master_key_alg) =
H::derived_keys_from_password(new_pw.as_bytes(), &master_key, None)?;
Ok(ResetPasswordOutput {
master_key_alg: master_key.get_alg_str(),
derived_alg: client_random_value.get_alg_str(),
client_random_value,
hashed_authentication_key_bytes,
encrypted_master_key,
encrypted_master_key_alg,
encrypted_private_key,
encrypted_sign_key,
})
}
pub fn safety_number<Vk: VerifyK>(
user_1_verify_key: &Vk,
user_1_user_info: &str,
user_2_verify_key: Option<&Vk>,
user_2_user_info: Option<&str>,
) -> Vec<u8>
{
let mut hasher = Sha256::new();
user_1_verify_key.create_hash(&mut hasher);
hasher.update(user_1_user_info.as_bytes());
if let (Some(u_2), Some(u_2_i)) = (user_2_verify_key, user_2_user_info) {
u_2.create_hash(&mut hasher);
hasher.update(u_2_i.as_bytes());
}
let number_bytes = hasher.finalize();
number_bytes.to_vec()
}