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