use secrecy::SecretBox;
use sha2::{Digest, Sha256};
use windows::{
Security::{
Credentials::{KeyCredentialCreationOption, KeyCredentialManager, KeyCredentialStatus},
Cryptography::CryptographicBuffer,
},
core::{Array, HSTRING},
};
use crate::error::{DefendorError, DefendorResult};
pub fn derive_key_by_biometric_impl(
challenge: &[u8],
name: &str,
) -> DefendorResult<SecretBox<Vec<u8>>> {
let name = HSTRING::from(name);
let result = match KeyCredentialManager::OpenAsync(&name)?.get() {
Ok(open_res) => open_res,
Err(_) => {
let create_res = KeyCredentialManager::RequestCreateAsync(
&name,
KeyCredentialCreationOption::FailIfExists,
)?
.get()?;
if create_res.Status()? != KeyCredentialStatus::Success {
return Err(DefendorError::BiometricInitializationFailed);
}
create_res
}
};
let credential = result.Credential()?;
let challenge_buffer = CryptographicBuffer::CreateFromByteArray(challenge)?;
let signature = credential.RequestSignAsync(&challenge_buffer)?.get()?;
if signature.Status()? != KeyCredentialStatus::Success {
return Err(DefendorError::BiometricInitializationFailed);
}
let signature_buffer = signature.Result()?;
let mut signature_value = Array::<u8>::with_len(signature_buffer.Length()? as usize);
CryptographicBuffer::CopyToByteArray(&signature_buffer, &mut signature_value)?;
let key = Sha256::digest(signature_value.as_ref());
Ok(SecretBox::new(Box::new(key.to_vec())))
}