use std::convert::TryInto;
use data_encoding::HEXLOWER;
use ring::rand::SecureRandom;
use ring::{aead, rand};
use thiserror::Error;
#[cfg(feature = "application")]
use crate::application::Application;
#[cfg(feature = "application")]
#[cfg_attr(docsrs, doc(cfg(feature = "application")))]
pub trait AppWithAeadKey: Application {
fn key(&self) -> &Key;
}
pub struct Key(aead::LessSafeKey);
impl Key {
pub fn new(secret: &[u8; 32]) -> Self {
Self(aead::LessSafeKey::new(
aead::UnboundKey::new(&aead::CHACHA20_POLY1305, secret).unwrap(),
))
}
pub fn from_hex_lower(s: &[u8]) -> Result<Self, Error> {
let bytes = HEXLOWER
.decode(s)
.map_err(|_| Error::InvalidKeyCharacters)?;
Ok(Self::new(
(&*bytes).try_into().map_err(|_| Error::InvalidKeyLength)?,
))
}
pub fn decrypt<'a>(&self, aad: &[u8], input: &'a mut [u8]) -> Result<&'a [u8], Error> {
if input.len() <= NONCE_LEN {
return Err(Error::Decryption);
}
let ad = aead::Aad::from(aad);
let (sealed, nonce) = input.split_at_mut(input.len() - NONCE_LEN);
aead::Nonce::try_assume_unique_for_key(nonce)
.and_then(move |nonce| self.0.open_in_place(nonce, ad, sealed))
.map(|plain| &*plain)
.map_err(|_| Error::Decryption)
}
pub fn encrypt(&self, aad: &[u8], buf: &mut Vec<u8>) -> Result<(), Error> {
let mut nonce_buf = [0; NONCE_LEN];
rand::SystemRandom::new()
.fill(&mut nonce_buf)
.map_err(|_| Error::GetRandomFailed)?;
let nonce = aead::Nonce::try_assume_unique_for_key(&nonce_buf).unwrap();
let aad = aead::Aad::from(aad);
self.0.seal_in_place_append_tag(nonce, aad, buf).unwrap(); buf.extend(nonce_buf);
Ok(())
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error("failed to decrypt")]
Decryption,
#[error("failed to acquire random bytes for nonce")]
GetRandomFailed,
#[error("invalid key characters")]
InvalidKeyCharacters,
#[error("invalid key length")]
InvalidKeyLength,
}
pub(crate) const NONCE_LEN: usize = 12;
#[cfg(all(feature = "cookies", feature = "application"))]
pub(crate) const TAG_LEN: usize = 16;