raycrypt 0.3.1

Encrypt at the speed of light
Documentation
pub use crate::ciphers::chacha::ChaCha20;
pub use crate::errors::InvalidMac;
pub use crate::macs::poly1305::Poly1305;
use crate::utils::const_time_eq;

pub struct ChaCha20Poly1305 {
    chacha: ChaCha20,
}

impl ChaCha20Poly1305 {
    pub fn new(key: &[u8]) -> ChaCha20Poly1305 {
        ChaCha20Poly1305 {
            chacha: ChaCha20::new(key),
        }
    }

    fn mac(&self, nonce: &[u8], ad: &[u8], ct: &[u8]) -> [u8; 16] {
        let poly1305_key: [u8; 32] = self.chacha.keystream(nonce, 0)[..32].try_into().unwrap();
        let mut poly1305 = Poly1305::new(poly1305_key);

        poly1305.update(ad);
        poly1305.update(ct);

        poly1305.update_unpadded(&(ad.len() as u64).to_le_bytes());
        poly1305.update_unpadded(&(ct.len() as u64).to_le_bytes());

        poly1305.tag()
    }

    pub fn encrypt(&self, msg: &[u8], nonce: &[u8], ad: &[u8]) -> Vec<u8> {
        let ct = self.chacha.encrypt(msg, nonce);
        let tag = self.mac(&nonce, &ad, &ct);

        [ct, tag.to_vec()].concat()
    }

    pub fn decrypt(&self, ct: &[u8], nonce: &[u8], ad: &[u8]) -> Result<Vec<u8>, InvalidMac> {
        let (ciphertext, tag) = (&ct[0..ct.len() - 16], &ct[ct.len() - 16..]);
        let msg = self.chacha.encrypt(ciphertext, nonce);
        let mac = self.mac(&nonce, &ad, &ct);

        if !const_time_eq(tag, &mac) {
            return Err(InvalidMac);
        }

        Ok(msg)
    }
}