libcrux_aesgcm/lib.rs
1//! # AES-GCM
2//!
3//! This crate implements AES-GCM-128 and AES-GCM-256. The crate provides
4//! optimized implementations for ARM and x86_64 platforms with support
5//! for AES hardware acceleration, as well as a bit-sliced portable
6//! implementation.
7//!
8//! For general use, we provide a platform-multiplexing API via the
9//! [`AesGcm128Key`] and [`AesGcm256Key`] structs, which selects the most
10//! performant implementation at runtime.
11//!
12//! Usage example:
13//!
14//! ```rust
15//! // Multiplexed owned API
16//! use libcrux_aesgcm::AeadConsts as _;
17//! use libcrux_aesgcm::{AesGcm128, AesGcm128Key, AesGcm128Nonce, AesGcm128Tag, NONCE_LEN, TAG_LEN};
18//!
19//! let k: AesGcm128Key = [0; AesGcm128::KEY_LEN].into();
20//! let nonce: AesGcm128Nonce = [0; NONCE_LEN].into();
21//! let mut tag: AesGcm128Tag = [0; TAG_LEN].into();
22//!
23//! let pt = b"the quick brown fox jumps over the lazy dog";
24//! let mut ct = [0; 43];
25//! let mut pt_out = [0; 43];
26//!
27//! k.encrypt(&mut ct, &mut tag, &nonce, b"", pt).unwrap();
28//! k.decrypt(&mut pt_out, &nonce, b"", &ct, &tag).unwrap();
29//! assert_eq!(pt, &pt_out);
30//! ```
31//!
32//! We also provide access to [lower-level AEAD
33//! APIs](libcrux_traits::aead) for the platform-multiplexing
34//! implementation with the [`AesGcm128`] and [`AesGcm256`] structs.
35//!
36//! Users who want to use a platform-specific implementation directly can
37//! access them in the submodules `aes_gcm_128::{portable, x64, neon}`.
38//!
39//!
40
41#![no_std]
42#![deny(unsafe_code)]
43#[cfg(feature = "std")]
44extern crate std;
45
46mod aes;
47mod ctr;
48mod gf128;
49mod platform;
50
51mod traits_api;
52
53mod aes_gcm;
54
55/// Implementations of AES-GCM 128
56///
57/// This module contains implementations of AES-GCM 128:
58/// - [`AesGcm128`]: A platform-multiplexing implementation, which will at
59/// runtime select the most performant implementation among the following for the given
60/// architecture at runtime.
61#[cfg_attr(
62 feature = "simd256",
63 doc = "- [`aes_gcm_128::x64::X64AesGcm128`]: An implementation optimized for x86_64 AES-NI instruction sets."
64)]
65#[cfg_attr(
66 feature = "simd128",
67 doc = "- [`aes_gcm_128::neon::NeonAesGcm128`]: An implementation optimized for ARM NEON instruction sets."
68)]
69/// - [`aes_gcm_128::portable::PortableAesGcm128`]: A portable, bit-sliced implementation.
70///
71/// See [`EncryptError`],
72/// [`DecryptError`](libcrux_traits::aead::arrayref::DecryptError) and
73/// [`KeyGenError`](libcrux_traits::aead::arrayref::DecryptError) for
74/// errors.
75///
76/// The [`libcrux_traits`](libcrux_traits) crate provides two typed APIs for AEADs:
77///
78/// ## Owned key-centric API
79/// This API operates on owned arrays for keys, nonces and tags:
80/// ```rust
81/// // Using the multiplexed implementation.
82/// use libcrux_aesgcm::AeadConsts as _;
83/// use libcrux_aesgcm::{NONCE_LEN, TAG_LEN, aes_gcm_128::{AesGcm128, Key, Tag, Nonce}};
84///
85/// let k: Key = [0; AesGcm128::KEY_LEN].into();
86/// let nonce: Nonce = [0; NONCE_LEN].into();
87/// let mut tag: Tag = [0; TAG_LEN].into();
88///
89/// let pt = b"the quick brown fox jumps over the lazy dog";
90/// let mut ct = [0; 43];
91/// let mut pt_out = [0; 43];
92///
93/// k.encrypt(&mut ct, &mut tag, &nonce, b"", pt).unwrap();
94/// k.decrypt(&mut pt_out, &nonce, b"", &ct, &tag).unwrap();
95/// assert_eq!(pt, &pt_out);
96/// ```
97///
98/// ## Refs key-centric API
99/// This API operates on array references for keys, nonces and tags:
100/// ```rust
101/// // Using the multiplexed API
102/// use libcrux_aesgcm::{AeadConsts as _, Aead as _};
103/// use libcrux_aesgcm::{NONCE_LEN, TAG_LEN, aes_gcm_128::{AesGcm128}};
104///
105/// let algo = AesGcm128;
106///
107/// let mut tag_bytes = [0; TAG_LEN];
108/// let tag = algo.new_tag_mut(&mut tag_bytes).unwrap();
109///
110/// let key = algo.new_key(&[0; AesGcm128::KEY_LEN]).unwrap();
111/// let nonce = algo.new_nonce(&[0; NONCE_LEN]).unwrap();
112///
113/// let pt = b"the quick brown fox jumps over the lazy dog";
114/// let mut ct = [0; 43];
115/// let mut pt_out = [0; 43];
116///
117/// key.encrypt(&mut ct, tag, nonce, b"", pt).unwrap();
118/// let tag = algo.new_tag(&tag_bytes).unwrap();
119/// key.decrypt(&mut pt_out, nonce, b"", &ct, tag).unwrap();
120/// assert_eq!(pt, &pt_out);
121/// ```
122pub mod aes_gcm_128;
123
124/// Implementations of AES-GCM 256
125///
126/// This module contains implementations of AES-GCM 256:
127/// - [`AesGcm256`]: A platform-multiplexing implementation, which will at
128/// runtime select the most performant implementation among the following for the given
129/// architecture at runtime.
130#[cfg_attr(
131 feature = "simd256",
132 doc = "- [`aes_gcm_256::x64::X64AesGcm256`]: An implementation optimized for x86_64 AES-NI instruction sets."
133)]
134#[cfg_attr(
135 feature = "simd128",
136 doc = "- [`aes_gcm_256::neon::NeonAesGcm256`]: An implementation optimized for ARM NEON instruction sets."
137)]
138/// - [`aes_gcm_256::portable::PortableAesGcm256`]: A portable, bit-sliced implementation.
139///
140/// See [`EncryptError`],
141/// [`DecryptError`](libcrux_traits::aead::arrayref::DecryptError) and
142/// [`KeyGenError`](libcrux_traits::aead::arrayref::DecryptError) for
143/// errors.
144///
145/// The [`libcrux_traits`](libcrux_traits) crate provides two typed APIs for AEADs:
146///
147/// ## Owned key-centric API
148/// This API operates on owned arrays for keys, nonces and tags:
149/// ```rust
150/// // Using the multiplexed implementation.
151/// use libcrux_aesgcm::AeadConsts as _;
152/// use libcrux_aesgcm::{NONCE_LEN, TAG_LEN, aes_gcm_256::{AesGcm256, Key, Tag, Nonce}};
153///
154/// let k: Key = [0; AesGcm256::KEY_LEN].into();
155/// let nonce: Nonce = [0; NONCE_LEN].into();
156/// let mut tag: Tag = [0; TAG_LEN].into();
157///
158/// let pt = b"the quick brown fox jumps over the lazy dog";
159/// let mut ct = [0; 43];
160/// let mut pt_out = [0; 43];
161///
162/// k.encrypt(&mut ct, &mut tag, &nonce, b"", pt).unwrap();
163/// k.decrypt(&mut pt_out, &nonce, b"", &ct, &tag).unwrap();
164/// assert_eq!(pt, &pt_out);
165/// ```
166///
167/// ## Refs key-centric API
168/// This API operates on array references for keys, nonces and tags:
169/// ```rust
170/// // Using the multiplexed API
171/// use libcrux_aesgcm::{AeadConsts as _, Aead as _};
172/// use libcrux_aesgcm::{NONCE_LEN, TAG_LEN, aes_gcm_256::{AesGcm256}};
173///
174/// let algo = AesGcm256;
175///
176/// let mut tag_bytes = [0; TAG_LEN];
177/// let tag = algo.new_tag_mut(&mut tag_bytes).unwrap();
178///
179/// let key = algo.new_key(&[0; AesGcm256::KEY_LEN]).unwrap();
180/// let nonce = algo.new_nonce(&[0; NONCE_LEN]).unwrap();
181///
182/// let pt = b"the quick brown fox jumps over the lazy dog";
183/// let mut ct = [0; 43];
184/// let mut pt_out = [0; 43];
185///
186/// key.encrypt(&mut ct, tag, nonce, b"", pt).unwrap();
187/// let tag = algo.new_tag(&tag_bytes).unwrap();
188/// key.decrypt(&mut pt_out, nonce, b"", &ct, tag).unwrap();
189/// assert_eq!(pt, &pt_out);
190/// ```
191pub mod aes_gcm_256;
192
193/// Trait for an AES State.
194/// Implemented for 128 and 256.
195pub(crate) trait State {
196 fn init(key: &[u8]) -> Self;
197 fn set_nonce(&mut self, nonce: &[u8]);
198 fn encrypt(&mut self, aad: &[u8], plaintext: &[u8], ciphertext: &mut [u8], tag: &mut [u8]);
199 fn decrypt(
200 &mut self,
201 aad: &[u8],
202 ciphertext: &[u8],
203 tag: &[u8],
204 plaintext: &mut [u8],
205 ) -> Result<(), DecryptError>;
206}
207
208pub(crate) mod implementations {
209
210 #[cfg(doc)]
211 use super::{aes_gcm_128, aes_gcm_256};
212
213 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for platform-multiplexed AES-GCM 128.
214 ///
215 /// The implementation used is determined automatically at runtime.
216 /// - `x64`
217 /// - `neon`
218 /// - `portable`
219 ///
220 /// For more information on usage, see [`aes_gcm_128`].
221 #[derive(Clone, Copy, PartialEq, Eq)]
222 pub struct AesGcm128;
223
224 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for portable AES-GCM 128.
225 ///
226 /// For more information on usage, see [`aes_gcm_128`].
227 #[derive(Clone, Copy, PartialEq, Eq)]
228 pub struct PortableAesGcm128;
229
230 #[cfg(feature = "simd128")]
231 #[derive(Clone, Copy, PartialEq, Eq)]
232 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for ARM Neon optimized AES-GCM 128.
233 ///
234 /// Should only be used directly after performing runtime checks for the necessary CPU
235 /// features.
236 ///
237 /// For more information on usage, see [`aes_gcm_128`].
238 pub struct NeonAesGcm128;
239
240 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for x86_64 AES-NI optimized AES-GCM 128.
241 ///
242 /// Should only be used directly after performing runtime checks for the necessary CPU
243 /// features.
244 ///
245 /// For more information on usage, see [`aes_gcm_128`].
246 #[cfg(feature = "simd256")]
247 #[derive(Clone, Copy, PartialEq, Eq)]
248 pub struct X64AesGcm128;
249
250 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for platform-multiplexed AES-GCM 256.
251 ///
252 /// The implementation used is determined automatically at runtime.
253 /// - `x64`
254 /// - `neon`
255 /// - `portable`
256 ///
257 /// For more information on usage, see [`aes_gcm_256`].
258 #[derive(Clone, Copy, PartialEq, Eq)]
259 pub struct AesGcm256;
260
261 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for portable AES-GCM 256.
262 ///
263 /// For more information on usage, see [`aes_gcm_256`].
264 #[derive(Clone, Copy, PartialEq, Eq)]
265 pub struct PortableAesGcm256;
266
267 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for ARM Neon optimized AES-GCM 256.
268 ///
269 /// For more information on usage, see [`aes_gcm_256`].
270 #[cfg(feature = "simd128")]
271 #[derive(Clone, Copy, PartialEq, Eq)]
272 pub struct NeonAesGcm256;
273
274 /// Access to [lower-level AEAD APIs](libcrux_traits::aead) for x86_64 AES-NI optimized AES-GCM 256.
275 ///
276 /// For more information on usage, see [`aes_gcm_256`].
277 #[derive(Clone, Copy, PartialEq, Eq)]
278 #[cfg(feature = "simd256")]
279 pub struct X64AesGcm256;
280}
281// pub use implementations::*;
282
283/// Tag length.
284pub const TAG_LEN: usize = 16;
285
286/// Nonce length.
287pub const NONCE_LEN: usize = 12;
288
289#[doc(inline)]
290pub use aes_gcm_128::KEY_LEN as AESGCM128_KEY_LEN;
291#[doc(inline)]
292pub use aes_gcm_256::KEY_LEN as AESGCM256_KEY_LEN;
293
294pub use libcrux_traits::aead::arrayref::{DecryptError, EncryptError, KeyGenError};
295
296/// Generic AES-GCM encrypt.
297pub(crate) fn encrypt<S: State>(
298 key: &[u8],
299 nonce: &[u8],
300 aad: &[u8],
301 plaintext: &[u8],
302 ciphertext: &mut [u8],
303 tag: &mut [u8],
304) -> Result<(), EncryptError> {
305 debug_assert!(nonce.len() == NONCE_LEN);
306 debug_assert!(tag.len() == TAG_LEN);
307
308 // plaintext length check
309 if plaintext.len() / crate::aes::AES_BLOCK_LEN >= (u32::MAX - 1) as usize {
310 return Err(EncryptError::PlaintextTooLong);
311 }
312
313 // ensure ciphertext and plaintext have same length
314 if ciphertext.len() != plaintext.len() {
315 return Err(EncryptError::WrongCiphertextLength);
316 }
317
318 let mut st = S::init(key);
319 st.set_nonce(nonce);
320 st.encrypt(aad, plaintext, ciphertext, tag);
321
322 Ok(())
323}
324
325/// Generic AES-GCM decrypt.
326pub(crate) fn decrypt<S: State>(
327 key: &[u8],
328 nonce: &[u8],
329 aad: &[u8],
330 ciphertext: &[u8],
331 tag: &[u8],
332 plaintext: &mut [u8],
333) -> Result<(), DecryptError> {
334 debug_assert!(nonce.len() == NONCE_LEN);
335 debug_assert!(tag.len() == TAG_LEN);
336
337 // plaintext length check
338 if plaintext.len() / crate::aes::AES_BLOCK_LEN >= (u32::MAX - 1) as usize {
339 return Err(DecryptError::PlaintextTooLong);
340 }
341
342 // ensure ciphertext and plaintext have same length
343 if ciphertext.len() != plaintext.len() {
344 return Err(DecryptError::WrongPlaintextLength);
345 }
346
347 let mut st = S::init(key);
348 st.set_nonce(nonce);
349 st.decrypt(aad, ciphertext, tag, plaintext)
350}
351
352/// Macro to instantiate the different variants, both 128/256 and platforms.
353macro_rules! pub_crate_mod {
354 ($variant_comment:literal, $mod_name:ident, $state:ty) => {
355 #[doc = $variant_comment]
356 pub mod $mod_name {
357 use crate::$mod_name::KEY_LEN;
358 use crate::{platform, DecryptError, EncryptError};
359
360 type State = $state;
361
362 #[doc = $variant_comment]
363 /// encrypt.
364 pub fn encrypt(
365 key: &[u8],
366 nonce: &[u8],
367 aad: &[u8],
368 plaintext: &[u8],
369 ciphertext: &mut [u8],
370 tag: &mut [u8],
371 ) -> Result<(), EncryptError> {
372 debug_assert!(key.len() == KEY_LEN);
373 crate::encrypt::<State>(key, nonce, aad, plaintext, ciphertext, tag)
374 }
375
376 #[doc = $variant_comment]
377 /// decrypt.
378 pub fn decrypt(
379 key: &[u8],
380 nonce: &[u8],
381 aad: &[u8],
382 ciphertext: &[u8],
383 tag: &[u8],
384 plaintext: &mut [u8],
385 ) -> Result<(), DecryptError> {
386 debug_assert!(key.len() == KEY_LEN);
387 crate::decrypt::<State>(key, nonce, aad, ciphertext, tag, plaintext)
388 }
389 }
390 };
391}
392
393pub(crate) mod portable {
394 pub_crate_mod!(r"AES-GCM 128 ", aes_gcm_128, crate::aes_gcm_128::State<platform::portable::State, platform::portable::FieldElement>);
395 pub_crate_mod!(r"AES-GCM 256 ", aes_gcm_256, crate::aes_gcm_256::State<platform::portable::State, platform::portable::FieldElement>);
396}
397
398#[cfg(feature = "simd128")]
399pub(crate) mod neon {
400 pub_crate_mod!(r"AES-GCM 128 ", aes_gcm_128, crate::aes_gcm_128::State<platform::neon::State, platform::neon::FieldElement>);
401 pub_crate_mod!(r"AES-GCM 256 ", aes_gcm_256, crate::aes_gcm_256::State<platform::neon::State, platform::neon::FieldElement>);
402}
403
404#[cfg(feature = "simd256")]
405pub(crate) mod x64 {
406 // Here we don't use the `pub_crate_mod` macro because we need to add target features
407 // onto the functions.
408 macro_rules! x64_pub_crate_mod {
409 ($variant_comment:literal, $mod_name:ident, $state:ty) => {
410 #[doc = $variant_comment]
411 pub mod $mod_name {
412 use crate::$mod_name::KEY_LEN;
413 use crate::{platform, DecryptError, EncryptError};
414
415 type State = $state;
416
417 #[doc = $variant_comment]
418 /// encrypt.
419 pub fn encrypt(
420 key: &[u8],
421 nonce: &[u8],
422 aad: &[u8],
423 plaintext: &[u8],
424 ciphertext: &mut [u8],
425 tag: &mut [u8],
426 ) -> Result<(), EncryptError> {
427 debug_assert!(key.len() == KEY_LEN);
428
429 // due to use of `target_feature`, unsafe is needed here
430 #[inline]
431 #[cfg_attr(not(hax), target_feature(enable = "avx2", enable = "aes"))]
432 #[allow(unsafe_code)]
433 unsafe fn inner(
434 key: &[u8],
435 nonce: &[u8],
436 aad: &[u8],
437 plaintext: &[u8],
438 ciphertext: &mut [u8],
439 tag: &mut [u8],
440 ) -> Result<(), EncryptError> {
441 crate::encrypt::<State>(key, nonce, aad, plaintext, ciphertext, tag)
442 }
443
444 #[allow(unsafe_code)]
445 unsafe {
446 inner(key, nonce, aad, plaintext, ciphertext, tag)
447 }
448 }
449
450 #[doc = $variant_comment]
451 /// decrypt.
452 pub fn decrypt(
453 key: &[u8],
454 nonce: &[u8],
455 aad: &[u8],
456 ciphertext: &[u8],
457 tag: &[u8],
458 plaintext: &mut [u8],
459 ) -> Result<(), DecryptError> {
460 debug_assert!(key.len() == KEY_LEN);
461
462 // due to use of `target_feature`, unsafe is needed here
463 #[inline]
464 #[cfg_attr(not(hax), target_feature(enable = "avx2", enable = "aes"))]
465 #[allow(unsafe_code)]
466 unsafe fn inner(
467 key: &[u8],
468 nonce: &[u8],
469 aad: &[u8],
470 ciphertext: &[u8],
471 tag: &[u8],
472 plaintext: &mut [u8],
473 ) -> Result<(), DecryptError> {
474 crate::decrypt::<State>(key, nonce, aad, ciphertext, tag, plaintext)
475 }
476
477 #[allow(unsafe_code)]
478 unsafe {
479 inner(key, nonce, aad, ciphertext, tag, plaintext)
480 }
481 }
482 }
483 };
484 }
485
486 x64_pub_crate_mod!(r"AES-GCM 128 ", aes_gcm_128, crate::aes_gcm_128::State<platform::x64::State, platform::x64::FieldElement>);
487 x64_pub_crate_mod!(r"AES-GCM 256 ", aes_gcm_256, crate::aes_gcm_256::State<platform::x64::State, platform::x64::FieldElement>);
488}
489
490// traits re-exports
491pub use libcrux_traits::aead::consts::AeadConsts;
492pub use libcrux_traits::aead::typed_refs::Aead;
493
494pub use implementations::{AesGcm128, AesGcm256};
495
496#[doc(inline)]
497pub use aes_gcm_128::Key as AesGcm128Key;
498#[doc(inline)]
499pub use aes_gcm_128::Nonce as AesGcm128Nonce;
500#[doc(inline)]
501pub use aes_gcm_128::Tag as AesGcm128Tag;
502
503#[doc(inline)]
504pub use aes_gcm_256::Key as AesGcm256Key;
505#[doc(inline)]
506pub use aes_gcm_256::Nonce as AesGcm256Nonce;
507#[doc(inline)]
508pub use aes_gcm_256::Tag as AesGcm256Tag;