melodies_core/
cipher_state.rs

1use crate::crypto::{Cipher, CIPHER_KEY_LEN, TAG_SIZE};
2use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
3
4#[derive(Zeroize, ZeroizeOnDrop)]
5pub struct CipherState<Nonce = u64> {
6    key: [u8; CIPHER_KEY_LEN],
7    #[zeroize(skip)]
8    pub(crate) cipher: &'static dyn Cipher,
9    /// Note that a nonce of u64::MAX will cause an error on every call to encrypt
10    #[zeroize(skip)]
11    pub nonce: Nonce,
12}
13
14impl<T> CipherState<T> {
15    /// Encrypt, with a provided nonce (must prevent reuse).
16    /// This occurs in place. The last TAG_SIZE bytes of buf will be replaced with the AEAD tag.
17    pub fn encrypt_with_nonce(&self, n: u64, ad: &[u8], buf: &mut [u8]) {
18        assert_ne!(n, u64::MAX);
19        let (buf, tag) = buf.split_at_mut(buf.len() - TAG_SIZE);
20        let tag = tag.try_into().unwrap();
21        self.cipher.encrypt(&self.key, n, ad, buf, tag);
22    }
23    pub fn decrypt_with_nonce<'a>(&self, n: u64, ad: &[u8], buf: &'a mut [u8]) -> Option<&'a [u8]> {
24        assert_ne!(n, u64::MAX);
25        self.cipher.decrypt(&self.key, n, ad, buf)
26    }
27    pub fn rekey(&mut self) {
28        let tmp = Zeroizing::new(self.key);
29        self.cipher.rekey(&tmp, &mut self.key);
30    }
31}
32
33
34impl CipherState<u64> {
35    #[inline(always)]
36    pub(crate) const fn new(cipher: &'static dyn Cipher) -> Self {
37        Self {
38            key: [0; CIPHER_KEY_LEN],
39            cipher,
40            nonce: u64::MAX,
41        }
42    }
43    pub(crate) fn initialize_key(&mut self, key: &[u8; CIPHER_KEY_LEN]) {
44        self.key = *key;
45        self.nonce = 0;
46    }
47    #[inline(always)]
48    pub fn into_stateless(self) -> CipherState<()> {
49        CipherState {
50            key: self.key,
51            cipher: self.cipher,
52            nonce: (),
53        }
54    }
55    /// Returns the size of the encrypted message. Buf should have space for a tag
56    pub fn encrypt(&mut self, ad: &[u8], buf: &mut [u8]) -> usize {
57        self.encrypt_with_nonce(self.nonce, ad, buf);
58        self.nonce += 1;
59        buf.len()
60    }
61    /// Returns the decrypted payload
62    pub fn decrypt<'a>(&mut self, ad: &[u8], buf: &'a mut [u8]) -> Option<&'a [u8]> {
63        let res = self.decrypt_with_nonce(self.nonce, ad, buf);
64        if res.is_some() {
65            self.nonce += 1;
66        }
67        res
68    }
69}
70