blob: 311d37056aee4ece5d0090744f0a15ee9402c0f3 [file] [log] [blame]
Alice Wang69b088f2023-09-27 12:54:05 +00001// 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
17use crate::util::{check_int_result, to_call_failed_error};
18use bssl_avf_error::{ApiName, Result};
Maurice Lam0322b8c2023-12-18 22:13:48 +000019use bssl_sys::{
Alice Wang69b088f2023-09-27 12:54:05 +000020 EVP_AEAD_CTX_free, EVP_AEAD_CTX_new, EVP_AEAD_CTX_open, EVP_AEAD_CTX_seal,
Alice Wangee07f722023-10-03 15:20:17 +000021 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,
Alice Wang69b088f2023-09-27 12:54:05 +000023};
24use core::ptr::NonNull;
25
Alice Wang8b8e6e62023-10-02 09:10:13 +000026/// 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
29pub const AES_GCM_NONCE_LENGTH: usize = 12;
30
Alice Wang69b088f2023-09-27 12:54:05 +000031/// Magic value indicating that the default tag length for an AEAD should be used to
Alice Wang78b35f82023-10-06 11:57:35 +000032/// initialize `AeadContext`.
Alice Wang69b088f2023-09-27 12:54:05 +000033const AEAD_DEFAULT_TAG_LENGTH: usize = EVP_AEAD_DEFAULT_TAG_LENGTH as usize;
34
35/// Represents an AEAD algorithm.
36#[derive(Clone, Copy, Debug)]
37pub struct Aead(&'static EVP_AEAD);
38
39impl 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
45 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
Alice Wangee07f722023-10-03 15:20:17 +000054 /// AES-256 in Galois Counter Mode with internal nonce generation.
55 /// The 12-byte nonce is appended to the tag and is generated internally.
56 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
Alice Wang69b088f2023-09-27 12:54:05 +000065 /// Returns the maximum number of additional bytes added by the act of sealing data.
66 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.
72 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.
Alice Wang78b35f82023-10-06 11:57:35 +000079pub struct AeadContext {
Alice Wang69b088f2023-09-27 12:54:05 +000080 ctx: NonNull<EVP_AEAD_CTX>,
81 aead: Aead,
82}
83
Alice Wang78b35f82023-10-06 11:57:35 +000084impl Drop for AeadContext {
Alice Wang69b088f2023-09-27 12:54:05 +000085 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
Alice Wang78b35f82023-10-06 11:57:35 +000092impl AeadContext {
93 /// Creates a new `AeadContext` with the given `Aead` algorithm, `key` and `tag_len`.
Alice Wang69b088f2023-09-27 12:54:05 +000094 ///
95 /// The default tag length will be used if `tag_len` is None.
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) };
Alice Wangf6e02272024-03-20 10:11:30 +0000101 let ctx =
102 NonNull::new(ctx).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_new))?;
Alice Wang69b088f2023-09-27 12:54:05 +0000103 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`.
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)?;
Alice Wangf6e02272024-03-20 10:11:30 +0000136 out.get(0..out_len).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_seal))
Alice Wang69b088f2023-09-27 12:54:05 +0000137 }
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`.
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)?;
Alice Wangf6e02272024-03-20 10:11:30 +0000170 out.get(0..out_len).ok_or_else(|| to_call_failed_error(ApiName::EVP_AEAD_CTX_open))
Alice Wang69b088f2023-09-27 12:54:05 +0000171 }
172
Alice Wang78b35f82023-10-06 11:57:35 +0000173 /// Returns the `Aead` represented by this `AeadContext`.
Alice Wang69b088f2023-09-27 12:54:05 +0000174 pub fn aead(&self) -> Aead {
175 self.aead
176 }
177}