Skip to main content

dcrypt_algorithms/aead/
mod.rs

1//! Authenticated Encryption with Associated Data (AEAD) with operation pattern
2//!
3//! This module provides implementations of authenticated encryption algorithms
4//! with an ergonomic operation pattern for operations.
5//!
6//! ## Example usage
7//!
8//! ```
9//! use dcrypt_algorithms::aead::{ChaCha20Poly1305Cipher, AeadCipher, AeadEncryptOperation, AeadDecryptOperation};
10//! use dcrypt_internal::random::ChaCha20Rng;
11//!
12//! // Generate key and nonce
13//! let mut rng = ChaCha20Rng::from_seed([0x42; 32]);
14//! let key = ChaCha20Poly1305Cipher::generate_key(&mut rng).unwrap();
15//! let nonce = ChaCha20Poly1305Cipher::generate_nonce(&mut rng).unwrap();
16//!
17//! // Create cipher instance
18//! let cipher = ChaCha20Poly1305Cipher::new(&key).unwrap();
19//!
20//! // Encrypt with operation pattern
21//! let ciphertext = cipher.encrypt()
22//!     .with_nonce(&nonce)
23//!     .with_aad(b"additional data")
24//!     .encrypt(b"secret message").unwrap();
25//!
26//! // Decrypt with operation pattern
27//! let plaintext = cipher.decrypt()
28//!     .with_nonce(&nonce)
29//!     .with_aad(b"additional data")
30//!     .decrypt(&ciphertext).unwrap();
31//!
32//! assert_eq!(plaintext, b"secret message");
33//! ```
34
35#[cfg(feature = "alloc")]
36extern crate alloc;
37
38// Core modules
39#[cfg(feature = "alloc")]
40pub mod gcm;
41
42#[cfg(feature = "alloc")]
43pub mod chacha20poly1305;
44
45#[cfg(feature = "alloc")]
46pub mod xchacha20poly1305;
47
48// Re-export for convenience when alloc is available
49#[cfg(feature = "alloc")]
50pub use self::gcm::Gcm;
51
52#[cfg(feature = "alloc")]
53pub use self::chacha20poly1305::ChaCha20Poly1305;
54
55#[cfg(feature = "alloc")]
56pub use self::xchacha20poly1305::XChaCha20Poly1305;
57
58use crate::error::{Error, Result};
59use crate::types::{Nonce, SecretBytes};
60#[cfg(feature = "alloc")]
61use alloc::vec::Vec;
62use dcrypt_internal::random::{try_fill_bytes_zeroing_on_error, CryptoRng, RngCore};
63use dcrypt_internal::zeroing::{Zeroize, Zeroizing};
64
65/// Marker trait for AEAD algorithms
66pub trait AeadAlgorithm {
67    /// Key size in bytes
68    const KEY_SIZE: usize;
69
70    /// Tag size in bytes
71    const TAG_SIZE: usize;
72
73    /// Algorithm name
74    fn name() -> &'static str;
75}
76
77/// Type-level constants for ChaCha20-Poly1305
78pub enum ChaCha20Poly1305Algorithm {}
79
80impl AeadAlgorithm for ChaCha20Poly1305Algorithm {
81    const KEY_SIZE: usize = 32;
82    const TAG_SIZE: usize = 16;
83
84    fn name() -> &'static str {
85        "ChaCha20-Poly1305"
86    }
87}
88
89/// Base trait for operations
90pub trait Operation<T> {
91    /// Execute the operation and produce a result
92    fn execute(self) -> Result<T>;
93
94    /// Reset the operation to its initial state
95    fn reset(&mut self);
96}
97
98/// Trait for encryption operations with AEAD algorithms
99pub trait AeadEncryptOperation<'a, A: AeadAlgorithm>: Operation<Vec<u8>> {
100    /// Set the nonce for encryption
101    fn with_nonce(self, nonce: &'a Nonce<12>) -> Self;
102
103    /// Set associated data for authenticated encryption
104    fn with_aad(self, aad: &'a [u8]) -> Self;
105
106    /// Set plaintext and execute encryption
107    fn encrypt(self, plaintext: &'a [u8]) -> Result<Vec<u8>>;
108}
109
110/// Trait for decryption operations with AEAD algorithms
111pub trait AeadDecryptOperation<'a, A: AeadAlgorithm>: Operation<Vec<u8>> {
112    /// Set the nonce for decryption
113    fn with_nonce(self, nonce: &'a Nonce<12>) -> Self;
114
115    /// Set associated data for authenticated decryption
116    fn with_aad(self, aad: &'a [u8]) -> Self;
117
118    /// Set ciphertext and execute decryption
119    fn decrypt(self, ciphertext: &'a [u8]) -> Result<Vec<u8>>;
120}
121
122/// Trait for AEAD ciphers with improved type safety
123pub trait AeadCipher {
124    /// The algorithm this cipher implements
125    type Algorithm: AeadAlgorithm;
126
127    /// Key type with appropriate size guarantee
128    type Key: AsRef<[u8]> + AsMut<[u8]> + Clone + Zeroize;
129
130    /// Creates a new AEAD cipher instance
131    fn new(key: &Self::Key) -> Result<Self>
132    where
133        Self: Sized;
134
135    /// Begin encryption operation with operation pattern
136    fn encrypt(&self) -> impl AeadEncryptOperation<'_, Self::Algorithm>;
137
138    /// Begin decryption operation with operation pattern
139    fn decrypt(&self) -> impl AeadDecryptOperation<'_, Self::Algorithm>;
140
141    /// Generate a random key
142    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key>;
143
144    /// Generate a random nonce for ChaCha20Poly1305
145    fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Nonce<12>>;
146
147    /// Returns the cipher name
148    fn name() -> &'static str {
149        Self::Algorithm::name()
150    }
151
152    /// Returns the key size in bytes
153    fn key_size() -> usize {
154        Self::Algorithm::KEY_SIZE
155    }
156
157    /// Returns the tag size in bytes
158    fn tag_size() -> usize {
159        Self::Algorithm::TAG_SIZE
160    }
161}
162
163/// Implementation of ChaCha20-Poly1305 with enhanced type safety
164#[cfg(feature = "alloc")]
165pub struct ChaCha20Poly1305Cipher {
166    inner: chacha20poly1305::ChaCha20Poly1305,
167}
168
169#[cfg(feature = "alloc")]
170impl AeadCipher for ChaCha20Poly1305Cipher {
171    type Algorithm = ChaCha20Poly1305Algorithm;
172    type Key = SecretBytes<32>;
173
174    fn new(key: &Self::Key) -> Result<Self> {
175        let mut key_array = Zeroizing::new([0u8; 32]);
176        key_array.copy_from_slice(key.as_ref());
177
178        let inner = chacha20poly1305::ChaCha20Poly1305::new(&*key_array);
179
180        Ok(Self { inner })
181    }
182
183    fn encrypt(&self) -> impl AeadEncryptOperation<'_, Self::Algorithm> {
184        ChaCha20Poly1305EncryptOperation {
185            cipher: self,
186            nonce: None,
187            aad: None,
188        }
189    }
190
191    fn decrypt(&self) -> impl AeadDecryptOperation<'_, Self::Algorithm> {
192        ChaCha20Poly1305DecryptOperation {
193            cipher: self,
194            nonce: None,
195            aad: None,
196        }
197    }
198
199    fn generate_key<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self::Key> {
200        let mut key = Zeroizing::new([0u8; 32]);
201        try_fill_bytes_zeroing_on_error(rng, &mut key[..])?;
202        Ok(SecretBytes::new(*key))
203    }
204
205    fn generate_nonce<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Nonce<12>> {
206        let mut nonce = [0u8; 12];
207        try_fill_bytes_zeroing_on_error(rng, &mut nonce)?;
208        Ok(Nonce::<12>::new(nonce))
209    }
210}
211
212/// ChaCha20-Poly1305 encryption operation
213#[cfg(feature = "alloc")]
214pub struct ChaCha20Poly1305EncryptOperation<'a> {
215    cipher: &'a ChaCha20Poly1305Cipher,
216    nonce: Option<&'a Nonce<12>>,
217    aad: Option<&'a [u8]>,
218}
219
220#[cfg(feature = "alloc")]
221impl Operation<Vec<u8>> for ChaCha20Poly1305EncryptOperation<'_> {
222    fn execute(self) -> Result<Vec<u8>> {
223        Err(Error::param("operation", "use encrypt method instead"))
224    }
225
226    fn reset(&mut self) {
227        self.nonce = None;
228        self.aad = None;
229    }
230}
231
232#[cfg(feature = "alloc")]
233impl<'a> AeadEncryptOperation<'a, ChaCha20Poly1305Algorithm>
234    for ChaCha20Poly1305EncryptOperation<'a>
235{
236    fn with_nonce(mut self, nonce: &'a Nonce<12>) -> Self {
237        self.nonce = Some(nonce);
238        self
239    }
240
241    fn with_aad(mut self, aad: &'a [u8]) -> Self {
242        self.aad = Some(aad);
243        self
244    }
245
246    fn encrypt(self, plaintext: &'a [u8]) -> Result<Vec<u8>> {
247        let nonce = self.nonce.ok_or_else(|| {
248            Error::param("nonce", "nonce is required for ChaCha20Poly1305 encryption")
249        })?;
250
251        self.cipher.inner.encrypt(nonce, plaintext, self.aad)
252    }
253}
254
255/// ChaCha20-Poly1305 decryption operation
256#[cfg(feature = "alloc")]
257pub struct ChaCha20Poly1305DecryptOperation<'a> {
258    cipher: &'a ChaCha20Poly1305Cipher,
259    nonce: Option<&'a Nonce<12>>,
260    aad: Option<&'a [u8]>,
261}
262
263#[cfg(feature = "alloc")]
264impl Operation<Vec<u8>> for ChaCha20Poly1305DecryptOperation<'_> {
265    fn execute(self) -> Result<Vec<u8>> {
266        Err(Error::param("operation", "use decrypt method instead"))
267    }
268
269    fn reset(&mut self) {
270        self.nonce = None;
271        self.aad = None;
272    }
273}
274
275#[cfg(feature = "alloc")]
276impl<'a> AeadDecryptOperation<'a, ChaCha20Poly1305Algorithm>
277    for ChaCha20Poly1305DecryptOperation<'a>
278{
279    fn with_nonce(mut self, nonce: &'a Nonce<12>) -> Self {
280        self.nonce = Some(nonce);
281        self
282    }
283
284    fn with_aad(mut self, aad: &'a [u8]) -> Self {
285        self.aad = Some(aad);
286        self
287    }
288
289    fn decrypt(self, ciphertext: &'a [u8]) -> Result<Vec<u8>> {
290        let nonce = self.nonce.ok_or_else(|| {
291            Error::param("nonce", "nonce is required for ChaCha20Poly1305 decryption")
292        })?;
293
294        self.cipher.inner.decrypt(nonce, ciphertext, self.aad)
295    }
296}