[bssl] Implement AEAD BoringSSL wrapper

AEAD will be used to encrypt the private key in the RKP HAL.

Bug: 302286887
Test: atest libbssl_avf_nostd.test
Change-Id: I734cf5ecd8b938f2c47f439d6f51594ccafb4ff2
diff --git a/libs/bssl/src/aead.rs b/libs/bssl/src/aead.rs
new file mode 100644
index 0000000..a7d03b9
--- /dev/null
+++ b/libs/bssl/src/aead.rs
@@ -0,0 +1,160 @@
+// Copyright 2023, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Wrappers of the AEAD functions in BoringSSL aead.h.
+
+use crate::util::{check_int_result, to_call_failed_error};
+use bssl_avf_error::{ApiName, Result};
+use bssl_ffi::{
+    EVP_AEAD_CTX_free, EVP_AEAD_CTX_new, EVP_AEAD_CTX_open, EVP_AEAD_CTX_seal,
+    EVP_AEAD_max_overhead, EVP_AEAD_nonce_length, EVP_aead_aes_256_gcm, EVP_AEAD, EVP_AEAD_CTX,
+    EVP_AEAD_DEFAULT_TAG_LENGTH,
+};
+use core::ptr::NonNull;
+
+/// Magic value indicating that the default tag length for an AEAD should be used to
+/// initialize `AeadCtx`.
+const AEAD_DEFAULT_TAG_LENGTH: usize = EVP_AEAD_DEFAULT_TAG_LENGTH as usize;
+
+/// Represents an AEAD algorithm.
+#[derive(Clone, Copy, Debug)]
+pub struct Aead(&'static EVP_AEAD);
+
+impl Aead {
+    /// This is AES-256 in Galois Counter Mode.
+    /// AES-GCM should only be used with 12-byte (96-bit) nonces as suggested in the
+    /// BoringSSL spec:
+    ///
+    /// https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html
+    pub fn aes_256_gcm() -> Self {
+        // SAFETY: This function does not access any Rust variables and simply returns
+        // a pointer to the static variable in BoringSSL.
+        let p = unsafe { EVP_aead_aes_256_gcm() };
+        // SAFETY: The returned pointer should always be valid and points to a static
+        // `EVP_AEAD`.
+        Self(unsafe { &*p })
+    }
+
+    /// Returns the maximum number of additional bytes added by the act of sealing data.
+    pub fn max_overhead(&self) -> usize {
+        // SAFETY: This function only reads from self.
+        unsafe { EVP_AEAD_max_overhead(self.0) }
+    }
+
+    /// Returns the length, in bytes, of the per-message nonce.
+    pub fn nonce_length(&self) -> usize {
+        // SAFETY: This function only reads from self.
+        unsafe { EVP_AEAD_nonce_length(self.0) }
+    }
+}
+
+/// Represents an AEAD algorithm configuration.
+pub struct AeadCtx {
+    ctx: NonNull<EVP_AEAD_CTX>,
+    aead: Aead,
+}
+
+impl Drop for AeadCtx {
+    fn drop(&mut self) {
+        // SAFETY: It is safe because the pointer has been created with `EVP_AEAD_CTX_new`
+        // and isn't used after this.
+        unsafe { EVP_AEAD_CTX_free(self.ctx.as_ptr()) }
+    }
+}
+
+impl AeadCtx {
+    /// Creates a new `AeadCtx` with the given `Aead` algorithm, `key` and `tag_len`.
+    ///
+    /// The default tag length will be used if `tag_len` is None.
+    pub fn new(aead: Aead, key: &[u8], tag_len: Option<usize>) -> Result<Self> {
+        let tag_len = tag_len.unwrap_or(AEAD_DEFAULT_TAG_LENGTH);
+        // SAFETY: This function only reads the given data and the returned pointer is
+        // checked below.
+        let ctx = unsafe { EVP_AEAD_CTX_new(aead.0, key.as_ptr(), key.len(), tag_len) };
+        let ctx = NonNull::new(ctx).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_new))?;
+        Ok(Self { ctx, aead })
+    }
+
+    /// Encrypts and authenticates `data` and writes the result to `out`.
+    /// The `out` length should be at least the `data` length plus the `max_overhead` of the
+    /// `aead` and the length of `nonce` should match the `nonce_length` of the `aead`.
+    ///  Otherwise, an error will be returned.
+    ///
+    /// The output is returned as a subslice of `out`.
+    pub fn seal<'b>(
+        &self,
+        data: &[u8],
+        nonce: &[u8],
+        ad: &[u8],
+        out: &'b mut [u8],
+    ) -> Result<&'b [u8]> {
+        let mut out_len = 0;
+        // SAFETY: Only reads from/writes to the provided slices.
+        let ret = unsafe {
+            EVP_AEAD_CTX_seal(
+                self.ctx.as_ptr(),
+                out.as_mut_ptr(),
+                &mut out_len,
+                out.len(),
+                nonce.as_ptr(),
+                nonce.len(),
+                data.as_ptr(),
+                data.len(),
+                ad.as_ptr(),
+                ad.len(),
+            )
+        };
+        check_int_result(ret, ApiName::EVP_AEAD_CTX_seal)?;
+        out.get(0..out_len).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_seal))
+    }
+
+    /// Authenticates `data` and decrypts it to `out`.
+    /// The `out` length should be at least the `data` length, and the length of `nonce` should
+    /// match the `nonce_length` of the `aead`.
+    /// Otherwise, an error will be returned.
+    ///
+    /// The output is returned as a subslice of `out`.
+    pub fn open<'b>(
+        &self,
+        data: &[u8],
+        nonce: &[u8],
+        ad: &[u8],
+        out: &'b mut [u8],
+    ) -> Result<&'b [u8]> {
+        let mut out_len = 0;
+        // SAFETY: Only reads from/writes to the provided slices.
+        // `data` and `out` are checked to be non-alias internally.
+        let ret = unsafe {
+            EVP_AEAD_CTX_open(
+                self.ctx.as_ptr(),
+                out.as_mut_ptr(),
+                &mut out_len,
+                out.len(),
+                nonce.as_ptr(),
+                nonce.len(),
+                data.as_ptr(),
+                data.len(),
+                ad.as_ptr(),
+                ad.len(),
+            )
+        };
+        check_int_result(ret, ApiName::EVP_AEAD_CTX_open)?;
+        out.get(0..out_len).ok_or(to_call_failed_error(ApiName::EVP_AEAD_CTX_open))
+    }
+
+    /// Returns the `Aead` represented by this `AeadCtx`.
+    pub fn aead(&self) -> Aead {
+        self.aead
+    }
+}