diff --git a/aws-lc-rs/src/aead.rs b/aws-lc-rs/src/aead.rs index c90aaea0971..61bdb6b06f2 100644 --- a/aws-lc-rs/src/aead.rs +++ b/aws-lc-rs/src/aead.rs @@ -63,13 +63,10 @@ //! ``` use crate::{derive_debug_via_id, hkdf}; -use aes_gcm::{aead_open_separate_gather, aead_seal_separate, aead_seal_separate_scatter}; use std::fmt::Debug; use crate::error::Unspecified; use aead_ctx::AeadCtx; -use aws_lc::{EVP_AEAD_CTX_open, EVP_AEAD_CTX_seal}; -use std::mem::MaybeUninit; use std::ops::RangeFrom; mod aead_ctx; @@ -80,11 +77,13 @@ mod nonce; pub mod nonce_sequence; mod poly1305; pub mod quic; +mod unbound_key; pub use self::{ aes_gcm::{AES_128_GCM, AES_128_GCM_SIV, AES_256_GCM, AES_256_GCM_SIV}, chacha::CHACHA20_POLY1305, nonce::{Nonce, NONCE_LEN}, + unbound_key::UnboundKey, }; /// A sequences of unique nonces. @@ -137,7 +136,7 @@ impl BoundKey for OpeningKey { #[inline] fn algorithm(&self) -> &'static Algorithm { - self.key.algorithm + self.key.algorithm() } } @@ -222,6 +221,7 @@ impl OpeningKey { /// overwritten in an unspecified way. /// #[inline] + #[allow(clippy::needless_pass_by_value)] pub fn open_within<'in_out, A>( &mut self, aad: Aad, @@ -231,57 +231,15 @@ impl OpeningKey { where A: AsRef<[u8]>, { - open_within_( - &self.key, - self.nonce_sequence.advance()?, - aad, + self.key.open_within( + &self.nonce_sequence.advance()?, + aad.as_ref(), in_out, ciphertext_and_tag, ) } } -#[inline] -fn open_within_<'in_out, A: AsRef<[u8]>>( - key: &UnboundKey, - nonce: Nonce, - Aad(aad): Aad, - in_out: &'in_out mut [u8], - ciphertext_and_tag: RangeFrom, -) -> Result<&'in_out mut [u8], Unspecified> { - fn open_within<'in_out>( - key: &UnboundKey, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &'in_out mut [u8], - ciphertext_and_tag: RangeFrom, - ) -> Result<&'in_out mut [u8], Unspecified> { - let in_prefix_len = ciphertext_and_tag.start; - let ciphertext_and_tag_len = in_out.len().checked_sub(in_prefix_len).ok_or(Unspecified)?; - let ciphertext_len = ciphertext_and_tag_len - .checked_sub(TAG_LEN) - .ok_or(Unspecified)?; - check_per_nonce_max_bytes(key.algorithm, ciphertext_len)?; - let key_inner_ref = key.get_inner_key(); - - aead_open_combined(key_inner_ref, nonce, aad, &mut in_out[in_prefix_len..])?; - - // shift the plaintext to the left - in_out.copy_within(in_prefix_len..in_prefix_len + ciphertext_len, 0); - - // `ciphertext_len` is also the plaintext length. - Ok(&mut in_out[..ciphertext_len]) - } - - open_within( - key, - nonce, - Aad::from(aad.as_ref()), - in_out, - ciphertext_and_tag, - ) -} - /// An AEAD key for encrypting and signing ("sealing"), bound to a nonce /// sequence. /// @@ -302,7 +260,7 @@ impl BoundKey for SealingKey { #[inline] fn algorithm(&self) -> &'static Algorithm { - self.key.algorithm + self.key.algorithm() } } @@ -321,6 +279,7 @@ impl SealingKey { /// See `seal_in_place_append_tag` #[deprecated(note = "Renamed to `seal_in_place_append_tag`.")] #[inline] + #[allow(clippy::needless_pass_by_value)] pub fn seal_in_place( &mut self, aad: Aad, @@ -356,12 +315,8 @@ impl SealingKey { A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, { - seal_in_place_append_tag_( - &self.key, - self.nonce_sequence.advance()?, - Aad::from(aad.as_ref()), - in_out, - ) + self.key + .seal_combined(&self.nonce_sequence.advance()?, aad.as_ref(), in_out) } /// Encrypts and signs (“seals”) data in place. @@ -389,84 +344,11 @@ impl SealingKey { where A: AsRef<[u8]>, { - seal_in_place_separate_tag_( - &self.key, - self.nonce_sequence.advance()?, - Aad::from(aad.as_ref()), - in_out, - ) + self.key + .seal_separate(&self.nonce_sequence.advance()?, aad.as_ref(), in_out) } } -#[inline] -fn seal_in_place_append_tag_( - key: &UnboundKey, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut InOut, -) -> Result<(), Unspecified> -where - InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, -{ - check_per_nonce_max_bytes(key.algorithm, in_out.as_mut().len())?; - let key_inner_ref = key.get_inner_key(); - aead_seal_combined(key_inner_ref, nonce, aad, in_out) -} - -#[inline] -fn seal_in_place_separate_tag_( - key: &UnboundKey, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut [u8], -) -> Result { - check_per_nonce_max_bytes(key.algorithm, in_out.len())?; - let key_inner_ref = key.get_inner_key(); - aead_seal_separate(key_inner_ref, nonce, aad, in_out) -} - -#[inline] -fn seal_in_place_separate_scatter_( - key: &UnboundKey, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut [u8], - extra_in: &[u8], - extra_out_and_tag: &mut [u8], -) -> Result<(), Unspecified> { - check_per_nonce_max_bytes(key.algorithm, in_out.len())?; - let key_inner_ref = key.get_inner_key(); - aead_seal_separate_scatter( - key_inner_ref, - nonce, - aad, - in_out, - extra_in, - extra_out_and_tag, - ) -} - -#[inline] -fn open_separate_gather_( - key: &UnboundKey, - nonce: Nonce, - aad: Aad<&[u8]>, - in_ciphertext: &[u8], - in_tag: &[u8], - out_plaintext: &mut [u8], -) -> Result<(), Unspecified> { - check_per_nonce_max_bytes(key.algorithm, in_ciphertext.len())?; - let key_inner_ref = key.get_inner_key(); - aead_open_separate_gather( - key_inner_ref, - nonce, - aad, - in_ciphertext, - in_tag, - out_plaintext, - ) -} - /// The additionally authenticated data (AAD) for an opening or sealing /// operation. This data is authenticated but is **not** encrypted. /// @@ -499,55 +381,6 @@ impl Aad<[u8; 0]> { } } -/// An AEAD key without a designated role or nonce sequence. -pub struct UnboundKey { - inner: AeadCtx, - algorithm: &'static Algorithm, -} - -#[allow(clippy::missing_fields_in_debug)] -impl Debug for UnboundKey { - fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { - f.debug_struct("UnboundKey") - .field("algorithm", &self.algorithm) - .finish() - } -} - -impl UnboundKey { - /// Constructs an `UnboundKey`. - /// # Errors - /// `error::Unspecified` if `key_bytes.len() != algorithm.key_len()`. - pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result { - Ok(Self { - inner: (algorithm.init)(key_bytes)?, - algorithm, - }) - } - - #[inline] - fn get_inner_key(&self) -> &AeadCtx { - &self.inner - } - - /// The key's AEAD algorithm. - #[inline] - #[must_use] - pub fn algorithm(&self) -> &'static Algorithm { - self.algorithm - } -} - -impl From> for UnboundKey { - fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self { - let mut key_bytes = [0; MAX_KEY_LEN]; - let key_bytes = &mut key_bytes[..okm.len().key_len]; - let algorithm = *okm.len(); - okm.fill(key_bytes).unwrap(); - Self::new(algorithm, key_bytes).unwrap() - } -} - impl hkdf::KeyType for &'static Algorithm { #[inline] fn len(&self) -> usize { @@ -598,6 +431,7 @@ impl LessSafeKey { /// `error::Unspecified` when ciphertext is invalid. /// #[inline] + #[allow(clippy::needless_pass_by_value)] pub fn open_within<'in_out, A>( &self, nonce: Nonce, @@ -608,7 +442,8 @@ impl LessSafeKey { where A: AsRef<[u8]>, { - open_within_(&self.key, nonce, aad, in_out, ciphertext_and_tag) + self.key + .open_within(&nonce, aad.as_ref(), in_out, ciphertext_and_tag) } /// Authenticates and decrypts (“opens”) data into another provided slice. @@ -637,14 +472,8 @@ impl LessSafeKey { where A: AsRef<[u8]>, { - open_separate_gather_( - &self.key, - nonce, - Aad::from(aad.as_ref()), - in_ciphertext, - in_tag, - out_plaintext, - ) + self.key + .open_separate_gather(&nonce, aad.as_ref(), in_ciphertext, in_tag, out_plaintext) } /// Deprecated. Renamed to `seal_in_place_append_tag()`. @@ -684,7 +513,7 @@ impl LessSafeKey { A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, { - seal_in_place_append_tag_(&self.key, nonce, Aad::from(aad.as_ref()), in_out) + self.key.seal_combined(&nonce, aad.as_ref(), in_out) } /// Like `SealingKey::seal_in_place_separate_tag()`, except it accepts an @@ -706,7 +535,7 @@ impl LessSafeKey { where A: AsRef<[u8]>, { - seal_in_place_separate_tag_(&self.key, nonce, Aad::from(aad.as_ref()), in_out) + self.key.seal_separate(&nonce, aad.as_ref(), in_out) } /// Encrypts and signs (“seals”) data in place with extra plaintext. @@ -739,21 +568,15 @@ impl LessSafeKey { where A: AsRef<[u8]>, { - seal_in_place_separate_scatter_( - &self.key, - nonce, - Aad::from(aad.as_ref()), - in_out, - extra_in, - extra_out_and_tag, - ) + self.key + .seal_separate_scatter(&nonce, aad.as_ref(), in_out, extra_in, extra_out_and_tag) } /// The key's AEAD algorithm. #[inline] #[must_use] pub fn algorithm(&self) -> &'static Algorithm { - self.key.algorithm + self.key.algorithm() } } @@ -842,97 +665,6 @@ const TAG_LEN: usize = 16; /// The maximum length of a tag for the algorithms in this module. pub const MAX_TAG_LEN: usize = TAG_LEN; -#[inline] -#[must_use] -const fn u64_from_usize(x: usize) -> u64 { - x as u64 -} - -#[inline] -fn check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), Unspecified> { - if u64_from_usize(in_out_len) > alg.max_input_len { - return Err(Unspecified); - } - Ok(()) -} - -#[inline] -#[allow(clippy::needless_pass_by_value)] -pub(crate) fn aead_seal_combined( - key: &AeadCtx, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut InOut, -) -> Result<(), Unspecified> -where - InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, -{ - unsafe { - let aead_ctx = key.as_ref(); - let nonce = nonce.as_ref(); - - let plaintext_len = in_out.as_mut().len(); - - in_out.extend([0u8; TAG_LEN].iter()); - - let mut out_len = MaybeUninit::::uninit(); - let mut_in_out = in_out.as_mut(); - let add_str = aad.0; - - if 1 != EVP_AEAD_CTX_seal( - *aead_ctx.as_const(), - mut_in_out.as_mut_ptr(), - out_len.as_mut_ptr(), - plaintext_len + TAG_LEN, - nonce.as_ptr(), - NONCE_LEN, - mut_in_out.as_ptr(), - plaintext_len, - add_str.as_ptr(), - add_str.len(), - ) { - return Err(Unspecified); - } - - Ok(()) - } -} - -#[inline] -#[allow(clippy::needless_pass_by_value)] -pub(crate) fn aead_open_combined( - key: &AeadCtx, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut [u8], -) -> Result<(), Unspecified> { - unsafe { - let aead_ctx = key.as_ref(); - let nonce = nonce.as_ref(); - - let plaintext_len = in_out.len() - TAG_LEN; - - let aad_str = aad.0; - let mut out_len = MaybeUninit::::uninit(); - if 1 != EVP_AEAD_CTX_open( - *aead_ctx.as_const(), - in_out.as_mut_ptr(), - out_len.as_mut_ptr(), - plaintext_len, - nonce.as_ptr(), - NONCE_LEN, - in_out.as_ptr(), - plaintext_len + TAG_LEN, - aad_str.as_ptr(), - aad_str.len(), - ) { - return Err(Unspecified); - } - - Ok(()) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/aws-lc-rs/src/aead/aes_gcm.rs b/aws-lc-rs/src/aead/aes_gcm.rs index 08eafb6ce1a..a59ed1a3f5b 100644 --- a/aws-lc-rs/src/aead/aes_gcm.rs +++ b/aws-lc-rs/src/aead/aes_gcm.rs @@ -1,140 +1,10 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR ISC -use crate::aead::{Aad, Algorithm, AlgorithmID, Nonce, Tag, MAX_TAG_LEN}; -use std::mem::MaybeUninit; - use crate::aead::aead_ctx::AeadCtx; +use crate::aead::{Algorithm, AlgorithmID}; use crate::cipher::aes::{AES_128_KEY_LEN, AES_256_KEY_LEN}; use crate::error::Unspecified; -use aws_lc::{EVP_AEAD_CTX_open_gather, EVP_AEAD_CTX_seal_scatter}; -use std::ptr::null; - -#[inline] -#[allow(clippy::needless_pass_by_value)] -pub(crate) fn aead_seal_separate( - key: &AeadCtx, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut [u8], -) -> Result { - unsafe { - let aead_ctx = key.as_ref(); - let aad_slice = aad.as_ref(); - let nonce = nonce.as_ref(); - let mut tag = MaybeUninit::<[u8; MAX_TAG_LEN]>::uninit(); - let mut out_tag_len = MaybeUninit::::uninit(); - - if 1 != EVP_AEAD_CTX_seal_scatter( - *aead_ctx.as_const(), - in_out.as_mut_ptr(), - tag.as_mut_ptr().cast(), - out_tag_len.as_mut_ptr(), - MAX_TAG_LEN, - nonce.as_ptr(), - nonce.len(), - in_out.as_ptr(), - in_out.len(), - null(), - 0usize, - aad_slice.as_ptr(), - aad_slice.len(), - ) { - return Err(Unspecified); - } - Ok(Tag(tag.assume_init())) - } -} - -#[inline] -#[allow(clippy::needless_pass_by_value)] -pub(crate) fn aead_seal_separate_scatter( - key: &AeadCtx, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut [u8], - extra_in: &[u8], - extra_out_and_tag: &mut [u8], -) -> Result<(), Unspecified> { - // ensure that the extra lengths match - { - let actual = extra_in.len() + MAX_TAG_LEN; - let expected = extra_out_and_tag.len(); - - if actual != expected { - return Err(Unspecified); - } - } - - unsafe { - let aead_ctx = key.as_ref(); - let aad_slice = aad.as_ref(); - let nonce = nonce.as_ref(); - let mut out_tag_len = extra_out_and_tag.len(); - - if 1 != EVP_AEAD_CTX_seal_scatter( - *aead_ctx.as_const(), - in_out.as_mut_ptr(), - extra_out_and_tag.as_mut_ptr(), - &mut out_tag_len, - extra_out_and_tag.len(), - nonce.as_ptr(), - nonce.len(), - in_out.as_ptr(), - in_out.len(), - extra_in.as_ptr(), - extra_in.len(), - aad_slice.as_ptr(), - aad_slice.len(), - ) { - return Err(Unspecified); - } - Ok(()) - } -} - -#[inline] -#[allow(clippy::needless_pass_by_value)] -pub(crate) fn aead_open_separate_gather( - key: &AeadCtx, - nonce: Nonce, - aad: Aad<&[u8]>, - in_ciphertext: &[u8], - in_tag: &[u8], - out_plaintext: &mut [u8], -) -> Result<(), Unspecified> { - // ensure that the lengths match - { - let actual = in_ciphertext.len(); - let expected = out_plaintext.len(); - - if actual != expected { - return Err(Unspecified); - } - } - - unsafe { - let aead_ctx = key.as_ref(); - let aad_slice = aad.as_ref(); - let nonce = nonce.as_ref(); - - if 1 != EVP_AEAD_CTX_open_gather( - *aead_ctx.as_const(), - out_plaintext.as_mut_ptr(), - nonce.as_ptr(), - nonce.len(), - in_ciphertext.as_ptr(), - in_ciphertext.len(), - in_tag.as_ptr(), - in_tag.len(), - aad_slice.as_ptr(), - aad_slice.len(), - ) { - return Err(Unspecified); - } - Ok(()) - } -} /// AES-128 in GCM mode with 128-bit tags and 96 bit nonces. pub const AES_128_GCM: Algorithm = Algorithm { diff --git a/aws-lc-rs/src/aead/unbound_key.rs b/aws-lc-rs/src/aead/unbound_key.rs new file mode 100644 index 00000000000..b7d36b62258 --- /dev/null +++ b/aws-lc-rs/src/aead/unbound_key.rs @@ -0,0 +1,266 @@ +// Copyright 2015-2016 Brian Smith. +// SPDX-License-Identifier: ISC +// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +use super::{AeadCtx, Algorithm, MAX_KEY_LEN}; +use crate::aead::{Nonce, Tag, MAX_TAG_LEN, NONCE_LEN, TAG_LEN}; +use crate::{error::Unspecified, hkdf}; +use aws_lc::{EVP_AEAD_CTX_open, EVP_AEAD_CTX_seal}; +use aws_lc::{EVP_AEAD_CTX_open_gather, EVP_AEAD_CTX_seal_scatter}; +use core::fmt::Debug; +use core::ops::RangeFrom; +use std::mem::MaybeUninit; + +/// An AEAD key without a designated role or nonce sequence. +pub struct UnboundKey { + inner: AeadCtx, + algorithm: &'static Algorithm, +} + +#[allow(clippy::missing_fields_in_debug)] +impl Debug for UnboundKey { + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { + f.debug_struct("UnboundKey") + .field("algorithm", &self.algorithm) + .finish() + } +} + +impl UnboundKey { + /// Constructs an `UnboundKey`. + /// # Errors + /// `error::Unspecified` if `key_bytes.len() != algorithm.key_len()`. + pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result { + Ok(Self { + inner: (algorithm.init)(key_bytes)?, + algorithm, + }) + } + + /// The key's AEAD algorithm. + #[inline] + #[must_use] + pub fn algorithm(&self) -> &'static Algorithm { + self.algorithm + } + + #[inline] + pub(crate) fn open_within<'in_out>( + &self, + nonce: &Nonce, + aad: &[u8], + in_out: &'in_out mut [u8], + ciphertext_and_tag: RangeFrom, + ) -> Result<&'in_out mut [u8], Unspecified> { + let in_prefix_len = ciphertext_and_tag.start; + let ciphertext_and_tag_len = in_out.len().checked_sub(in_prefix_len).ok_or(Unspecified)?; + let ciphertext_len = ciphertext_and_tag_len + .checked_sub(TAG_LEN) + .ok_or(Unspecified)?; + + self.open_combined(nonce, aad, &mut in_out[in_prefix_len..])?; + + // shift the plaintext to the left + in_out.copy_within(in_prefix_len..in_prefix_len + ciphertext_len, 0); + + // `ciphertext_len` is also the plaintext length. + Ok(&mut in_out[..ciphertext_len]) + } + + #[inline] + pub(crate) fn open_combined( + &self, + nonce: &Nonce, + aad: &[u8], + in_out: &mut [u8], + ) -> Result<(), Unspecified> { + unsafe { + let aead_ctx = self.inner.as_ref(); + let nonce = nonce.as_ref(); + + let plaintext_len = in_out.len().checked_sub(TAG_LEN).ok_or(Unspecified)?; + self.check_per_nonce_max_bytes(plaintext_len)?; + + let mut out_len = MaybeUninit::::uninit(); + if 1 != EVP_AEAD_CTX_open( + *aead_ctx.as_const(), + in_out.as_mut_ptr(), + out_len.as_mut_ptr(), + plaintext_len, + nonce.as_ptr(), + NONCE_LEN, + in_out.as_ptr(), + plaintext_len + TAG_LEN, + aad.as_ptr(), + aad.len(), + ) { + return Err(Unspecified); + } + + Ok(()) + } + } + + #[inline] + pub(crate) fn open_separate_gather( + &self, + nonce: &Nonce, + aad: &[u8], + in_ciphertext: &[u8], + in_tag: &[u8], + out_plaintext: &mut [u8], + ) -> Result<(), Unspecified> { + self.check_per_nonce_max_bytes(in_ciphertext.len())?; + + // ensure that the lengths match + { + let actual = in_ciphertext.len(); + let expected = out_plaintext.len(); + + if actual != expected { + return Err(Unspecified); + } + } + + unsafe { + let aead_ctx = self.inner.as_ref(); + let nonce = nonce.as_ref(); + + if 1 != EVP_AEAD_CTX_open_gather( + *aead_ctx.as_const(), + out_plaintext.as_mut_ptr(), + nonce.as_ptr(), + nonce.len(), + in_ciphertext.as_ptr(), + in_ciphertext.len(), + in_tag.as_ptr(), + in_tag.len(), + aad.as_ptr(), + aad.len(), + ) { + return Err(Unspecified); + } + Ok(()) + } + } + + #[inline] + pub(crate) fn seal_combined( + &self, + nonce: &Nonce, + aad: &[u8], + in_out: &mut InOut, + ) -> Result<(), Unspecified> + where + InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, + { + unsafe { + let aead_ctx = self.inner.as_ref(); + let nonce = nonce.as_ref(); + + let plaintext_len = in_out.as_mut().len(); + + self.check_per_nonce_max_bytes(plaintext_len)?; + + in_out.extend([0u8; TAG_LEN].iter()); + + let mut out_len = MaybeUninit::::uninit(); + let mut_in_out = in_out.as_mut(); + + if 1 != EVP_AEAD_CTX_seal( + *aead_ctx.as_const(), + mut_in_out.as_mut_ptr(), + out_len.as_mut_ptr(), + plaintext_len + TAG_LEN, + nonce.as_ptr(), + NONCE_LEN, + mut_in_out.as_ptr(), + plaintext_len, + aad.as_ptr(), + aad.len(), + ) { + return Err(Unspecified); + } + + Ok(()) + } + } + + #[inline] + pub(crate) fn seal_separate( + &self, + nonce: &Nonce, + aad: &[u8], + in_out: &mut [u8], + ) -> Result { + let mut tag = [0; MAX_TAG_LEN]; + self.seal_separate_scatter(nonce, aad, in_out, &[], &mut tag)?; + Ok(Tag(tag)) + } + + #[inline] + pub(crate) fn seal_separate_scatter( + &self, + nonce: &Nonce, + aad: &[u8], + in_out: &mut [u8], + extra_in: &[u8], + extra_out_and_tag: &mut [u8], + ) -> Result<(), Unspecified> { + // ensure that the extra lengths match + { + let actual = extra_in.len() + MAX_TAG_LEN; + let expected = extra_out_and_tag.len(); + + if actual != expected { + return Err(Unspecified); + } + } + + unsafe { + let aead_ctx = self.inner.as_ref(); + let nonce = nonce.as_ref(); + let mut out_tag_len = extra_out_and_tag.len(); + + self.check_per_nonce_max_bytes(in_out.len() + extra_in.len())?; + + if 1 != EVP_AEAD_CTX_seal_scatter( + *aead_ctx.as_const(), + in_out.as_mut_ptr(), + extra_out_and_tag.as_mut_ptr(), + &mut out_tag_len, + extra_out_and_tag.len(), + nonce.as_ptr(), + nonce.len(), + in_out.as_ptr(), + in_out.len(), + extra_in.as_ptr(), + extra_in.len(), + aad.as_ptr(), + aad.len(), + ) { + return Err(Unspecified); + } + Ok(()) + } + } + + #[inline] + fn check_per_nonce_max_bytes(&self, in_out_len: usize) -> Result<(), Unspecified> { + if in_out_len as u64 > self.algorithm.max_input_len { + return Err(Unspecified); + } + Ok(()) + } +} + +impl From> for UnboundKey { + fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self { + let mut key_bytes = [0; MAX_KEY_LEN]; + let key_bytes = &mut key_bytes[..okm.len().key_len]; + let algorithm = *okm.len(); + okm.fill(key_bytes).unwrap(); + Self::new(algorithm, key_bytes).unwrap() + } +}