use super::*;
pub(in crate::two_factor) fn derive_encryption_key(secret: &str) -> AuthResult<Key<Aes256Gcm>> {
let hkdf = Hkdf::<Sha256>::new(None, secret.as_bytes());
let mut okm = [0u8; 32];
hkdf.expand(ENCRYPTION_INFO, &mut okm).map_err(|error| {
AuthError::internal(format!("Failed to derive encryption key: {error}"))
})?;
Ok(Key::<Aes256Gcm>::from(okm))
}
pub(in crate::two_factor) fn encrypt_value(
secret: &alibi_core::AuthConfig,
plaintext: &str,
) -> AuthResult<String> {
super::super::token_crypto::encrypt_with_config(plaintext, secret)
}
pub(in crate::two_factor) fn decrypt_value(
secret: &alibi_core::AuthConfig,
encrypted: &str,
) -> AuthResult<String> {
super::super::token_crypto::decrypt_with_config(encrypted, secret).or_else(|error| {
if secret.managed_secrets.is_some() {
return Err(error);
}
decrypt_legacy_value(secret.current_secret(), encrypted)
})
}
pub(in crate::two_factor) fn decrypt_legacy_value(
secret: &str,
encrypted: &str,
) -> AuthResult<String> {
let cipher = Aes256Gcm::new(&derive_encryption_key(secret)?);
let bytes = URL_SAFE_NO_PAD.decode(encrypted).map_err(|error| {
AuthError::internal(format!(
"Failed to decode encrypted two-factor data: {error}"
))
})?;
if bytes.len() < 12 {
return Err(AuthError::internal(
"Encrypted two-factor payload is missing the nonce",
));
}
let (nonce_bytes, ciphertext) = bytes.split_at(12);
let nonce: &Nonce<aes_gcm::aead::consts::U12> = nonce_bytes
.try_into()
.map_err(|_error| AuthError::Encryption("Invalid nonce".into()))?;
let plaintext = cipher.decrypt(nonce, ciphertext).map_err(|error| {
AuthError::internal(format!("Failed to decrypt two-factor data: {error}"))
})?;
String::from_utf8(plaintext).map_err(|error| {
AuthError::internal(format!("Two-factor plaintext is not valid UTF-8: {error}"))
})
}