use error::Error;
use ring::aead;
use std::ops::{Deref, DerefMut};
static ALGORITHM: &'static aead::Algorithm = &aead::AES_256_GCM;
pub const NONCE_LEN: usize = 12;
const TAG_LEN: usize = 16;
const EMPTY: &'static [u8] = &[];
#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
pub struct Vault {
pub nonce: [u8; NONCE_LEN],
pub value: Box<[u8]>,
}
pub struct Unlocked<'a> {
len: usize,
key: &'a [u8],
inner: &'a mut Vault,
}
impl Vault {
pub fn new(
key: &[u8],
nonce: [u8; NONCE_LEN],
mut data: Vec<u8>
) -> Result<Vault, Error> {
data.extend_from_slice(&[0; TAG_LEN]);
aead::seal_in_place(
&aead::SealingKey::new(ALGORITHM, key)
.map_err(|_| Error::BadKey)?,
&nonce,
EMPTY,
&mut data[..],
TAG_LEN
).map_err(|_| Error::Encrypt)?;
Ok(Vault {
nonce: nonce,
value: data.into_boxed_slice(),
})
}
pub fn unlock<'a> (
&'a mut self,
key: &'a [u8]
) -> Result<Unlocked<'a>, Error> {
let backup = self.value.clone();
let len = aead::open_in_place(
&aead::OpeningKey::new(ALGORITHM, key)
.map_err(|_| Error::BadKey)?,
&self.nonce,
EMPTY,
0,
&mut self.value[..]
).map(|x| x.len());
if let Ok(len) = len {
Ok(Unlocked {
len: len,
key: key,
inner: self,
})
} else {
self.value = backup;
Err(Error::Decrypt)
}
}
}
impl<'a> Unlocked<'a> {
pub fn rekey (
&mut self,
key: &'a [u8],
nonce: [u8; NONCE_LEN]
) {
self.key = key;
self.inner.nonce = nonce;
}
}
impl<'a> Drop for Unlocked<'a> {
fn drop(&mut self) {
aead::seal_in_place(
&aead::SealingKey::new(ALGORITHM, self.key).unwrap(),
&self.inner.nonce,
EMPTY,
&mut self.inner.value[..],
TAG_LEN
).unwrap();
}
}
impl<'a> Deref for Unlocked<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.inner.value[..self.len]
}
}
impl<'a> DerefMut for Unlocked<'a> {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.inner.value[..self.len]
}
}