blob: 1ac2c228ee9b15fdc184a4ec6c5bb09d371d4e51 [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};
19use bssl_ffi::{
20 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) };
101 let ctx = NonNull::new(ctx).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_new))?;
102 Ok(Self { ctx, aead })
103 }
104
105 /// Encrypts and authenticates `data` and writes the result to `out`.
106 /// The `out` length should be at least the `data` length plus the `max_overhead` of the
107 /// `aead` and the length of `nonce` should match the `nonce_length` of the `aead`.
108 /// Otherwise, an error will be returned.
109 ///
110 /// The output is returned as a subslice of `out`.
111 pub fn seal<'b>(
112 &self,
113 data: &[u8],
114 nonce: &[u8],
115 ad: &[u8],
116 out: &'b mut [u8],
117 ) -> Result<&'b [u8]> {
118 let mut out_len = 0;
119 // SAFETY: Only reads from/writes to the provided slices.
120 let ret = unsafe {
121 EVP_AEAD_CTX_seal(
122 self.ctx.as_ptr(),
123 out.as_mut_ptr(),
124 &mut out_len,
125 out.len(),
126 nonce.as_ptr(),
127 nonce.len(),
128 data.as_ptr(),
129 data.len(),
130 ad.as_ptr(),
131 ad.len(),
132 )
133 };
134 check_int_result(ret, ApiName::EVP_AEAD_CTX_seal)?;
135 out.get(0..out_len).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_seal))
136 }
137
138 /// Authenticates `data` and decrypts it to `out`.
139 /// The `out` length should be at least the `data` length, and the length of `nonce` should
140 /// match the `nonce_length` of the `aead`.
141 /// Otherwise, an error will be returned.
142 ///
143 /// The output is returned as a subslice of `out`.
144 pub fn open<'b>(
145 &self,
146 data: &[u8],
147 nonce: &[u8],
148 ad: &[u8],
149 out: &'b mut [u8],
150 ) -> Result<&'b [u8]> {
151 let mut out_len = 0;
152 // SAFETY: Only reads from/writes to the provided slices.
153 // `data` and `out` are checked to be non-alias internally.
154 let ret = unsafe {
155 EVP_AEAD_CTX_open(
156 self.ctx.as_ptr(),
157 out.as_mut_ptr(),
158 &mut out_len,
159 out.len(),
160 nonce.as_ptr(),
161 nonce.len(),
162 data.as_ptr(),
163 data.len(),
164 ad.as_ptr(),
165 ad.len(),
166 )
167 };
168 check_int_result(ret, ApiName::EVP_AEAD_CTX_open)?;
169 out.get(0..out_len).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_open))
170 }
171
Alice Wang78b35f82023-10-06 11:57:35 +0000172 /// Returns the `Aead` represented by this `AeadContext`.
Alice Wang69b088f2023-09-27 12:54:05 +0000173 pub fn aead(&self) -> Aead {
174 self.aead
175 }
176}