use chacha20poly1305::{
aead::{AeadMut, Key, Nonce, OsRng},
AeadCore, KeyInit, XChaCha20Poly1305,
};
use crate::error::Error;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
pub mod keyring;
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
pub type PlatformKeyStore = keyring::KeyStore;
const NONCE_SIZE: usize = 24;
pub fn encrypt(data: &[u8], key: Vec<u8>) -> Result<Vec<u8>, Error> {
let key = Key::<XChaCha20Poly1305>::from_iter(key);
let mut cipher = XChaCha20Poly1305::new(&key);
let nonce = generate_nonce();
let mut encrypted = cipher.encrypt(&nonce, data)?;
encrypted.reserve(nonce.len());
encrypted.extend(nonce.as_slice());
Ok(encrypted)
}
pub fn decrypt(mut data: Vec<u8>, key: Vec<u8>) -> Result<Vec<u8>, Error> {
let key = Key::<XChaCha20Poly1305>::from_iter(key);
let mut cipher = XChaCha20Poly1305::new(&key);
let nonce_data = data
.drain(data.len() - NONCE_SIZE..data.len())
.collect::<Vec<_>>();
let nonce = Nonce::<XChaCha20Poly1305>::from_slice(nonce_data.as_slice());
Ok(cipher.decrypt(nonce, data.as_slice())?)
}
pub fn generate_key() -> Key<XChaCha20Poly1305> {
XChaCha20Poly1305::generate_key(OsRng)
}
pub fn generate_nonce() -> Nonce<XChaCha20Poly1305> {
XChaCha20Poly1305::generate_nonce(OsRng)
}
pub fn namespace() -> Result<String, Error> {
let process = std::env::current_exe()?;
Ok(process
.file_name()
.expect("Failed to get file name")
.to_string_lossy()
.to_string())
}
pub trait KeyStore {
fn get_key_or_generate(name: &str) -> Result<Vec<u8>, Error> {
let key = Self::get_key(name)?;
if let Some(key) = key {
Ok(key)
} else {
let key = generate_key();
Self::set_key(name, key.to_vec())?;
Ok(key.to_vec())
}
}
fn get_key(name: &str) -> Result<Option<Vec<u8>>, Error>;
fn set_key(name: &str, key: Vec<u8>) -> Result<(), Error>;
}