lich 0.1.0

Minimal password management.
Documentation
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],
    //TODO: Switch to DST when they become less sucky.
    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> {
        //TODO: Avoid backup.
        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]
    }
}