use crate::error::Error;
use crate::file::{AuthSecretFile, NoiseFile, SecretFile};
use crate::types::{
DeviceKey, EncryptedDeviceKey, EncryptedRandomKey, Mask, Password, PublicDeviceKey, RandomKey,
};
use async_std::path::{Path, PathBuf};
use fail::fail_point;
pub struct Generation {
gen: u16,
path: PathBuf,
edk: AuthSecretFile,
erk: SecretFile,
noise: NoiseFile,
pdk: SecretFile,
}
impl Generation {
pub fn new(path: &Path, gen: u16) -> Self {
let path = path.join(gen.to_string());
Self {
gen,
edk: AuthSecretFile::new(path.join("encrypted_device_key")),
erk: SecretFile::new(path.join("encrypted_random_key")),
noise: NoiseFile::new(path.join("noise")),
pdk: SecretFile::new(path.join("public_device_key")),
path,
}
}
pub fn gen(&self) -> u16 {
self.gen
}
pub async fn is_initialized(&self) -> bool {
self.edk.exists().await
}
pub async fn initialize(
&self,
dk: &DeviceKey,
pass: &Password,
force: bool,
) -> Result<(), Error> {
if !force && self.is_initialized().await {
return Err(Error::Initialized);
}
let path = self.edk.parent().expect("joined a file name on init; qed");
async_std::fs::create_dir_all(path).await?;
let rk = RandomKey::generate().await;
let edk = dk.encrypt(&rk).await;
let pdk = rk.public(&pass);
self.pdk.write(&pdk.0).await?;
self.noise.generate().await?;
let nk = self.noise.read_secret().await?;
let erk = rk.encrypt(&nk);
self.erk.write(&erk.0).await?;
fail_point!("edk-write-fail", |_| Err(Error::Corrupted));
self.edk.write(&edk.0).await?;
self.device_key().await?;
Ok(())
}
pub async fn unlock(&self, pass: &Password) -> Result<DeviceKey, Error> {
let pdk = self.public().await?;
let rk = pdk.private(pass);
self.noise.generate().await?;
let nk = self.noise.read_secret().await?;
let erk = rk.encrypt(&nk);
self.erk.write(&erk.0).await?;
self.device_key().await
}
pub async fn lock(&self) -> Result<(), Error> {
self.noise.zeroize().await?;
Ok(())
}
async fn random_key(&self) -> Result<RandomKey, Error> {
let nk = self.noise.read_secret().await?;
let erk = EncryptedRandomKey(self.erk.read().await?);
Ok(erk.decrypt(&nk))
}
pub async fn device_key(&self) -> Result<DeviceKey, Error> {
let rk = self.random_key().await?;
let edk = EncryptedDeviceKey(self.edk.read().await?);
let dk = edk.decrypt(&rk)?;
Ok(dk)
}
pub async fn password(&self) -> Result<Password, Error> {
let rk = self.random_key().await?;
let pdk = self.public().await?;
Ok(rk.password(&pdk))
}
pub async fn public(&self) -> Result<PublicDeviceKey, Error> {
Ok(PublicDeviceKey(self.pdk.read().await?))
}
pub async fn change_password_mask(&self, password: &Password) -> Result<Mask, Error> {
let old_password = self.password().await?;
let mask = old_password.mask(password);
Ok(mask)
}
pub async fn remove(self) -> Result<(), Error> {
fail_point!("gen-rm-fail", |_| Ok(()));
Ok(async_std::fs::remove_dir_all(&self.path).await?)
}
}