Skip to main content

reallyme_crypto/
aes.rs

1// SPDX-FileCopyrightText: 2026 ReallyMe LLC
2//
3// SPDX-License-Identifier: MIT OR Apache-2.0
4
5//! AES-GCM facade routes backed by the semantic AEAD operation owner.
6
7use crypto_core::{AeadAlgorithm, CryptoError};
8use zeroize::Zeroizing;
9
10use crate::aead_error::{crypto_error_from_operation_error, invalid_output_error, AeadOperation};
11
12pub use crypto_aes256_gcm::{
13    Aes128GcmDecryptRequest, Aes128GcmEncryptRequest, Aes128GcmKey, Aes128GcmNonce,
14    Aes192GcmDecryptRequest, Aes192GcmEncryptRequest, Aes192GcmKey, Aes192GcmNonce, Aes256GcmKey,
15    Aes256GcmNonce, CiphertextWithTag, DecryptRequest, EncryptRequest, AES_128_GCM_KEY_LENGTH,
16    AES_128_GCM_NONCE_LENGTH, AES_128_GCM_TAG_LENGTH, AES_192_GCM_KEY_LENGTH,
17    AES_192_GCM_NONCE_LENGTH, AES_192_GCM_TAG_LENGTH, AES_256_GCM_KEY_LENGTH,
18    AES_256_GCM_NONCE_LENGTH, AES_256_GCM_TAG_LENGTH,
19};
20
21/// Encrypts with AES-128-GCM through the operation layer.
22pub fn encrypt_aes128_gcm(
23    request: &Aes128GcmEncryptRequest<'_>,
24) -> Result<CiphertextWithTag, CryptoError> {
25    seal(
26        AeadAlgorithm::Aes128Gcm,
27        request.key.as_bytes(),
28        request.nonce.as_bytes(),
29        request.aad,
30        request.plaintext,
31    )
32}
33
34/// Decrypts with AES-128-GCM through the operation layer.
35pub fn decrypt_aes128_gcm(request: &Aes128GcmDecryptRequest<'_>) -> Result<Vec<u8>, CryptoError> {
36    open(
37        AeadAlgorithm::Aes128Gcm,
38        request.key.as_bytes(),
39        request.nonce.as_bytes(),
40        request.aad,
41        request.ciphertext.as_bytes(),
42    )
43}
44
45/// Encrypts with AES-192-GCM through the operation layer.
46pub fn encrypt_aes192_gcm(
47    request: &Aes192GcmEncryptRequest<'_>,
48) -> Result<CiphertextWithTag, CryptoError> {
49    seal(
50        AeadAlgorithm::Aes192Gcm,
51        request.key.as_bytes(),
52        request.nonce.as_bytes(),
53        request.aad,
54        request.plaintext,
55    )
56}
57
58/// Decrypts with AES-192-GCM through the operation layer.
59pub fn decrypt_aes192_gcm(request: &Aes192GcmDecryptRequest<'_>) -> Result<Vec<u8>, CryptoError> {
60    open(
61        AeadAlgorithm::Aes192Gcm,
62        request.key.as_bytes(),
63        request.nonce.as_bytes(),
64        request.aad,
65        request.ciphertext.as_bytes(),
66    )
67}
68
69/// Encrypts with AES-256-GCM through the operation layer.
70pub fn encrypt(request: &EncryptRequest<'_>) -> Result<CiphertextWithTag, CryptoError> {
71    seal(
72        AeadAlgorithm::Aes256Gcm,
73        request.key.as_bytes(),
74        request.nonce.as_bytes(),
75        request.aad,
76        request.plaintext,
77    )
78}
79
80/// Decrypts with AES-256-GCM through the operation layer.
81pub fn decrypt(request: &DecryptRequest<'_>) -> Result<Vec<u8>, CryptoError> {
82    open(
83        AeadAlgorithm::Aes256Gcm,
84        request.key.as_bytes(),
85        request.nonce.as_bytes(),
86        request.aad,
87        request.ciphertext.as_bytes(),
88    )
89}
90
91/// Decrypts with AES-256-GCM and wipes plaintext when the owner is dropped.
92pub fn decrypt_zeroizing(request: &DecryptRequest<'_>) -> Result<Zeroizing<Vec<u8>>, CryptoError> {
93    open_zeroizing(
94        AeadAlgorithm::Aes256Gcm,
95        request.key.as_bytes(),
96        request.nonce.as_bytes(),
97        request.aad,
98        request.ciphertext.as_bytes(),
99    )
100}
101
102fn seal(
103    algorithm: AeadAlgorithm,
104    key: &[u8],
105    nonce: &[u8],
106    aad: &[u8],
107    plaintext: &[u8],
108) -> Result<CiphertextWithTag, CryptoError> {
109    let bytes =
110        crate::operations::aead::seal(algorithm, key, nonce, aad, plaintext).map_err(|error| {
111            crypto_error_from_operation_error(
112                algorithm,
113                AeadOperation::Seal,
114                error,
115                key.len(),
116                nonce.len(),
117                plaintext.len(),
118            )
119        })?;
120    CiphertextWithTag::from_vec(bytes).map_err(|_| invalid_output_error(AeadOperation::Seal))
121}
122
123fn open(
124    algorithm: AeadAlgorithm,
125    key: &[u8],
126    nonce: &[u8],
127    aad: &[u8],
128    ciphertext: &[u8],
129) -> Result<Vec<u8>, CryptoError> {
130    open_zeroizing(algorithm, key, nonce, aad, ciphertext).map(|plaintext| plaintext.to_vec())
131}
132
133fn open_zeroizing(
134    algorithm: AeadAlgorithm,
135    key: &[u8],
136    nonce: &[u8],
137    aad: &[u8],
138    ciphertext: &[u8],
139) -> Result<Zeroizing<Vec<u8>>, CryptoError> {
140    crate::operations::aead::open(algorithm, key, nonce, aad, ciphertext).map_err(|error| {
141        crypto_error_from_operation_error(
142            algorithm,
143            AeadOperation::Open,
144            error,
145            key.len(),
146            nonce.len(),
147            ciphertext.len(),
148        )
149    })
150}