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}