diff --git a/src/aead.rs b/src/aead.rs index e92527e..2e5bc70 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -4,255 +4,362 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{ - fmt, - os::raw::{c_char, c_int, c_uint}, - ptr::null_mut, -}; +use std::{os::raw::c_int, ptr::null_mut}; + +pub use recprot::RecordProtection; use crate::{ SECItemBorrowed, SymKey, - constants::{Cipher, Version}, - err::{Error, Res, sec::SEC_ERROR_BAD_DATA}, + err::{Error, Res}, p11::{ self, CK_ATTRIBUTE_TYPE, CK_GENERATOR_FUNCTION, CK_MECHANISM_TYPE, CKA_DECRYPT, CKA_ENCRYPT, CKA_NSS_MESSAGE, CKG_GENERATE_COUNTER_XOR, CKG_NO_GENERATE, CKM_AES_GCM, - CKM_CHACHA20_POLY1305, Context, PK11_AEADOp, PK11_CreateContextBySymKey, PK11SymKey, + CKM_CHACHA20_POLY1305, Context, PK11_AEADOp, PK11_CreateContextBySymKey, }, secstatus_to_res, - ssl::{PRUint8, PRUint16, PRUint64, SSLAeadContext}, }; -/// Trait for AEAD (Authenticated Encryption with Associated Data) operations. -/// -/// This trait provides a common interface for both real and null AEAD implementations, -/// eliminating code duplication and allowing for consistent usage patterns. -pub trait AeadTrait { - /// Create a new AEAD instance. - /// - /// # Errors - /// - /// Returns `Error` when the underlying crypto operations fail. - fn new(version: Version, cipher: Cipher, secret: &SymKey, prefix: &str) -> Res - where - Self: Sized; - - /// Get the expansion size (authentication tag length) for this AEAD. - fn expansion(&self) -> usize; - - /// Encrypt plaintext with associated data. - /// - /// # Errors - /// - /// Returns `Error` when encryption fails. - fn encrypt<'a>( - &self, - count: u64, - aad: &[u8], - input: &[u8], - output: &'a mut [u8], - ) -> Res<&'a [u8]>; - - /// Encrypt plaintext in place with associated data. - /// - /// # Errors - /// - /// Returns `Error` when encryption fails. - fn encrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res; - - /// Decrypt ciphertext with associated data. - /// - /// # Errors - /// - /// Returns `Error` when decryption or authentication fails. - fn decrypt<'a>( - &self, - count: u64, - aad: &[u8], - input: &[u8], - output: &'a mut [u8], - ) -> Res<&'a [u8]>; - - /// Decrypt ciphertext in place with associated data. - /// - /// # Errors - /// - /// Returns `Error` when decryption or authentication fails. - fn decrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res; -} +#[cfg(not(feature = "disable-encryption"))] +mod recprot { + use std::{ + fmt, + os::raw::{c_char, c_uint}, + ptr::null_mut, + }; + + use crate::{ + Cipher, Error, Res, SymKey, Version, + err::sec::SEC_ERROR_BAD_DATA, + p11::PK11SymKey, + ssl::{PRUint8, PRUint16, PRUint64, SSLAeadContext}, + }; + + experimental_api!(SSL_MakeAead( + version: PRUint16, + cipher: PRUint16, + secret: *mut PK11SymKey, + label_prefix: *const c_char, + label_prefix_len: c_uint, + ctx: *mut *mut SSLAeadContext, + )); + + experimental_api!(SSL_AeadEncrypt( + ctx: *const SSLAeadContext, + counter: PRUint64, + aad: *const PRUint8, + aad_len: c_uint, + input: *const PRUint8, + input_len: c_uint, + output: *const PRUint8, + output_len: *mut c_uint, + max_output: c_uint + )); + + experimental_api!(SSL_AeadDecrypt( + ctx: *const SSLAeadContext, + counter: PRUint64, + aad: *const PRUint8, + aad_len: c_uint, + input: *const PRUint8, + input_len: c_uint, + output: *const PRUint8, + output_len: *mut c_uint, + max_output: c_uint + )); + experimental_api!(SSL_DestroyAead(ctx: *mut SSLAeadContext)); + scoped_ptr!(AeadContext, SSLAeadContext, SSL_DestroyAead); + + pub struct RecordProtection { + ctx: AeadContext, + } -experimental_api!(SSL_MakeAead( - version: PRUint16, - cipher: PRUint16, - secret: *mut PK11SymKey, - label_prefix: *const c_char, - label_prefix_len: c_uint, - ctx: *mut *mut SSLAeadContext, -)); -experimental_api!(SSL_AeadEncrypt( - ctx: *const SSLAeadContext, - counter: PRUint64, - aad: *const PRUint8, - aad_len: c_uint, - input: *const PRUint8, - input_len: c_uint, - output: *const PRUint8, - output_len: *mut c_uint, - max_output: c_uint -)); -experimental_api!(SSL_AeadDecrypt( - ctx: *const SSLAeadContext, - counter: PRUint64, - aad: *const PRUint8, - aad_len: c_uint, - input: *const PRUint8, - input_len: c_uint, - output: *const PRUint8, - output_len: *mut c_uint, - max_output: c_uint -)); -experimental_api!(SSL_DestroyAead(ctx: *mut SSLAeadContext)); -scoped_ptr!(AeadContext, SSLAeadContext, SSL_DestroyAead); - -pub struct RealAead { - ctx: AeadContext, -} + impl RecordProtection { + unsafe fn from_raw( + version: Version, + cipher: Cipher, + secret: *mut PK11SymKey, + prefix: &str, + ) -> Res { + let p = prefix.as_bytes(); + let mut ctx: *mut SSLAeadContext = null_mut(); + unsafe { + SSL_MakeAead( + version, + cipher, + secret, + p.as_ptr().cast(), + c_uint::try_from(p.len())?, + &raw mut ctx, + )?; + } + Ok(Self { + ctx: AeadContext::from_ptr(ctx)?, + }) + } -impl RealAead { - unsafe fn from_raw( - version: Version, - cipher: Cipher, - secret: *mut PK11SymKey, - prefix: &str, - ) -> Res { - let p = prefix.as_bytes(); - let mut ctx: *mut SSLAeadContext = null_mut(); - unsafe { - SSL_MakeAead( - version, - cipher, - secret, - p.as_ptr().cast(), - c_uint::try_from(p.len())?, - &raw mut ctx, - )?; + /// Create a new AEAD instance. + /// + /// # Errors + /// + /// Returns `Error` when the underlying crypto operations fail. + pub fn new(version: Version, cipher: Cipher, secret: &SymKey, prefix: &str) -> Res { + let s: *mut PK11SymKey = **secret; + unsafe { Self::from_raw(version, cipher, s, prefix) } } - Ok(Self { - ctx: AeadContext::from_ptr(ctx)?, - }) - } -} -impl AeadTrait for RealAead { - fn new(version: Version, cipher: Cipher, secret: &SymKey, prefix: &str) -> Res { - let s: *mut PK11SymKey = **secret; - unsafe { Self::from_raw(version, cipher, s, prefix) } - } + /// Get the expansion size (authentication tag length) for this AEAD. + #[must_use] + #[expect(clippy::missing_const_for_fn, clippy::unused_self)] + pub fn expansion(&self) -> usize { + 16 + } - fn expansion(&self) -> usize { - 16 - } + /// Encrypt plaintext with associated data. + /// + /// # Errors + /// + /// Returns `Error` when encryption fails. + pub fn encrypt<'a>( + &self, + count: u64, + aad: &[u8], + input: &[u8], + output: &'a mut [u8], + ) -> Res<&'a [u8]> { + let mut l: c_uint = 0; + unsafe { + SSL_AeadEncrypt( + *self.ctx, + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + input.as_ptr(), + c_uint::try_from(input.len())?, + output.as_mut_ptr(), + &raw mut l, + c_uint::try_from(output.len())?, + ) + }?; + Ok(&output[..l.try_into()?]) + } - fn encrypt<'a>( - &self, - count: u64, - aad: &[u8], - input: &[u8], - output: &'a mut [u8], - ) -> Res<&'a [u8]> { - let mut l: c_uint = 0; - unsafe { - SSL_AeadEncrypt( - *self.ctx, - count, - aad.as_ptr(), - c_uint::try_from(aad.len())?, - input.as_ptr(), - c_uint::try_from(input.len())?, - output.as_mut_ptr(), - &raw mut l, - c_uint::try_from(output.len())?, - ) - }?; - Ok(&output[..l.try_into()?]) - } + /// Encrypt plaintext in place with associated data. + /// + /// # Errors + /// + /// Returns `Error` when encryption fails. + pub fn encrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res { + if data.len() < self.expansion() { + return Err(Error::from(SEC_ERROR_BAD_DATA)); + } + + let mut l: c_uint = 0; + unsafe { + SSL_AeadEncrypt( + *self.ctx, + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + data.as_ptr(), + c_uint::try_from(data.len() - self.expansion())?, + data.as_mut_ptr(), + &raw mut l, + c_uint::try_from(data.len())?, + ) + }?; + debug_assert_eq!(usize::try_from(l)?, data.len()); + Ok(data.len()) + } - fn encrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res { - if data.len() < self.expansion() { - return Err(Error::from(SEC_ERROR_BAD_DATA)); + /// Decrypt ciphertext with associated data. + /// + /// # Errors + /// + /// Returns `Error` when decryption or authentication fails. + pub fn decrypt<'a>( + &self, + count: u64, + aad: &[u8], + input: &[u8], + output: &'a mut [u8], + ) -> Res<&'a [u8]> { + let mut l: c_uint = 0; + unsafe { + // Note that NSS insists upon having extra space available for decryption, so + // the buffer for `output` should be the same length as `input`, even though + // the final result will be shorter. + SSL_AeadDecrypt( + *self.ctx, + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + input.as_ptr(), + c_uint::try_from(input.len())?, + output.as_mut_ptr(), + &raw mut l, + c_uint::try_from(output.len())?, + ) + }?; + Ok(&output[..l.try_into()?]) } - let mut l: c_uint = 0; - unsafe { - SSL_AeadEncrypt( - *self.ctx, - count, - aad.as_ptr(), - c_uint::try_from(aad.len())?, - data.as_ptr(), - c_uint::try_from(data.len() - self.expansion())?, - data.as_mut_ptr(), - &raw mut l, - c_uint::try_from(data.len())?, - ) - }?; - debug_assert_eq!(usize::try_from(l)?, data.len()); - Ok(data.len()) + /// Decrypt ciphertext in place with associated data. + /// + /// # Errors + /// + /// Returns `Error` when decryption or authentication fails. + pub fn decrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res { + let mut l: c_uint = 0; + unsafe { + // Note that NSS insists upon having extra space available for decryption, so + // the buffer for `output` should be the same length as `input`, even though + // the final result will be shorter. + SSL_AeadDecrypt( + *self.ctx, + count, + aad.as_ptr(), + c_uint::try_from(aad.len())?, + data.as_ptr(), + c_uint::try_from(data.len())?, + data.as_mut_ptr(), + &raw mut l, + c_uint::try_from(data.len())?, + ) + }?; + debug_assert_eq!(usize::try_from(l)?, data.len() - self.expansion()); + Ok(l.try_into()?) + } } - fn decrypt<'a>( - &self, - count: u64, - aad: &[u8], - input: &[u8], - output: &'a mut [u8], - ) -> Res<&'a [u8]> { - let mut l: c_uint = 0; - unsafe { - // Note that NSS insists upon having extra space available for decryption, so - // the buffer for `output` should be the same length as `input`, even though - // the final result will be shorter. - SSL_AeadDecrypt( - *self.ctx, - count, - aad.as_ptr(), - c_uint::try_from(aad.len())?, - input.as_ptr(), - c_uint::try_from(input.len())?, - output.as_mut_ptr(), - &raw mut l, - c_uint::try_from(output.len())?, - ) - }?; - Ok(&output[..l.try_into()?]) + impl fmt::Debug for RecordProtection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[AEAD Context]") + } } +} - fn decrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res { - let mut l: c_uint = 0; - unsafe { - // Note that NSS insists upon having extra space available for decryption, so - // the buffer for `output` should be the same length as `input`, even though - // the final result will be shorter. - SSL_AeadDecrypt( - *self.ctx, - count, - aad.as_ptr(), - c_uint::try_from(aad.len())?, - data.as_ptr(), - c_uint::try_from(data.len())?, - data.as_mut_ptr(), - &raw mut l, - c_uint::try_from(data.len())?, - ) - }?; - debug_assert_eq!(usize::try_from(l)?, data.len() - self.expansion()); - Ok(l.try_into()?) +#[cfg(feature = "disable-encryption")] +mod recprot { + use std::fmt; + + use crate::{Cipher, Error, Res, SymKey, Version, err::sec::SEC_ERROR_BAD_DATA}; + + pub const AEAD_NULL_TAG: &[u8] = &[0x0a; 16]; + + pub struct RecordProtection {} + + impl RecordProtection { + fn decrypt_check(&self, _count: u64, _aad: &[u8], input: &[u8]) -> Res { + if input.len() < self.expansion() { + return Err(Error::from(SEC_ERROR_BAD_DATA)); + } + + let len_encrypted = input + .len() + .checked_sub(self.expansion()) + .ok_or_else(|| Error::from(SEC_ERROR_BAD_DATA))?; + // Check that: + // 1) expansion is all zeros and + // 2) if the encrypted data is also supplied that at least some values are no zero + // (otherwise padding will be interpreted as a valid packet) + if &input[len_encrypted..] == AEAD_NULL_TAG + && (len_encrypted == 0 || input[..len_encrypted].iter().any(|x| *x != 0x0)) + { + Ok(len_encrypted) + } else { + Err(Error::from(SEC_ERROR_BAD_DATA)) + } + } + + /// Create a new AEAD instance. + /// + /// # Errors + /// + /// Returns `Error` when the underlying crypto operations fail. + #[expect(clippy::missing_const_for_fn, clippy::unnecessary_wraps)] + pub fn new( + _version: Version, + _cipher: Cipher, + _secret: &SymKey, + _prefix: &str, + ) -> Res { + Ok(Self {}) + } + + /// Get the expansion size (authentication tag length) for this AEAD. + #[must_use] + #[expect(clippy::missing_const_for_fn, clippy::unused_self)] + pub fn expansion(&self) -> usize { + AEAD_NULL_TAG.len() + } + + /// Encrypt plaintext with associated data. + /// + /// # Errors + /// + /// Returns `Error` when encryption fails. + #[expect(clippy::unnecessary_wraps)] + pub fn encrypt<'a>( + &self, + _count: u64, + _aad: &[u8], + input: &[u8], + output: &'a mut [u8], + ) -> Res<&'a [u8]> { + let l = input.len(); + output[..l].copy_from_slice(input); + output[l..l + self.expansion()].copy_from_slice(AEAD_NULL_TAG); + Ok(&output[..l + self.expansion()]) + } + + /// Encrypt plaintext in place with associated data. + /// + /// # Errors + /// + /// Returns `Error` when encryption fails. + #[expect(clippy::unnecessary_wraps)] + pub fn encrypt_in_place(&self, _count: u64, _aad: &[u8], data: &mut [u8]) -> Res { + let pos = data.len() - self.expansion(); + data[pos..].copy_from_slice(AEAD_NULL_TAG); + Ok(data.len()) + } + + /// Decrypt ciphertext with associated data. + /// + /// # Errors + /// + /// Returns `Error` when decryption or authentication fails. + pub fn decrypt<'a>( + &self, + count: u64, + aad: &[u8], + input: &[u8], + output: &'a mut [u8], + ) -> Res<&'a [u8]> { + self.decrypt_check(count, aad, input).map(|len| { + output[..len].copy_from_slice(&input[..len]); + &output[..len] + }) + } + + /// Decrypt ciphertext in place with associated data. + /// + /// # Errors + /// + /// Returns `Error` when decryption or authentication fails. + #[expect( + clippy::needless_pass_by_ref_mut, + reason = "Copy encryption enabled API" + )] + pub fn decrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res { + self.decrypt_check(count, aad, data) + } } -} -impl fmt::Debug for RealAead { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[AEAD Context]") + impl fmt::Debug for RecordProtection { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "[NULL AEAD]") + } } } @@ -358,7 +465,7 @@ impl Aead { }) } - pub fn seal(&mut self, aad: &[u8], pt: &[u8]) -> Result, Error> { + pub fn encrypt(&mut self, aad: &[u8], pt: &[u8]) -> Result, Error> { crate::init()?; assert_eq!(self.mode, Mode::Encrypt); @@ -394,7 +501,12 @@ impl Aead { Ok(ct) } - pub fn open(&mut self, aad: &[u8], seq: SequenceNumber, ct: &[u8]) -> Result, Error> { + pub fn decrypt( + &mut self, + aad: &[u8], + seq: SequenceNumber, + ct: &[u8], + ) -> Result, Error> { crate::init()?; assert_eq!(self.mode, Mode::Decrypt); @@ -450,11 +562,11 @@ mod test { let k = Aead::import_key(algorithm, key).unwrap(); let mut enc = Aead::new(Mode::Encrypt, algorithm, &k, *nonce).unwrap(); - let ciphertext = enc.seal(aad, pt).unwrap(); + let ciphertext = enc.encrypt(aad, pt).unwrap(); assert_eq!(&ciphertext[..], ct); let mut dec = Aead::new(Mode::Decrypt, algorithm, &k, *nonce).unwrap(); - let plaintext = dec.open(aad, 0, ct).unwrap(); + let plaintext = dec.decrypt(aad, 0, ct).unwrap(); assert_eq!(&plaintext[..], pt); } @@ -469,7 +581,7 @@ mod test { ) { let k = Aead::import_key(algorithm, key).unwrap(); let mut dec = Aead::new(Mode::Decrypt, algorithm, &k, *nonce).unwrap(); - let plaintext = dec.open(aad, seq, ct).unwrap(); + let plaintext = dec.decrypt(aad, seq, ct).unwrap(); assert_eq!(&plaintext[..], pt); } diff --git a/src/aead_null.rs b/src/aead_null.rs deleted file mode 100644 index f7587c0..0000000 --- a/src/aead_null.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; - -use crate::{ - aead::AeadTrait, - constants::{Cipher, Version}, - err::{Error, Res, sec::SEC_ERROR_BAD_DATA}, - p11::SymKey, -}; - -pub const AEAD_NULL_TAG: &[u8] = &[0x0a; 16]; - -pub struct AeadNull {} - -impl AeadNull { - fn decrypt_check(&self, _count: u64, _aad: &[u8], input: &[u8]) -> Res { - if input.len() < self.expansion() { - return Err(Error::from(SEC_ERROR_BAD_DATA)); - } - - let len_encrypted = input - .len() - .checked_sub(self.expansion()) - .ok_or_else(|| Error::from(SEC_ERROR_BAD_DATA))?; - // Check that: - // 1) expansion is all zeros and - // 2) if the encrypted data is also supplied that at least some values are no zero - // (otherwise padding will be interpreted as a valid packet) - if &input[len_encrypted..] == AEAD_NULL_TAG - && (len_encrypted == 0 || input[..len_encrypted].iter().any(|x| *x != 0x0)) - { - Ok(len_encrypted) - } else { - Err(Error::from(SEC_ERROR_BAD_DATA)) - } - } -} - -impl AeadTrait for AeadNull { - fn new(_version: Version, _cipher: Cipher, _secret: &SymKey, _prefix: &str) -> Res { - Ok(Self {}) - } - - fn expansion(&self) -> usize { - AEAD_NULL_TAG.len() - } - - fn encrypt<'a>( - &self, - _count: u64, - _aad: &[u8], - input: &[u8], - output: &'a mut [u8], - ) -> Res<&'a [u8]> { - let l = input.len(); - output[..l].copy_from_slice(input); - output[l..l + self.expansion()].copy_from_slice(AEAD_NULL_TAG); - Ok(&output[..l + self.expansion()]) - } - - fn encrypt_in_place(&self, _count: u64, _aad: &[u8], data: &mut [u8]) -> Res { - let pos = data.len() - self.expansion(); - data[pos..].copy_from_slice(AEAD_NULL_TAG); - Ok(data.len()) - } - - fn decrypt<'a>( - &self, - count: u64, - aad: &[u8], - input: &[u8], - output: &'a mut [u8], - ) -> Res<&'a [u8]> { - self.decrypt_check(count, aad, input).map(|len| { - output[..len].copy_from_slice(&input[..len]); - &output[..len] - }) - } - - fn decrypt_in_place(&self, count: u64, aad: &[u8], data: &mut [u8]) -> Res { - self.decrypt_check(count, aad, data) - } -} - -impl fmt::Debug for AeadNull { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[NULL AEAD]") - } -} diff --git a/src/lib.rs b/src/lib.rs index 338babe..036fdbe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,6 @@ #![cfg_attr(coverage_nightly, feature(coverage_attribute))] -#[cfg(feature = "disable-encryption")] -pub mod aead_null; pub mod agent; mod agentio; mod auth; @@ -53,14 +51,8 @@ mod _link_anchor { use windows::Win32::Security::Authentication::Identity::RtlGenRandom as _; } -#[cfg(not(feature = "disable-encryption"))] -pub use self::aead::RealAead as Aead; -#[cfg(feature = "disable-encryption")] -pub use self::aead::RealAead; -#[cfg(feature = "disable-encryption")] -pub use self::aead_null::AeadNull as Aead; pub use self::{ - aead::AeadTrait, + aead::RecordProtection, agent::{ Agent, AllowZeroRtt, Client, HandshakeState, Record, RecordList, ResumptionToken, SecretAgent, SecretAgentInfo, SecretAgentPreInfo, Server, ZeroRttCheckResult, diff --git a/src/selfencrypt.rs b/src/selfencrypt.rs index 8bcdb93..b1987fe 100644 --- a/src/selfencrypt.rs +++ b/src/selfencrypt.rs @@ -9,8 +9,7 @@ use std::{fmt::Write as _, io::Write as _, mem}; use log::{info, trace}; use crate::{ - Aead, - aead::AeadTrait as _, + RecordProtection, constants::{Cipher, Version}, err::{Error, Res}, hkdf, @@ -53,11 +52,11 @@ impl SelfEncrypt { }) } - fn make_aead(&self, k: &SymKey, salt: &[u8]) -> Res { + fn make_aead(&self, k: &SymKey, salt: &[u8]) -> Res { debug_assert_eq!(salt.len(), Self::SALT_LENGTH); let salt = hkdf::import_key(self.version, salt)?; let secret = hkdf::extract(self.version, self.cipher, Some(&salt), k)?; - Aead::new(self.version, self.cipher, &secret, "neqo self") + RecordProtection::new(self.version, self.cipher, &secret, "neqo self") } /// Rotate keys. This causes any previous key that is being held to be replaced by the current diff --git a/tests/aead.rs b/tests/aead.rs index 6b6b78c..693fd52 100644 --- a/tests/aead.rs +++ b/tests/aead.rs @@ -8,7 +8,7 @@ #![cfg(not(feature = "disable-encryption"))] use nss_rs::{ - Aead, AeadTrait as _, + RecordProtection, constants::{Cipher, TLS_AES_128_GCM_SHA256, TLS_VERSION_1_3}, hkdf, }; @@ -28,7 +28,7 @@ const PLAINTEXT: &[u8] = &[ 0x03, 0x04, ]; -fn make_aead(cipher: Cipher) -> Aead { +fn make_aead(cipher: Cipher) -> RecordProtection { fixture_init(); let secret = hkdf::import_key( @@ -40,7 +40,7 @@ fn make_aead(cipher: Cipher) -> Aead { ], ) .expect("make a secret"); - Aead::new( + RecordProtection::new( TLS_VERSION_1_3, cipher, &secret,