1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Wrappers of the AEAD functions in BoringSSL aead.h.
16 
17 use crate::util::{check_int_result, to_call_failed_error};
18 use bssl_avf_error::{ApiName, Result};
19 use bssl_sys::{
20     EVP_AEAD_CTX_free, EVP_AEAD_CTX_new, EVP_AEAD_CTX_open, EVP_AEAD_CTX_seal,
21     EVP_AEAD_max_overhead, EVP_AEAD_nonce_length, EVP_aead_aes_256_gcm,
22     EVP_aead_aes_256_gcm_randnonce, EVP_AEAD, EVP_AEAD_CTX, EVP_AEAD_DEFAULT_TAG_LENGTH,
23 };
24 use core::ptr::NonNull;
25 
26 /// BoringSSL spec recommends to use 12-byte nonces.
27 ///
28 /// https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html#EVP_aead_aes_256_gcm
29 pub const AES_GCM_NONCE_LENGTH: usize = 12;
30 
31 /// Magic value indicating that the default tag length for an AEAD should be used to
32 /// initialize `AeadContext`.
33 const AEAD_DEFAULT_TAG_LENGTH: usize = EVP_AEAD_DEFAULT_TAG_LENGTH as usize;
34 
35 /// Represents an AEAD algorithm.
36 #[derive(Clone, Copy, Debug)]
37 pub struct Aead(&'static EVP_AEAD);
38 
39 impl Aead {
40     /// This is AES-256 in Galois Counter Mode.
41     /// AES-GCM should only be used with 12-byte (96-bit) nonces as suggested in the
42     /// BoringSSL spec:
43     ///
44     /// https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html
aes_256_gcm() -> Self45     pub fn aes_256_gcm() -> Self {
46         // SAFETY: This function does not access any Rust variables and simply returns
47         // a pointer to the static variable in BoringSSL.
48         let p = unsafe { EVP_aead_aes_256_gcm() };
49         // SAFETY: The returned pointer should always be valid and points to a static
50         // `EVP_AEAD`.
51         Self(unsafe { &*p })
52     }
53 
54     /// AES-256 in Galois Counter Mode with internal nonce generation.
55     /// The 12-byte nonce is appended to the tag and is generated internally.
aes_256_gcm_randnonce() -> Self56     pub fn aes_256_gcm_randnonce() -> Self {
57         // SAFETY: This function does not access any Rust variables and simply returns
58         // a pointer to the static variable in BoringSSL.
59         let p = unsafe { EVP_aead_aes_256_gcm_randnonce() };
60         // SAFETY: The returned pointer should always be valid and points to a static
61         // `EVP_AEAD`.
62         Self(unsafe { &*p })
63     }
64 
65     /// Returns the maximum number of additional bytes added by the act of sealing data.
max_overhead(&self) -> usize66     pub fn max_overhead(&self) -> usize {
67         // SAFETY: This function only reads from self.
68         unsafe { EVP_AEAD_max_overhead(self.0) }
69     }
70 
71     /// Returns the length, in bytes, of the per-message nonce.
nonce_length(&self) -> usize72     pub fn nonce_length(&self) -> usize {
73         // SAFETY: This function only reads from self.
74         unsafe { EVP_AEAD_nonce_length(self.0) }
75     }
76 }
77 
78 /// Represents an AEAD algorithm configuration.
79 pub struct AeadContext {
80     ctx: NonNull<EVP_AEAD_CTX>,
81     aead: Aead,
82 }
83 
84 impl Drop for AeadContext {
drop(&mut self)85     fn drop(&mut self) {
86         // SAFETY: It is safe because the pointer has been created with `EVP_AEAD_CTX_new`
87         // and isn't used after this.
88         unsafe { EVP_AEAD_CTX_free(self.ctx.as_ptr()) }
89     }
90 }
91 
92 impl AeadContext {
93     /// Creates a new `AeadContext` with the given `Aead` algorithm, `key` and `tag_len`.
94     ///
95     /// The default tag length will be used if `tag_len` is None.
new(aead: Aead, key: &[u8], tag_len: Option<usize>) -> Result<Self>96     pub fn new(aead: Aead, key: &[u8], tag_len: Option<usize>) -> Result<Self> {
97         let tag_len = tag_len.unwrap_or(AEAD_DEFAULT_TAG_LENGTH);
98         // SAFETY: This function only reads the given data and the returned pointer is
99         // checked below.
100         let ctx = unsafe { EVP_AEAD_CTX_new(aead.0, key.as_ptr(), key.len(), tag_len) };
101         let ctx =
102             NonNull::new(ctx).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_new))?;
103         Ok(Self { ctx, aead })
104     }
105 
106     /// Encrypts and authenticates `data` and writes the result to `out`.
107     /// The `out` length should be at least the `data` length plus the `max_overhead` of the
108     /// `aead` and the length of `nonce` should match the `nonce_length` of the `aead`.
109     ///  Otherwise, an error will be returned.
110     ///
111     /// The output is returned as a subslice of `out`.
seal<'b>( &self, data: &[u8], nonce: &[u8], ad: &[u8], out: &'b mut [u8], ) -> Result<&'b [u8]>112     pub fn seal<'b>(
113         &self,
114         data: &[u8],
115         nonce: &[u8],
116         ad: &[u8],
117         out: &'b mut [u8],
118     ) -> Result<&'b [u8]> {
119         let mut out_len = 0;
120         // SAFETY: Only reads from/writes to the provided slices.
121         let ret = unsafe {
122             EVP_AEAD_CTX_seal(
123                 self.ctx.as_ptr(),
124                 out.as_mut_ptr(),
125                 &mut out_len,
126                 out.len(),
127                 nonce.as_ptr(),
128                 nonce.len(),
129                 data.as_ptr(),
130                 data.len(),
131                 ad.as_ptr(),
132                 ad.len(),
133             )
134         };
135         check_int_result(ret, ApiName::EVP_AEAD_CTX_seal)?;
136         out.get(0..out_len).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_seal))
137     }
138 
139     /// Authenticates `data` and decrypts it to `out`.
140     /// The `out` length should be at least the `data` length, and the length of `nonce` should
141     /// match the `nonce_length` of the `aead`.
142     /// Otherwise, an error will be returned.
143     ///
144     /// The output is returned as a subslice of `out`.
open<'b>( &self, data: &[u8], nonce: &[u8], ad: &[u8], out: &'b mut [u8], ) -> Result<&'b [u8]>145     pub fn open<'b>(
146         &self,
147         data: &[u8],
148         nonce: &[u8],
149         ad: &[u8],
150         out: &'b mut [u8],
151     ) -> Result<&'b [u8]> {
152         let mut out_len = 0;
153         // SAFETY: Only reads from/writes to the provided slices.
154         // `data` and `out` are checked to be non-alias internally.
155         let ret = unsafe {
156             EVP_AEAD_CTX_open(
157                 self.ctx.as_ptr(),
158                 out.as_mut_ptr(),
159                 &mut out_len,
160                 out.len(),
161                 nonce.as_ptr(),
162                 nonce.len(),
163                 data.as_ptr(),
164                 data.len(),
165                 ad.as_ptr(),
166                 ad.len(),
167             )
168         };
169         check_int_result(ret, ApiName::EVP_AEAD_CTX_open)?;
170         out.get(0..out_len).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_open))
171     }
172 
173     /// Returns the `Aead` represented by this `AeadContext`.
aead(&self) -> Aead174     pub fn aead(&self) -> Aead {
175         self.aead
176     }
177 }
178