use ring::aead::{self, LessSafeKey, Nonce, UnboundKey, AES_256_GCM};
use ring::rand::{SecureRandom, SystemRandom};
use crate::error::HexvaultError;
const ALGORITHM: &aead::Algorithm = &AES_256_GCM;
pub const NONCE_LEN: usize = 12;
pub const KEY_LEN: usize = 32;
fn generate_nonce() -> Result<([u8; NONCE_LEN], Nonce), HexvaultError> {
let rng = SystemRandom::new();
let mut buf = [0u8; NONCE_LEN];
rng.fill(&mut buf)
.map_err(|_| HexvaultError::RandomnessFailure)?;
Ok((buf, Nonce::assume_unique_for_key(buf)))
}
pub fn encrypt(
key_bytes: &[u8; KEY_LEN],
plaintext: &[u8],
aad_bytes: &[u8],
) -> Result<Vec<u8>, HexvaultError> {
let unbound = UnboundKey::new(ALGORITHM, key_bytes).map_err(|_| HexvaultError::InvalidKey)?;
let key = LessSafeKey::new(unbound);
let (nonce_bytes, nonce) = generate_nonce()?;
let aad = aead::Aad::from(aad_bytes);
let mut buffer = plaintext.to_vec();
key.seal_in_place_append_tag(nonce, aad, &mut buffer)
.map_err(|_| HexvaultError::EncryptionFailure)?;
let mut output = Vec::with_capacity(NONCE_LEN + buffer.len());
output.extend_from_slice(&nonce_bytes);
output.extend_from_slice(&buffer);
Ok(output)
}
pub fn decrypt(
key_bytes: &[u8; KEY_LEN],
ciphertext: &[u8],
aad_bytes: &[u8],
) -> Result<Vec<u8>, HexvaultError> {
if ciphertext.len() < NONCE_LEN {
return Err(HexvaultError::DecryptionFailure);
}
let nonce_bytes: [u8; NONCE_LEN] = ciphertext[..NONCE_LEN]
.try_into()
.map_err(|_| HexvaultError::DecryptionFailure)?;
let nonce = Nonce::assume_unique_for_key(nonce_bytes);
let unbound = UnboundKey::new(ALGORITHM, key_bytes).map_err(|_| HexvaultError::InvalidKey)?;
let key = LessSafeKey::new(unbound);
let aad = aead::Aad::from(aad_bytes);
let mut payload = ciphertext[NONCE_LEN..].to_vec();
let plaintext = key
.open_in_place(nonce, aad, &mut payload)
.map_err(|_| HexvaultError::DecryptionFailure)?;
Ok(plaintext.to_vec())
}
pub fn generate_random_key() -> Result<[u8; KEY_LEN], HexvaultError> {
let rng = SystemRandom::new();
let mut key = [0u8; KEY_LEN];
rng.fill(&mut key)
.map_err(|_| HexvaultError::RandomnessFailure)?;
Ok(key)
}