#[cfg_attr(target_os = "macos", path = "macos.rs")]
mod platform_impl;
use aes_gcm::aead::AeadMutInPlace;
use aes_gcm::aead::generic_array::GenericArray;
use aes_gcm::{Aes256Gcm, KeyInit};
use serde::{Deserialize, Serialize};
use std::io::{Error, ErrorKind};
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum AuthLevel {
Unauthenticated,
Interactive,
Biometry,
}
impl TryFrom<&str> for AuthLevel {
type Error = Error;
fn try_from(value: &str) -> Result<Self, Self::Error> {
match value {
"unauthenticated" => Ok(Self::Unauthenticated),
"interactive" => Ok(Self::Interactive),
"biometry" => Ok(Self::Biometry),
_ => Err(Error::new(ErrorKind::InvalidInput, format!("Invalid authentication level: {value}"))),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
struct SealedKey {
#[serde(with = "serde_bytes")]
nonce: [u8; 12],
#[serde(with = "serde_bytes")]
ciphertext: Vec<u8>,
#[serde(with = "serde_bytes")]
mac: [u8; 16],
}
pub fn create(auth_level: AuthLevel) -> Result<Vec<u8>, Error> {
platform_impl::create(auth_level)
}
pub fn unlock(metadata: &[u8], user_auth: Option<&[u8]>) -> Result<[u8; 32], Error> {
platform_impl::unlock(metadata, user_auth)
}
pub fn wrap(key: &[u8], key_encryption_key: &[u8; 32]) -> Result<Vec<u8>, Error> {
let mut nonce = [0; 12];
getrandom::fill(&mut nonce)?;
let nonce = GenericArray::from_slice(&nonce);
let key_encryption_key_ = GenericArray::from_slice(key_encryption_key);
let mut aes256_gcm = Aes256Gcm::new(key_encryption_key_);
let mut key = key.to_vec();
let mac = aes256_gcm.encrypt_in_place_detached(nonce, b"", &mut key).expect("failed to seal key");
let sealed_key = SealedKey { nonce: (*nonce).into(), ciphertext: key, mac: mac.into() };
let sealed_key = serde_asn1_der::to_vec(&sealed_key).expect("failed to serialize ciphertext");
Ok(sealed_key)
}
pub fn unwrap(sealed_key: &[u8], key_encryption_key: &[u8; 32]) -> Result<Vec<u8>, Error> {
let SealedKey { nonce, ciphertext: mut chiphertext, mac } =
serde_asn1_der::from_bytes(&sealed_key).map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
let nonce = GenericArray::from_slice(&nonce);
let mac = GenericArray::from_slice(&mac);
let key_encryption_key = GenericArray::from_slice(key_encryption_key);
let mut aes256_gcm = Aes256Gcm::new(key_encryption_key);
(aes256_gcm.decrypt_in_place_detached(nonce, b"", &mut chiphertext, mac))
.map_err(|e| Error::new(ErrorKind::InvalidInput, e))?;
Ok(chiphertext)
}