cl_noise_protocol/
cipherstate.rs

1use crate::traits::{Cipher, Unspecified};
2
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5
6/// A `CipherState` can encrypt and decrypt data.
7///
8/// Mostly like `CipherState` in the spec, but must be created with a key.
9///
10/// # Panics
11///
12/// Encryption and decryption methods will panic if nonce reaches maximum u64, i.e., 2 ^ 64 - 1.
13pub struct CipherState<C: Cipher> {
14    key: C::Key,
15    n: u64,
16}
17
18impl<C> Clone for CipherState<C>
19where
20    C: Cipher,
21    <C as Cipher>::Key: Clone,
22{
23    fn clone(&self) -> Self {
24        Self {
25            key: self.key.clone(),
26            n: self.n,
27        }
28    }
29}
30
31impl<C> CipherState<C>
32where
33    C: Cipher,
34{
35    /// Name of cipher, e.g. “ChaChaPoly”.
36    pub fn name() -> &'static str {
37        C::name()
38    }
39
40    /// Create a new `CipherState` with a `key` and a nonce `n`.
41    pub fn new(key: &[u8], n: u64) -> Self {
42        CipherState {
43            key: C::key_from_slice(key),
44            n,
45        }
46    }
47
48    /// Rekey. Set our key to `REKEY(old key)`.
49    pub fn rekey(&mut self) {
50        self.key = C::rekey(&self.key);
51    }
52
53    /// AEAD encryption.
54    pub fn encrypt_ad(&mut self, authtext: &[u8], plaintext: &[u8], out: &mut [u8]) {
55        C::encrypt(&self.key, self.n, authtext, plaintext, out);
56        #[cfg(feature = "alloc")]
57        if option_env!("NOISE_RUST_TEST_IN_PLACE").is_some() {
58            let mut inout = plaintext.to_vec();
59            inout.extend_from_slice(&[0; 16]);
60            let l = C::encrypt_in_place(&self.key, self.n, authtext, &mut inout, plaintext.len());
61            assert_eq!(inout, out);
62            assert_eq!(l, out.len());
63        }
64        // This will fail when n == 2 ^ 64 - 1, complying to the spec.
65        self.n = self.n.checked_add(1).unwrap();
66    }
67
68    /// AEAD encryption in place.
69    pub fn encrypt_ad_in_place(
70        &mut self,
71        authtext: &[u8],
72        in_out: &mut [u8],
73        plaintext_len: usize,
74    ) -> usize {
75        let size = C::encrypt_in_place(&self.key, self.n, authtext, in_out, plaintext_len);
76        // This will fail when n == 2 ^ 64 - 1, complying to the spec.
77        self.n = self.n.checked_add(1).unwrap();
78        size
79    }
80
81    /// AEAD decryption.
82    pub fn decrypt_ad(
83        &mut self,
84        authtext: &[u8],
85        ciphertext: &[u8],
86        out: &mut [u8],
87    ) -> Result<(), Unspecified> {
88        let r = C::decrypt(&self.key, self.n, authtext, ciphertext, out);
89        #[cfg(feature = "alloc")]
90        if option_env!("NOISE_RUST_TEST_IN_PLACE").is_some() {
91            let mut inout = ciphertext.to_vec();
92            let r2 = C::decrypt_in_place(&self.key, self.n, authtext, &mut inout, ciphertext.len());
93            assert_eq!(r.map(|_| out.len()), r2);
94            if r.is_ok() {
95                assert_eq!(&inout[..out.len()], out);
96            }
97        }
98        r?;
99        self.n = self.n.checked_add(1).unwrap();
100        Ok(())
101    }
102
103    /// AEAD decryption in place.
104    pub fn decrypt_ad_in_place(
105        &mut self,
106        authtext: &[u8],
107        in_out: &mut [u8],
108        ciphertext_len: usize,
109    ) -> Result<usize, Unspecified> {
110        let size = C::decrypt_in_place(&self.key, self.n, authtext, in_out, ciphertext_len)?;
111        self.n = self.n.checked_add(1).unwrap();
112        Ok(size)
113    }
114
115    /// Encryption.
116    pub fn encrypt(&mut self, plaintext: &[u8], out: &mut [u8]) {
117        self.encrypt_ad(&[0u8; 0], plaintext, out)
118    }
119
120    /// Encryption in place.
121    pub fn encrypt_in_place(&mut self, in_out: &mut [u8], plaintext_len: usize) -> usize {
122        self.encrypt_ad_in_place(&[0u8; 0], in_out, plaintext_len)
123    }
124
125    /// Encryption, returns ciphertext as `Vec<u8>`.
126    #[cfg(feature = "alloc")]
127    pub fn encrypt_vec(&mut self, plaintext: &[u8]) -> Vec<u8> {
128        let mut out = vec![0u8; plaintext.len() + 16];
129        self.encrypt(plaintext, &mut out);
130        out
131    }
132
133    /// Decryption.
134    pub fn decrypt(&mut self, ciphertext: &[u8], out: &mut [u8]) -> Result<(), Unspecified> {
135        self.decrypt_ad(&[0u8; 0], ciphertext, out)
136    }
137
138    /// Decryption in place.
139    pub fn decrypt_in_place(
140        &mut self,
141        in_out: &mut [u8],
142        ciphertext_len: usize,
143    ) -> Result<usize, Unspecified> {
144        self.decrypt_ad_in_place(&[0u8; 0], in_out, ciphertext_len)
145    }
146
147    /// Decryption, returns plaintext as `Vec<u8>`.
148    #[cfg(feature = "alloc")]
149    pub fn decrypt_vec(&mut self, ciphertext: &[u8]) -> Result<Vec<u8>, Unspecified> {
150        if ciphertext.len() < 16 {
151            return Err(Unspecified);
152        }
153        let mut out = vec![0u8; ciphertext.len() - 16];
154        self.decrypt(ciphertext, &mut out)?;
155        Ok(out)
156    }
157
158    /// Get the next value of `n`. Could be used to decide on whether to re-key, etc.
159    pub fn get_next_n(&self) -> u64 {
160        self.n
161    }
162
163    /// Get underlying cipher and nonce.
164    ///
165    /// This is useful for e.g. WireGuard. Because packets may be lost or arrive out of order,
166    /// they would likely want to deal with nonces themselves.
167    pub fn extract(self) -> (C::Key, u64) {
168        (self.key, self.n)
169    }
170}