aws_lc_rs/aead/
aead_ctx.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4use core::mem::size_of;
5use core::ptr::null_mut;
6
7use crate::cipher::chacha;
8
9use crate::aws_lc::{
10    evp_aead_direction_t, evp_aead_direction_t_evp_aead_open, evp_aead_direction_t_evp_aead_seal,
11    EVP_AEAD_CTX_init, EVP_AEAD_CTX_init_with_direction, EVP_AEAD_CTX_zero, EVP_aead_aes_128_gcm,
12    EVP_aead_aes_128_gcm_randnonce, EVP_aead_aes_128_gcm_siv, EVP_aead_aes_128_gcm_tls12,
13    EVP_aead_aes_128_gcm_tls13, EVP_aead_aes_192_gcm, EVP_aead_aes_256_gcm,
14    EVP_aead_aes_256_gcm_randnonce, EVP_aead_aes_256_gcm_siv, EVP_aead_aes_256_gcm_tls12,
15    EVP_aead_aes_256_gcm_tls13, EVP_aead_chacha20_poly1305, OPENSSL_malloc, EVP_AEAD_CTX,
16};
17use crate::cipher::aes::{AES_128_KEY_LEN, AES_192_KEY_LEN, AES_256_KEY_LEN};
18use crate::error::Unspecified;
19use crate::ptr::LcPtr;
20
21pub(crate) enum AeadDirection {
22    Open,
23    Seal,
24}
25
26impl From<AeadDirection> for evp_aead_direction_t {
27    fn from(value: AeadDirection) -> Self {
28        match value {
29            AeadDirection::Open => evp_aead_direction_t_evp_aead_open,
30            AeadDirection::Seal => evp_aead_direction_t_evp_aead_seal,
31        }
32    }
33}
34
35#[allow(
36    clippy::large_enum_variant,
37    variant_size_differences,
38    non_camel_case_types
39)]
40pub(crate) enum AeadCtx {
41    AES_128_GCM(LcPtr<EVP_AEAD_CTX>),
42    AES_192_GCM(LcPtr<EVP_AEAD_CTX>),
43    AES_256_GCM(LcPtr<EVP_AEAD_CTX>),
44
45    AES_128_GCM_SIV(LcPtr<EVP_AEAD_CTX>),
46    AES_256_GCM_SIV(LcPtr<EVP_AEAD_CTX>),
47
48    AES_128_GCM_RANDNONCE(LcPtr<EVP_AEAD_CTX>),
49    AES_256_GCM_RANDNONCE(LcPtr<EVP_AEAD_CTX>),
50
51    AES_128_GCM_TLS12(LcPtr<EVP_AEAD_CTX>),
52    AES_256_GCM_TLS12(LcPtr<EVP_AEAD_CTX>),
53
54    AES_128_GCM_TLS13(LcPtr<EVP_AEAD_CTX>),
55    AES_256_GCM_TLS13(LcPtr<EVP_AEAD_CTX>),
56
57    CHACHA20_POLY1305(LcPtr<EVP_AEAD_CTX>),
58}
59
60unsafe impl Send for AeadCtx {}
61unsafe impl Sync for AeadCtx {}
62
63impl AeadCtx {
64    pub(crate) fn aes_128_gcm(key_bytes: &[u8], tag_len: usize) -> Result<Self, Unspecified> {
65        Ok(AeadCtx::AES_128_GCM(AeadCtx::aes_128_context(
66            EVP_aead_aes_128_gcm,
67            key_bytes,
68            tag_len,
69            None,
70        )?))
71    }
72
73    pub(crate) fn aes_128_gcm_siv(key_bytes: &[u8], tag_len: usize) -> Result<Self, Unspecified> {
74        Ok(AeadCtx::AES_128_GCM_SIV(AeadCtx::aes_128_context(
75            EVP_aead_aes_128_gcm_siv,
76            key_bytes,
77            tag_len,
78            None,
79        )?))
80    }
81
82    pub(crate) fn aes_192_gcm(key_bytes: &[u8], tag_len: usize) -> Result<Self, Unspecified> {
83        Ok(AeadCtx::AES_192_GCM(AeadCtx::aes_192_context(
84            EVP_aead_aes_192_gcm,
85            key_bytes,
86            tag_len,
87            None,
88        )?))
89    }
90
91    pub(crate) fn aes_256_gcm(key_bytes: &[u8], tag_len: usize) -> Result<Self, Unspecified> {
92        Ok(AeadCtx::AES_256_GCM(AeadCtx::aes_256_context(
93            EVP_aead_aes_256_gcm,
94            key_bytes,
95            tag_len,
96            None,
97        )?))
98    }
99
100    pub(crate) fn aes_256_gcm_siv(key_bytes: &[u8], tag_len: usize) -> Result<Self, Unspecified> {
101        Ok(AeadCtx::AES_256_GCM_SIV(AeadCtx::aes_256_context(
102            EVP_aead_aes_256_gcm_siv,
103            key_bytes,
104            tag_len,
105            None,
106        )?))
107    }
108
109    pub(crate) fn aes_128_gcm_randnonce(
110        key_bytes: &[u8],
111        tag_len: usize,
112        nonce_len: usize,
113    ) -> Result<Self, Unspecified> {
114        Ok(AeadCtx::AES_128_GCM_RANDNONCE(AeadCtx::aes_128_context(
115            EVP_aead_aes_128_gcm_randnonce,
116            key_bytes,
117            tag_len + nonce_len,
118            None,
119        )?))
120    }
121
122    pub(crate) fn aes_256_gcm_randnonce(
123        key_bytes: &[u8],
124        tag_len: usize,
125        nonce_len: usize,
126    ) -> Result<Self, Unspecified> {
127        Ok(AeadCtx::AES_256_GCM_RANDNONCE(AeadCtx::aes_256_context(
128            EVP_aead_aes_256_gcm_randnonce,
129            key_bytes,
130            tag_len + nonce_len,
131            None,
132        )?))
133    }
134
135    pub(crate) fn aes_128_gcm_tls12(
136        key_bytes: &[u8],
137        tag_len: usize,
138        direction: AeadDirection,
139    ) -> Result<Self, Unspecified> {
140        Ok(AeadCtx::AES_128_GCM_TLS12(AeadCtx::aes_128_context(
141            EVP_aead_aes_128_gcm_tls12,
142            key_bytes,
143            tag_len,
144            Some(direction),
145        )?))
146    }
147
148    pub(crate) fn aes_256_gcm_tls12(
149        key_bytes: &[u8],
150        tag_len: usize,
151        direction: AeadDirection,
152    ) -> Result<Self, Unspecified> {
153        Ok(AeadCtx::AES_256_GCM_TLS12(AeadCtx::aes_256_context(
154            EVP_aead_aes_256_gcm_tls12,
155            key_bytes,
156            tag_len,
157            Some(direction),
158        )?))
159    }
160
161    pub(crate) fn aes_128_gcm_tls13(
162        key_bytes: &[u8],
163        tag_len: usize,
164        direction: AeadDirection,
165    ) -> Result<Self, Unspecified> {
166        Ok(AeadCtx::AES_128_GCM_TLS13(AeadCtx::aes_128_context(
167            EVP_aead_aes_128_gcm_tls13,
168            key_bytes,
169            tag_len,
170            Some(direction),
171        )?))
172    }
173
174    pub(crate) fn aes_256_gcm_tls13(
175        key_bytes: &[u8],
176        tag_len: usize,
177        direction: AeadDirection,
178    ) -> Result<Self, Unspecified> {
179        Ok(AeadCtx::AES_256_GCM_TLS13(AeadCtx::aes_256_context(
180            EVP_aead_aes_256_gcm_tls13,
181            key_bytes,
182            tag_len,
183            Some(direction),
184        )?))
185    }
186
187    pub(crate) fn chacha20(key_bytes: &[u8], tag_len: usize) -> Result<Self, Unspecified> {
188        if chacha::KEY_LEN != key_bytes.len() {
189            return Err(Unspecified);
190        }
191        Ok(AeadCtx::CHACHA20_POLY1305(AeadCtx::build_context(
192            EVP_aead_chacha20_poly1305,
193            key_bytes,
194            tag_len,
195            None,
196        )?))
197    }
198
199    fn aes_128_context(
200        aead: unsafe extern "C" fn() -> *const aws_lc::evp_aead_st,
201        key_bytes: &[u8],
202        tag_len: usize,
203        direction: Option<AeadDirection>,
204    ) -> Result<LcPtr<EVP_AEAD_CTX>, Unspecified> {
205        if AES_128_KEY_LEN != key_bytes.len() {
206            return Err(Unspecified);
207        }
208        AeadCtx::build_context(aead, key_bytes, tag_len, direction)
209    }
210
211    fn aes_192_context(
212        aead: unsafe extern "C" fn() -> *const aws_lc::evp_aead_st,
213        key_bytes: &[u8],
214        tag_len: usize,
215        direction: Option<AeadDirection>,
216    ) -> Result<LcPtr<EVP_AEAD_CTX>, Unspecified> {
217        if AES_192_KEY_LEN != key_bytes.len() {
218            return Err(Unspecified);
219        }
220        AeadCtx::build_context(aead, key_bytes, tag_len, direction)
221    }
222
223    fn aes_256_context(
224        aead: unsafe extern "C" fn() -> *const aws_lc::evp_aead_st,
225        key_bytes: &[u8],
226        tag_len: usize,
227        direction: Option<AeadDirection>,
228    ) -> Result<LcPtr<EVP_AEAD_CTX>, Unspecified> {
229        if AES_256_KEY_LEN != key_bytes.len() {
230            return Err(Unspecified);
231        }
232        AeadCtx::build_context(aead, key_bytes, tag_len, direction)
233    }
234
235    fn build_context(
236        aead_fn: unsafe extern "C" fn() -> *const aws_lc::evp_aead_st,
237        key_bytes: &[u8],
238        tag_len: usize,
239        direction: Option<AeadDirection>,
240    ) -> Result<LcPtr<EVP_AEAD_CTX>, Unspecified> {
241        let aead = unsafe { aead_fn() };
242
243        // We are performing the allocation ourselves as EVP_AEAD_CTX_new will call EVP_AEAD_CTX_init by default
244        // and this avoid having to zero and reinitalize again if we need to set an explicit direction.
245        let mut aead_ctx: LcPtr<EVP_AEAD_CTX> =
246            LcPtr::new(unsafe { OPENSSL_malloc(size_of::<EVP_AEAD_CTX>()) }.cast())?;
247
248        unsafe { EVP_AEAD_CTX_zero(*aead_ctx.as_mut()) };
249
250        if 1 != match direction {
251            Some(direction) => unsafe {
252                EVP_AEAD_CTX_init_with_direction(
253                    *aead_ctx.as_mut(),
254                    aead,
255                    key_bytes.as_ptr(),
256                    key_bytes.len(),
257                    tag_len,
258                    direction.into(),
259                )
260            },
261            None => unsafe {
262                EVP_AEAD_CTX_init(
263                    *aead_ctx.as_mut(),
264                    aead,
265                    key_bytes.as_ptr(),
266                    key_bytes.len(),
267                    tag_len,
268                    null_mut(),
269                )
270            },
271        } {
272            return Err(Unspecified);
273        }
274        Ok(aead_ctx)
275    }
276}
277
278impl AsRef<LcPtr<EVP_AEAD_CTX>> for AeadCtx {
279    #[inline]
280    fn as_ref(&self) -> &LcPtr<EVP_AEAD_CTX> {
281        match self {
282            AeadCtx::AES_128_GCM(ctx)
283            | AeadCtx::AES_192_GCM(ctx)
284            | AeadCtx::AES_256_GCM(ctx)
285            | AeadCtx::AES_128_GCM_SIV(ctx)
286            | AeadCtx::AES_256_GCM_SIV(ctx)
287            | AeadCtx::AES_128_GCM_RANDNONCE(ctx)
288            | AeadCtx::AES_256_GCM_RANDNONCE(ctx)
289            | AeadCtx::AES_128_GCM_TLS12(ctx)
290            | AeadCtx::AES_256_GCM_TLS12(ctx)
291            | AeadCtx::AES_128_GCM_TLS13(ctx)
292            | AeadCtx::AES_256_GCM_TLS13(ctx)
293            | AeadCtx::CHACHA20_POLY1305(ctx) => ctx,
294        }
295    }
296}