dcrypt_symmetric/aead/gcm/
mod.rs

1// File: crates/symmetric/src/aead/gcm/mod.rs
2//! AES-GCM authenticated encryption
3//!
4//! This module provides an implementation of the AES-GCM authenticated encryption
5//! algorithm as defined in NIST SP 800-38D.
6//!
7//! # Examples
8//!
9//! ```
10//! use dcrypt_symmetric::{Aes128Gcm, GcmNonce}; // Corrected
11//! use dcrypt_symmetric::Aes128Key;            // Corrected
12//! use dcrypt_symmetric::{SymmetricCipher, Aead}; // Corrected
13//! use dcrypt_symmetric::Result;                 // Corrected
14//!
15//! // Example function that handles errors properly
16//! fn example() -> Result<()> {
17//!     // Generate a random key
18//!     let key = Aes128Key::generate();
19//!
20//!     // Create a cipher instance
21//!     let cipher = Aes128Gcm::new(&key)?;
22//!
23//!     // Encrypt some data
24//!     let plaintext = b"Secret message";
25//!     let nonce = Aes128Gcm::generate_nonce();
26//!     let ciphertext = cipher.encrypt(&nonce, plaintext, None)?;
27//!
28//!     // Decrypt the data
29//!     let decrypted = cipher.decrypt(&nonce, &ciphertext, None)?;
30//!     assert_eq!(decrypted, plaintext);
31//!     Ok(())
32//! }
33//! ```
34//!
35//! ## Streaming Encryption
36//!
37/// For streaming encryption of large data, see the `streaming::gcm` module.
38/// ```
39/// use std::io::Cursor;
40/// use symmetric::Aes128Key; // Corrected
41/// use symmetric::streaming::{StreamingEncrypt, StreamingDecrypt}; // Corrected
42/// use symmetric::streaming::gcm::{Aes128GcmEncryptStream, Aes128GcmDecryptStream}; // Corrected
43/// use symmetric::Result; // Corrected
44///
45/// // Example function with proper error handling
46/// fn example() -> Result<()> {
47///     // Generate a random key
48///     let key = Aes128Key::generate();
49///
50///     // Create an in-memory buffer for this example
51///     let mut encrypted = Vec::new();
52///
53///     // Create a streaming encryption context with proper error handling
54///     let mut stream = Aes128GcmEncryptStream::new(&mut encrypted, &key, None)?;
55///
56///     // Encrypt data in chunks
57///     stream.write(b"First chunk of data")?;
58///     stream.write(b"Second chunk of data")?;
59///
60///     // Finalize the stream
61///     let writer = stream.finalize()?;
62///
63///     // Now decrypt the data
64///     let reader = Cursor::new(encrypted); // encrypted is already a Vec<u8>
65///     let mut stream = Aes128GcmDecryptStream::new(reader, &key, None)?;
66///
67///     // Read the decrypted data
68///     let mut buffer = [0u8; 1024];
69///     let bytes_read = stream.read(&mut buffer)?;
70///     
71///     // The decrypted data is now in buffer[..bytes_read]
72///     Ok(())
73/// }
74/// ```
75
76#[cfg(not(feature = "std"))]
77use alloc::vec::Vec;
78
79use crate::error::{from_primitive_error, validate, Result};
80use dcrypt_algorithms::aead::Gcm;
81use dcrypt_algorithms::block::aes::{Aes128, Aes256};
82use dcrypt_algorithms::block::BlockCipher;
83use dcrypt_api::types::SecretBytes;
84// Import the new Nonce type
85use dcrypt_algorithms::error::Error as PrimitiveError;
86use dcrypt_algorithms::types::Nonce;
87
88use crate::aes::keys::{Aes128Key, Aes256Key};
89use crate::cipher::{Aead, SymmetricCipher as OurSymmetricCipher};
90
91pub mod aes128;
92pub mod aes256;
93pub mod types;
94
95// Re-export GCM-specific types
96pub use types::{AesCiphertextPackage, GcmNonce};
97
98/// AES-128-GCM implementation
99pub struct Aes128Gcm {
100    pub(crate) key: Aes128Key,
101}
102
103/// AES-256-GCM implementation
104pub struct Aes256Gcm {
105    pub(crate) key: Aes256Key,
106}
107
108// Bring in the per-key helper functions
109pub use aes128::{aes128_decrypt, aes128_decrypt_package, aes128_encrypt, aes128_encrypt_package};
110pub use aes256::{aes256_decrypt, aes256_decrypt_package, aes256_encrypt, aes256_encrypt_package};
111
112impl OurSymmetricCipher for Aes128Gcm {
113    type Key = Aes128Key;
114
115    fn new(key: &Self::Key) -> Result<Self> {
116        Ok(Self { key: key.clone() })
117    }
118
119    fn name() -> &'static str {
120        "AES-128-GCM"
121    }
122}
123
124impl Aead for Aes128Gcm {
125    type Nonce = GcmNonce;
126
127    fn encrypt(
128        &self,
129        nonce: &Self::Nonce,
130        plaintext: &[u8],
131        aad: Option<&[u8]>,
132    ) -> Result<Vec<u8>> {
133        // Validate nonce length
134        validate::length("GCM nonce", nonce.as_bytes().len(), 12)?;
135
136        // Convert key bytes to SecretBytes<16>
137        let key_bytes = SecretBytes::<16>::from_slice(self.key.as_bytes())?;
138
139        let aes = Aes128::new(&key_bytes);
140
141        // Convert the GcmNonce to a Nonce<12>
142        let primitives_nonce = Nonce::<12>::from_slice(nonce.as_bytes())?;
143
144        // Create Gcm instance with proper error handling
145        let gcm = Gcm::new(aes, &primitives_nonce)?;
146
147        // Use internal_encrypt method directly
148        gcm.internal_encrypt(plaintext, aad)
149            .map_err(from_primitive_error)
150    }
151
152    fn decrypt(
153        &self,
154        nonce: &Self::Nonce,
155        ciphertext: &[u8],
156        aad: Option<&[u8]>,
157    ) -> Result<Vec<u8>> {
158        // Validate nonce length
159        validate::length("GCM nonce", nonce.as_bytes().len(), 12)?;
160
161        // Convert key bytes to SecretBytes<16>
162        let key_bytes = SecretBytes::<16>::from_slice(self.key.as_bytes())?;
163
164        let aes = Aes128::new(&key_bytes);
165
166        // Convert the GcmNonce to a Nonce<12>
167        let primitives_nonce = Nonce::<12>::from_slice(nonce.as_bytes())?;
168
169        // Create Gcm instance with proper error handling
170        let gcm = Gcm::new(aes, &primitives_nonce)?;
171
172        // Use internal_decrypt method directly with better error context
173        gcm.internal_decrypt(ciphertext, aad).map_err(|e| match e {
174            PrimitiveError::Authentication { .. } => {
175                dcrypt_api::error::Error::AuthenticationFailed {
176                    context: "AES-128-GCM",
177                    #[cfg(feature = "std")]
178                    message: "authentication tag verification failed".to_string(),
179                }
180            }
181            _ => from_primitive_error(e),
182        })
183    }
184
185    fn generate_nonce() -> Self::Nonce {
186        GcmNonce::generate()
187    }
188}
189
190impl OurSymmetricCipher for Aes256Gcm {
191    type Key = Aes256Key;
192
193    fn new(key: &Self::Key) -> Result<Self> {
194        Ok(Self { key: key.clone() })
195    }
196
197    fn name() -> &'static str {
198        "AES-256-GCM"
199    }
200}
201
202impl Aead for Aes256Gcm {
203    type Nonce = GcmNonce;
204
205    fn encrypt(
206        &self,
207        nonce: &Self::Nonce,
208        plaintext: &[u8],
209        aad: Option<&[u8]>,
210    ) -> Result<Vec<u8>> {
211        // Validate nonce length
212        validate::length("GCM nonce", nonce.as_bytes().len(), 12)?;
213
214        // Convert key bytes to SecretBytes<32>
215        let key_bytes = SecretBytes::<32>::from_slice(self.key.as_bytes())?;
216
217        let aes = Aes256::new(&key_bytes);
218
219        // Convert the GcmNonce to a Nonce<12>
220        let primitives_nonce = Nonce::<12>::from_slice(nonce.as_bytes())?;
221
222        // Create Gcm instance with proper error handling
223        let gcm = Gcm::new(aes, &primitives_nonce)?;
224
225        // Use internal_encrypt method directly
226        gcm.internal_encrypt(plaintext, aad)
227            .map_err(from_primitive_error)
228    }
229
230    fn decrypt(
231        &self,
232        nonce: &Self::Nonce,
233        ciphertext: &[u8],
234        aad: Option<&[u8]>,
235    ) -> Result<Vec<u8>> {
236        // Validate nonce length
237        validate::length("GCM nonce", nonce.as_bytes().len(), 12)?;
238
239        // Convert key bytes to SecretBytes<32>
240        let key_bytes = SecretBytes::<32>::from_slice(self.key.as_bytes())?;
241
242        let aes = Aes256::new(&key_bytes);
243
244        // Convert the GcmNonce to a Nonce<12>
245        let primitives_nonce = Nonce::<12>::from_slice(nonce.as_bytes())?;
246
247        // Create Gcm instance with proper error handling
248        let gcm = Gcm::new(aes, &primitives_nonce)?;
249
250        // Use internal_decrypt method directly with better error context
251        gcm.internal_decrypt(ciphertext, aad).map_err(|e| match e {
252            PrimitiveError::Authentication { .. } => {
253                dcrypt_api::error::Error::AuthenticationFailed {
254                    context: "AES-256-GCM",
255                    #[cfg(feature = "std")]
256                    message: "authentication tag verification failed".to_string(),
257                }
258            }
259            _ => from_primitive_error(e),
260        })
261    }
262
263    fn generate_nonce() -> Self::Nonce {
264        GcmNonce::generate()
265    }
266}