diff --git a/aws-lc-rs/src/aead.rs b/aws-lc-rs/src/aead.rs index c9e41f5f5fa..d78d86da2df 100644 --- a/aws-lc-rs/src/aead.rs +++ b/aws-lc-rs/src/aead.rs @@ -115,7 +115,7 @@ //! ``` use crate::{derive_debug_via_id, fips::indicator_check, hkdf, iv::FixedLength}; -use std::{fmt::Debug, ptr::null, sync::Mutex}; +use std::{fmt::Debug, ptr::null}; use crate::error::Unspecified; use aead_ctx::AeadCtx; @@ -133,11 +133,15 @@ mod nonce; pub mod nonce_sequence; mod poly1305; pub mod quic; +mod rand_nonce; +mod tls; 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}, + rand_nonce::RandomizedNonceKey, + tls::{TlsProtocolId, TlsRecordOpeningKey, TlsRecordSealingKey}, }; /// A sequences of unique nonces. @@ -176,7 +180,6 @@ pub trait BoundKey: Debug { /// Intentionally not `Clone` or `Copy` since cloning would allow duplication /// of the nonce sequence. /// -/// # FIPS /// Prefer [`RandomizedNonceKey`] for opening operations. pub struct OpeningKey { key: UnboundKey, @@ -215,14 +218,13 @@ impl OpeningKey { /// has been overwritten by the plaintext; `plaintext` will refer to the /// plaintext without the tag. /// - /// # FIPS - /// Use this method with one of the following algorithms: - /// * `AES_128_GCM` - /// * `AES_256_GCM` - /// - /// Prefer [`RandomizedNonceKey::open_in_place`], as it provides API symmetry - /// with sealing operations. + /// Prefer [`RandomizedNonceKey::open_in_place`]. /// + // # FIPS + // Use this method with one of the following algorithms: + // * `AES_128_GCM` + // * `AES_256_GCM` + // /// # Errors /// `error::Unspecified` when ciphertext is invalid. In this case, `in_out` may have been /// overwritten in an unspecified way. @@ -280,14 +282,13 @@ impl OpeningKey { /// /// This reassembly be accomplished with three calls to `open_within()`. /// - /// # FIPS - /// Use this method with one of the following algorithms: - /// * `AES_128_GCM` - /// * `AES_256_GCM` - /// - /// Prefer [`RandomizedNonceKey::open_within`], as it provides API symmetry - /// with sealing operations. + /// Prefer [`RandomizedNonceKey::open_within`]. /// + // # FIPS + // Use this method with one of the following algorithms: + // * `AES_128_GCM` + // * `AES_256_GCM` + // /// # Errors /// `error::Unspecified` when ciphertext is invalid. In this case, `in_out` may have been /// overwritten in an unspecified way. @@ -360,7 +361,6 @@ fn open_within<'in_out, A: AsRef<[u8]>>( /// Intentionally not `Clone` or `Copy` since cloning would allow duplication /// of the nonce sequence. /// -/// # FIPS /// Prefer [`RandomizedNonceKey`] for sealing operations. pub struct SealingKey { key: UnboundKey, @@ -392,11 +392,11 @@ impl Debug for SealingKey { impl SealingKey { /// Deprecated. Renamed to `seal_in_place_append_tag`. /// - /// # FIPS - /// This method must not be used. - /// - /// See [`RandomizedNonceKey::seal_in_place_append_tag`]. + /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. /// + // # FIPS + // This method must not be used. + // /// # Errors /// See `seal_in_place_append_tag` #[deprecated(note = "Renamed to `seal_in_place_append_tag`.")] @@ -423,11 +423,11 @@ impl SealingKey { /// .map(|tag| in_out.extend(tag.as_ref())) /// ``` /// - /// # FIPS - /// This method must not be used. - /// - /// See [`RandomizedNonceKey::seal_in_place_append_tag`]. + /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. /// + // # FIPS + // This method must not be used. + // /// # Errors /// `error::Unspecified` when `nonce_sequence` cannot be advanced. #[inline] @@ -463,11 +463,11 @@ impl SealingKey { /// For most protocols, the caller must append the tag to the ciphertext. /// The tag will be `self.algorithm.tag_len()` bytes long. /// - /// # FIPS - /// This method must not be used. - /// - /// See [`RandomizedNonceKey::seal_in_place_separate_tag`]. + /// Prefer [`RandomizedNonceKey::seal_in_place_separate_tag`]. /// + // # FIPS + // This method must not be used. + // /// # Errors /// `error::Unspecified` when `nonce_sequence` cannot be advanced. #[inline] @@ -688,14 +688,12 @@ impl hkdf::KeyType for &'static Algorithm { /// /// Prefer [`RandomizedNonceKey`] when practical. /// -/// # FIPS -/// The following conditions must be met: -/// * `UnboundKey`'s algorithm is one of: -/// * `AES_128_GCM` -/// * `AES_256_GCM` -/// * Use `open_in_place` or `open_within` only. -/// -/// Use [`RandomizedNonceKey`]. +// # FIPS +// The following conditions must be met: +// * `UnboundKey`'s algorithm is one of: +// * `AES_128_GCM` +// * `AES_256_GCM` +// * Use `open_in_place` or `open_within` only. pub struct LessSafeKey { key: UnboundKey, } @@ -711,14 +709,13 @@ impl LessSafeKey { /// /// `nonce` must be unique for every use of the key to open data. /// - /// # FIPS - /// Use this method with one of the following algorithms: - /// * `AES_128_GCM` - /// * `AES_256_GCM` - /// - /// Prefer [`RandomizedNonceKey::open_in_place`] as it provides API symmetry with - /// sealing operations. + /// Prefer [`RandomizedNonceKey::open_in_place`]. /// + // # FIPS + // Use this method with one of the following algorithms: + // * `AES_128_GCM` + // * `AES_256_GCM` + // /// # Errors /// `error::Unspecified` when ciphertext is invalid. #[inline] @@ -738,14 +735,13 @@ impl LessSafeKey { /// /// `nonce` must be unique for every use of the key to open data. /// - /// # FIPS - /// Use this method with one of the following algorithms: - /// * `AES_128_GCM` - /// * `AES_256_GCM` - /// - /// Prefer [`RandomizedNonceKey::open_in_place`], as it provides API symmetry - /// with sealing operations. + /// Prefer [`RandomizedNonceKey::open_in_place`]. /// + // # FIPS + // Use this method with one of the following algorithms: + // * `AES_128_GCM` + // * `AES_256_GCM` + // /// # Errors /// `error::Unspecified` when ciphertext is invalid. #[inline] @@ -771,10 +767,11 @@ impl LessSafeKey { /// Deprecated. Renamed to `seal_in_place_append_tag()`. /// - /// # FIPS - /// This method must not be used. + /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. /// - /// See [`RandomizedNonceKey::seal_in_place_append_tag`]. + // # FIPS + // This method must not be used. + // #[deprecated(note = "Renamed to `seal_in_place_append_tag`.")] #[inline] #[allow(clippy::missing_errors_doc)] @@ -796,11 +793,11 @@ impl LessSafeKey { /// /// `nonce` must be unique for every use of the key to seal data. /// - /// # FIPS - /// This method must not be used. - /// - /// See [`RandomizedNonceKey::seal_in_place_append_tag`]. + /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. /// + // # FIPS + // This method must not be used. + // /// # Errors /// `error::Unspecified` if encryption operation fails. #[inline] @@ -830,11 +827,11 @@ impl LessSafeKey { /// /// `nonce` must be unique for every use of the key to seal data. /// - /// # FIPS - /// This method must not be used. - /// - /// See [`RandomizedNonceKey::seal_in_place_separate_tag`]. + /// Prefer [`RandomizedNonceKey::seal_in_place_separate_tag`]. /// + // # FIPS + // This method must not be used. + // /// # Errors /// `error::Unspecified` if encryption operation fails. #[inline] @@ -872,9 +869,9 @@ impl LessSafeKey { /// /// `nonce` must be unique for every use of the key to seal data. /// - /// # FIPS - /// This method must not be used. - /// + // # FIPS + // This method must not be used. + // /// # Errors /// `error::Unspecified` if encryption operation fails. #[inline] @@ -917,437 +914,6 @@ impl Debug for LessSafeKey { } } -/// AEAD Cipher key using a randomized nonce. -/// -/// `RandomizedNonceKey` handles generation random nonce values. -/// -/// The following algorithms are supported: -/// * `AES_128_GCM` -/// * `AES_256_GCM` -/// -/// # FIPS -/// Use this type in place of `LessSafeKey`, `OpeningKey`, `SealingKey`. -pub struct RandomizedNonceKey { - ctx: AeadCtx, - algorithm: &'static Algorithm, -} - -impl RandomizedNonceKey { - /// New Random Nonce Sequence - /// # Errors - pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result { - let ctx = match algorithm.id { - AlgorithmID::AES_128_GCM => AeadCtx::aes_128_gcm_randnonce( - key_bytes, - algorithm.tag_len(), - algorithm.nonce_len(), - ), - AlgorithmID::AES_256_GCM => AeadCtx::aes_256_gcm_randnonce( - key_bytes, - algorithm.tag_len(), - algorithm.nonce_len(), - ), - AlgorithmID::AES_128_GCM_SIV - | AlgorithmID::AES_256_GCM_SIV - | AlgorithmID::CHACHA20_POLY1305 => return Err(Unspecified), - }?; - Ok(Self { ctx, algorithm }) - } - - /// Authenticates and decrypts (“opens”) data in place. - // - // aad is the additional authenticated data (AAD), if any. - // - // On input, in_out must be the ciphertext followed by the tag. When open_in_place() returns Ok(plaintext), - // the input ciphertext has been overwritten by the plaintext; plaintext will refer to the plaintext without the tag. - /// - /// # Errors - /// `error::Unspecified` when ciphertext is invalid. - #[inline] - pub fn open_in_place<'in_out, A>( - &self, - nonce: Nonce, - aad: Aad, - in_out: &'in_out mut [u8], - ) -> Result<&'in_out mut [u8], Unspecified> - where - A: AsRef<[u8]>, - { - self.open_within(nonce, aad, in_out, 0..) - } - - /// Authenticates and decrypts (“opens”) data in place, with a shift. - /// - /// `aad` is the additional authenticated data (AAD), if any. - /// - /// See [`OpeningKey::open_within`] for details on `ciphertext_and_tag` argument usage. - /// - /// # Errors - /// `error::Unspecified` when ciphertext is invalid. - #[inline] - pub fn open_within<'in_out, A>( - &self, - nonce: Nonce, - aad: Aad, - in_out: &'in_out mut [u8], - ciphertext_and_tag: RangeFrom, - ) -> Result<&'in_out mut [u8], Unspecified> - where - A: AsRef<[u8]>, - { - open_within( - self.algorithm, - &self.ctx, - nonce, - aad, - in_out, - ciphertext_and_tag, - ) - } - - /// Encrypts and signs (“seals”) data in place, appending the tag to the - /// resulting ciphertext. - /// - /// `key.seal_in_place_append_tag(aad, in_out)` is equivalent to: - /// - /// ```skip - /// key.seal_in_place_separate_tag(aad, in_out.as_mut()) - /// .map(|tag| in_out.extend(tag.as_ref())) - /// ``` - /// - /// The Nonce used for the operation is randomly generated, and returned to the caller. - /// - /// # Errors - /// `error::Unspecified` if encryption operation fails. - #[inline] - #[allow(clippy::needless_pass_by_value)] - pub fn seal_in_place_append_tag<'a, A, InOut>( - &self, - aad: Aad, - in_out: &'a mut InOut, - ) -> Result - where - A: AsRef<[u8]>, - InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, - { - seal_in_place_append_tag( - self.algorithm, - &self.ctx, - None, - Aad::from(aad.as_ref()), - in_out, - ) - } - - /// Encrypts and signs (“seals”) data in place. - /// - /// `aad` is the additional authenticated data (AAD), if any. This is - /// authenticated but not encrypted. The type `A` could be a byte slice - /// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec`, etc. - /// If there is no AAD then use `Aad::empty()`. - /// - /// The plaintext is given as the input value of `in_out`. `seal_in_place()` - /// will overwrite the plaintext with the ciphertext and return the tag. - /// For most protocols, the caller must append the tag to the ciphertext. - /// The tag will be `self.algorithm.tag_len()` bytes long. - /// - /// The Nonce used for the operation is randomly generated, and returned to the caller. - /// - /// # Errors - /// `error::Unspecified` if encryption operation fails. - #[inline] - #[allow(clippy::needless_pass_by_value)] - pub fn seal_in_place_separate_tag( - &self, - aad: Aad, - in_out: &mut [u8], - ) -> Result<(Nonce, Tag), Unspecified> - where - A: AsRef<[u8]>, - { - let nonce = if let AlgorithmID::CHACHA20_POLY1305 = self.algorithm.id { - Some(Nonce(FixedLength::::new()?)) - } else { - None - }; - seal_in_place_separate_tag( - self.algorithm, - &self.ctx, - nonce, - Aad::from(aad.as_ref()), - in_out, - ) - } - - /// The key's AEAD algorithm. - #[inline] - #[must_use] - pub fn algorithm(&self) -> &'static Algorithm { - self.algorithm - } -} - -/// The Transport Layer Security (TLS) protocol version. -pub enum TlsProtocolId { - /// TLS 1.2 (RFC 5246) - TLS12, - - /// TLS 1.3 (RFC 8446) - TLS13, -} - -/// AEAD Encryption key used for TLS protocol record encryption. -/// -/// This type encapsulates encryption operations for TLS AEAD algorithms. -/// It validates that the provides nonce values are monotonically increasing for each invocation. -/// -/// The following algorithms are supported: -/// * `AES_128_GCM` -/// * `AES_256_GCM` -/// -/// # FIPS -/// Use this type in place of `LessSafeKey`, `OpeningKey`, `SealingKey`. -pub struct TlsRecordSealingKey { - // The TLS specific construction for TLS ciphers in AWS-LC are not thread-safe! - // The choice here was either wrap the underlying EVP_AEAD_CTX in a Mutex as done here, - // or force this type to !Sync. Since this is an implementation detail of AWS-LC - // we have optex to manage this behavior internally. - ctx: Mutex, - algorithm: &'static Algorithm, -} - -impl TlsRecordSealingKey { - /// New TLS record sealing key. Only supports `AES_128_GCM` and `AES_256_GCM`. - /// - /// # Errors - /// * `Unspecified`: Returned if the length of `key_bytes` does not match the chosen algorithm, - /// or if an unsupported algorithm is provided. - pub fn new( - algorithm: &'static Algorithm, - protocol: TlsProtocolId, - key_bytes: &[u8], - ) -> Result { - let ctx = Mutex::new(match (algorithm.id, protocol) { - (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_128_gcm_tls12( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Seal, - ), - (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_128_gcm_tls13( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Seal, - ), - (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_256_gcm_tls12( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Seal, - ), - (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_256_gcm_tls13( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Seal, - ), - ( - AlgorithmID::AES_128_GCM_SIV - | AlgorithmID::AES_256_GCM_SIV - | AlgorithmID::CHACHA20_POLY1305, - _, - ) => Err(Unspecified), - }?); - Ok(Self { ctx, algorithm }) - } - - /// Accepts a `Nonce` and `Aad` construction that is unique for this key and - /// TLS record sealing operation for the configured TLS protocol version. - /// - /// `nonce` must be unique and incremented per each sealing operation, - /// otherwise an error is returned. - /// - /// # Errors - /// `error::Unspecified` if encryption operation fails. - #[inline] - #[allow(clippy::needless_pass_by_value)] - pub fn seal_in_place_append_tag( - &self, - nonce: Nonce, - aad: Aad, - in_out: &mut InOut, - ) -> Result<(), Unspecified> - where - A: AsRef<[u8]>, - InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, - { - let ctx = self.ctx.lock().map_err(|_| Unspecified)?; - seal_in_place_append_tag( - self.algorithm, - &ctx, - Some(nonce), - Aad::from(aad.as_ref()), - in_out, - ) - .map(|_| ()) - } - - /// Encrypts and signs (“seals”) data in place. - /// - /// `aad` is the additional authenticated data (AAD), if any. This is - /// authenticated but not encrypted. The type `A` could be a byte slice - /// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec`, etc. - /// If there is no AAD then use `Aad::empty()`. - /// - /// The plaintext is given as the input value of `in_out`. `seal_in_place()` - /// will overwrite the plaintext with the ciphertext and return the tag. - /// For most protocols, the caller must append the tag to the ciphertext. - /// The tag will be `self.algorithm.tag_len()` bytes long. - /// - /// The Nonce used for the operation is randomly generated, and returned to the caller. - /// - /// # Errors - /// `error::Unspecified` if encryption operation fails. - #[inline] - #[allow(clippy::needless_pass_by_value)] - pub fn seal_in_place_separate_tag( - &self, - nonce: Nonce, - aad: Aad, - in_out: &mut [u8], - ) -> Result<(Nonce, Tag), Unspecified> - where - A: AsRef<[u8]>, - { - let ctx = self.ctx.lock().map_err(|_| Unspecified)?; - seal_in_place_separate_tag( - self.algorithm, - &ctx, - Some(nonce), - Aad::from(aad.as_ref()), - in_out, - ) - } - - /// The key's AEAD algorithm. - #[inline] - #[must_use] - pub fn algorithm(&self) -> &'static Algorithm { - self.algorithm - } -} - -/// AEAD Encryption key used for TLS protocol record encryption. -/// -/// This type encapsulates decryption operations for TLS AEAD algorithms. -/// It validates that the provided nonce values are monotonically increasing for each invocation. -/// -/// The following algorithms are supported: -/// * `AES_128_GCM` -/// * `AES_256_GCM` -/// -/// # FIPS -/// Use this type in place of `LessSafeKey`, `OpeningKey`, `SealingKey`. -pub struct TlsRecordOpeningKey { - // The TLS specific construction for TLS ciphers in AWS-LC are not thread-safe! - // The choice here was either wrap the underlying EVP_AEAD_CTX in a Mutex as done here, - // or force this type to !Sync. Since this is an implementation detail of AWS-LC - // we have optex to manage this behavior internally. - ctx: Mutex, - algorithm: &'static Algorithm, -} - -impl TlsRecordOpeningKey { - /// New TLS record opening key. Only supports `AES_128_GCM` and `AES_256_GCM` Algorithms. - /// - /// # Errors - /// * `Unspecified`: Returned if the length of `key_bytes` does not match the chosen algorithm, - /// or if an unsupported algorithm is provided. - pub fn new( - algorithm: &'static Algorithm, - protocol: TlsProtocolId, - key_bytes: &[u8], - ) -> Result { - let ctx = Mutex::new(match (algorithm.id, protocol) { - (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_128_gcm_tls12( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Open, - ), - (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_128_gcm_tls13( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Open, - ), - (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_256_gcm_tls12( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Open, - ), - (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_256_gcm_tls13( - key_bytes, - algorithm.tag_len(), - aead_ctx::AeadDirection::Open, - ), - ( - AlgorithmID::AES_128_GCM_SIV - | AlgorithmID::AES_256_GCM_SIV - | AlgorithmID::CHACHA20_POLY1305, - _, - ) => Err(Unspecified), - }?); - Ok(Self { ctx, algorithm }) - } - - /// Accepts a Noce and Aad construction that is unique for this TLS record - /// opening operation. - /// - /// `nonce` must be unique for every use of the key to open data. - /// - /// # Errors - /// `error::Unspecified` when ciphertext is invalid. - #[inline] - pub fn open_in_place<'in_out, A>( - &self, - nonce: Nonce, - aad: Aad, - in_out: &'in_out mut [u8], - ) -> Result<&'in_out mut [u8], Unspecified> - where - A: AsRef<[u8]>, - { - self.open_within(nonce, aad, in_out, 0..) - } - - /// Accepts a Noce and Aad construction that is unique for this TLS record - /// opening operation. - /// - /// `nonce` must be unique for every use of the key to open data. - /// - /// See [`OpeningKey::open_within`] for details on `ciphertext_and_tag` argument usage. - /// - /// # Errors - /// `error::Unspecified` when ciphertext is invalid. - #[inline] - pub fn open_within<'in_out, A>( - &self, - nonce: Nonce, - aad: Aad, - in_out: &'in_out mut [u8], - ciphertext_and_tag: RangeFrom, - ) -> Result<&'in_out mut [u8], Unspecified> - where - A: AsRef<[u8]>, - { - let ctx = self.ctx.lock().map_err(|_| Unspecified)?; - open_within(self.algorithm, &ctx, nonce, aad, in_out, ciphertext_and_tag) - } - - /// The key's AEAD algorithm. - #[inline] - #[must_use] - pub fn algorithm(&self) -> &'static Algorithm { - self.algorithm - } -} - /// An AEAD Algorithm. pub struct Algorithm { init: fn(key: &[u8], tag_len: usize) -> Result, @@ -1727,22 +1293,10 @@ pub(crate) fn aead_open_combined_randnonce( mod tests { use super::*; use crate::{iv::FixedLength, test::from_hex}; - use paste::paste; #[cfg(feature = "fips")] mod fips; - const TEST_128_BIT_KEY: &[u8] = &[ - 0xb0, 0x37, 0x9f, 0xf8, 0xfb, 0x8e, 0xa6, 0x31, 0xf4, 0x1c, 0xe6, 0x3e, 0xb5, 0xc5, 0x20, - 0x7c, - ]; - - const TEST_256_BIT_KEY: &[u8] = &[ - 0x56, 0xd8, 0x96, 0x68, 0xbd, 0x96, 0xeb, 0xff, 0x5e, 0xa2, 0x0b, 0x34, 0xf2, 0x79, 0x84, - 0x6e, 0x2b, 0x13, 0x01, 0x3d, 0xab, 0x1d, 0xa4, 0x07, 0x5a, 0x16, 0xd5, 0x0b, 0x53, 0xb0, - 0xcc, 0x88, - ]; - #[test] fn test_aes_128() { let key = from_hex("000102030405060708090a0b0c0d0e0f").unwrap(); @@ -1793,191 +1347,4 @@ mod tests { assert_eq!(plaintext, in_out[..plaintext.len()]); } - - macro_rules! test_randnonce { - ($name:ident, $alg:expr, $key:expr) => { - paste! { - #[test] - fn []() { - assert!(RandomizedNonceKey::new($alg, $key).is_err()); - } - } - }; - ($name:ident, $alg:expr, $key:expr, $expect_tag_len:expr, $expect_nonce_len:expr) => { - paste! { - #[test] - fn []() { - let plaintext = from_hex("00112233445566778899aabbccddeeff").unwrap(); - let rand_nonce_key = - RandomizedNonceKey::new($alg, $key).unwrap(); - - assert_eq!($alg, rand_nonce_key.algorithm()); - assert_eq!(*$expect_tag_len, $alg.tag_len()); - assert_eq!(*$expect_nonce_len, $alg.nonce_len()); - - let mut in_out = Vec::from(plaintext.as_slice()); - - let nonce = rand_nonce_key - .seal_in_place_append_tag(Aad::empty(), &mut in_out) - .unwrap(); - - assert_ne!(plaintext, in_out[..plaintext.len()]); - - rand_nonce_key - .open_in_place(nonce, Aad::empty(), &mut in_out) - .unwrap(); - - assert_eq!(plaintext, in_out[..plaintext.len()]); - - let mut in_out = Vec::from(plaintext.as_slice()); - - let (nonce, tag) = rand_nonce_key - .seal_in_place_separate_tag(Aad::empty(), &mut in_out) - .unwrap(); - - assert_ne!(plaintext, in_out[..plaintext.len()]); - - in_out.extend(tag.as_ref()); - - rand_nonce_key - .open_in_place(nonce, Aad::empty(), &mut in_out) - .unwrap(); - - assert_eq!(plaintext, in_out[..plaintext.len()]); - } - } - }; - } - - test_randnonce!(aes_128_gcm, &AES_128_GCM, TEST_128_BIT_KEY, &16, &12); - test_randnonce!(aes_256_gcm, &AES_256_GCM, TEST_256_BIT_KEY, &16, &12); - test_randnonce!(chacha20_poly1305, &CHACHA20_POLY1305, TEST_256_BIT_KEY); - - struct TlsNonceTestCase { - nonce: &'static str, - expect_err: bool, - } - - const TLS_NONCE_TEST_CASES: &[TlsNonceTestCase] = &[ - TlsNonceTestCase { - nonce: "9fab40177c900aad9fc28cc3", - expect_err: false, - }, - TlsNonceTestCase { - nonce: "9fab40177c900aad9fc28cc4", - expect_err: false, - }, - TlsNonceTestCase { - nonce: "9fab40177c900aad9fc28cc2", - expect_err: true, - }, - ]; - - macro_rules! test_tls_aead { - ($name:ident, $alg:expr, $proto:expr, $key:expr) => { - paste! { - #[test] - fn []() { - assert!(TlsRecordSealingKey::new($alg, $proto, $key).is_err()); - assert!(TlsRecordOpeningKey::new($alg, $proto, $key).is_err()); - } - } - }; - ($name:ident, $alg:expr, $proto:expr, $key:expr, $expect_tag_len:expr, $expect_nonce_len:expr) => { - paste! { - #[test] - fn []() { - let sealing_key = - TlsRecordSealingKey::new($alg, $proto, $key).unwrap(); - - let opening_key = - TlsRecordOpeningKey::new($alg, $proto, $key).unwrap(); - - for case in TLS_NONCE_TEST_CASES { - let plaintext = from_hex("00112233445566778899aabbccddeeff").unwrap(); - - assert_eq!($alg, sealing_key.algorithm()); - assert_eq!(*$expect_tag_len, $alg.tag_len()); - assert_eq!(*$expect_nonce_len, $alg.nonce_len()); - - let mut in_out = Vec::from(plaintext.as_slice()); - - let nonce = from_hex(case.nonce).unwrap(); - - let nonce_bytes = nonce.as_slice(); - - let result = sealing_key.seal_in_place_append_tag( - Nonce::try_assume_unique_for_key(nonce_bytes).unwrap(), - Aad::empty(), - &mut in_out, - ); - - match (result, case.expect_err) { - (Ok(()), true) => panic!("expected error for seal_in_place_append_tag"), - (Ok(()), false) => {} - (Err(_), true) => return, - (Err(e), false) => panic!("{e}"), - } - - assert_ne!(plaintext, in_out[..plaintext.len()]); - - opening_key - .open_in_place( - Nonce::try_assume_unique_for_key(nonce_bytes).unwrap(), - Aad::empty(), - &mut in_out, - ) - .unwrap(); - - assert_eq!(plaintext, in_out[..plaintext.len()]); - } - } - } - }; - } - - test_tls_aead!( - aes_128_gcm_tls12, - &AES_128_GCM, - TlsProtocolId::TLS12, - TEST_128_BIT_KEY, - &16, - &12 - ); - test_tls_aead!( - aes_128_gcm_tls13, - &AES_128_GCM, - TlsProtocolId::TLS13, - TEST_128_BIT_KEY, - &16, - &12 - ); - test_tls_aead!( - aes_256_gcm_tls12, - &AES_256_GCM, - TlsProtocolId::TLS12, - TEST_256_BIT_KEY, - &16, - &12 - ); - test_tls_aead!( - aes_256_gcm_tls13, - &AES_256_GCM, - TlsProtocolId::TLS13, - TEST_256_BIT_KEY, - &16, - &12 - ); - test_tls_aead!( - chacha20_poly1305_tls12, - &CHACHA20_POLY1305, - TlsProtocolId::TLS12, - TEST_256_BIT_KEY - ); - test_tls_aead!( - chacha20_poly1305_tls13, - &CHACHA20_POLY1305, - TlsProtocolId::TLS13, - TEST_256_BIT_KEY - ); } diff --git a/aws-lc-rs/src/aead/chacha20_poly1305_openssh.rs b/aws-lc-rs/src/aead/chacha20_poly1305_openssh.rs index c4969f46cd3..a39a4c949fa 100644 --- a/aws-lc-rs/src/aead/chacha20_poly1305_openssh.rs +++ b/aws-lc-rs/src/aead/chacha20_poly1305_openssh.rs @@ -51,9 +51,9 @@ impl SealingKey { /// `padding_length||payload||random padding`. It will be overwritten by /// `encrypted_packet_length||ciphertext`, where `encrypted_packet_length` /// is encrypted with `K_1` and `ciphertext` is encrypted by `K_2`. - /// - /// # FIPS - /// This method must not be used. + // + // # FIPS + // This method must not be used. #[inline] pub fn seal_in_place( &self, @@ -98,9 +98,9 @@ impl OpeningKey { /// /// Importantly, the result won't be authenticated until `open_in_place` is /// called. - /// - /// # FIPS - /// This method must not be used. + // + // # FIPS + // This method must not be used. #[inline] #[must_use] pub fn decrypt_packet_length( @@ -128,9 +128,9 @@ impl OpeningKey { /// /// # Errors /// `error::Unspecified` when ciphertext is invalid - /// - /// # FIPS - /// This method must not be used. + // + // # FIPS + // This method must not be used. #[inline] pub fn open_in_place<'a>( &self, diff --git a/aws-lc-rs/src/aead/rand_nonce.rs b/aws-lc-rs/src/aead/rand_nonce.rs new file mode 100644 index 00000000000..67f75357cef --- /dev/null +++ b/aws-lc-rs/src/aead/rand_nonce.rs @@ -0,0 +1,239 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +use crate::{error::Unspecified, iv::FixedLength}; +use std::fmt::Debug; + +use super::{ + aead_ctx::AeadCtx, open_within, seal_in_place_append_tag, seal_in_place_separate_tag, Aad, + Algorithm, AlgorithmID, Nonce, Tag, NONCE_LEN, +}; + +/// AEAD Cipher key using a randomized nonce. +/// +/// `RandomizedNonceKey` handles generation random nonce values. +/// +/// The following algorithms are supported: +/// * `AES_128_GCM` +/// * `AES_256_GCM` +/// +/// Prefer this type in place of `LessSafeKey`, `OpeningKey`, `SealingKey`. +pub struct RandomizedNonceKey { + ctx: AeadCtx, + algorithm: &'static Algorithm, +} + +impl RandomizedNonceKey { + /// New Random Nonce Sequence + /// # Errors + pub fn new(algorithm: &'static Algorithm, key_bytes: &[u8]) -> Result { + let ctx = match algorithm.id { + AlgorithmID::AES_128_GCM => AeadCtx::aes_128_gcm_randnonce( + key_bytes, + algorithm.tag_len(), + algorithm.nonce_len(), + ), + AlgorithmID::AES_256_GCM => AeadCtx::aes_256_gcm_randnonce( + key_bytes, + algorithm.tag_len(), + algorithm.nonce_len(), + ), + AlgorithmID::AES_128_GCM_SIV + | AlgorithmID::AES_256_GCM_SIV + | AlgorithmID::CHACHA20_POLY1305 => return Err(Unspecified), + }?; + Ok(Self { ctx, algorithm }) + } + + /// Authenticates and decrypts (“opens”) data in place. + // + // aad is the additional authenticated data (AAD), if any. + // + // On input, in_out must be the ciphertext followed by the tag. When open_in_place() returns Ok(plaintext), + // the input ciphertext has been overwritten by the plaintext; plaintext will refer to the plaintext without the tag. + /// + /// # Errors + /// `error::Unspecified` when ciphertext is invalid. + #[inline] + pub fn open_in_place<'in_out, A>( + &self, + nonce: Nonce, + aad: Aad, + in_out: &'in_out mut [u8], + ) -> Result<&'in_out mut [u8], Unspecified> + where + A: AsRef<[u8]>, + { + open_within(self.algorithm, &self.ctx, nonce, aad, in_out, 0..) + } + + /// Encrypts and signs (“seals”) data in place, appending the tag to the + /// resulting ciphertext. + /// + /// `key.seal_in_place_append_tag(aad, in_out)` is equivalent to: + /// + /// ```skip + /// key.seal_in_place_separate_tag(aad, in_out.as_mut()) + /// .map(|tag| in_out.extend(tag.as_ref())) + /// ``` + /// + /// The Nonce used for the operation is randomly generated, and returned to the caller. + /// + /// # Errors + /// `error::Unspecified` if encryption operation fails. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn seal_in_place_append_tag<'a, A, InOut>( + &self, + aad: Aad, + in_out: &'a mut InOut, + ) -> Result + where + A: AsRef<[u8]>, + InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, + { + seal_in_place_append_tag( + self.algorithm, + &self.ctx, + None, + Aad::from(aad.as_ref()), + in_out, + ) + } + + /// Encrypts and signs (“seals”) data in place. + /// + /// `aad` is the additional authenticated data (AAD), if any. This is + /// authenticated but not encrypted. The type `A` could be a byte slice + /// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec`, etc. + /// If there is no AAD then use `Aad::empty()`. + /// + /// The plaintext is given as the input value of `in_out`. `seal_in_place()` + /// will overwrite the plaintext with the ciphertext and return the tag. + /// For most protocols, the caller must append the tag to the ciphertext. + /// The tag will be `self.algorithm.tag_len()` bytes long. + /// + /// The Nonce used for the operation is randomly generated, and returned to the caller. + /// + /// # Errors + /// `error::Unspecified` if encryption operation fails. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn seal_in_place_separate_tag( + &self, + aad: Aad, + in_out: &mut [u8], + ) -> Result<(Nonce, Tag), Unspecified> + where + A: AsRef<[u8]>, + { + let nonce = if let AlgorithmID::CHACHA20_POLY1305 = self.algorithm.id { + Some(Nonce(FixedLength::::new()?)) + } else { + None + }; + seal_in_place_separate_tag( + self.algorithm, + &self.ctx, + nonce, + Aad::from(aad.as_ref()), + in_out, + ) + } + + /// The key's AEAD algorithm. + #[inline] + #[must_use] + pub fn algorithm(&self) -> &'static Algorithm { + self.algorithm + } +} + +#[allow(clippy::missing_fields_in_debug)] +impl Debug for RandomizedNonceKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RandomizedNonceKey") + .field("algorithm", &self.algorithm) + .finish() + } +} + +#[cfg(test)] +mod tests { + use super::{Aad, RandomizedNonceKey}; + use crate::{ + aead::{AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305}, + test::from_hex, + }; + use paste::paste; + + const TEST_128_BIT_KEY: &[u8] = &[ + 0xb0, 0x37, 0x9f, 0xf8, 0xfb, 0x8e, 0xa6, 0x31, 0xf4, 0x1c, 0xe6, 0x3e, 0xb5, 0xc5, 0x20, + 0x7c, + ]; + + const TEST_256_BIT_KEY: &[u8] = &[ + 0x56, 0xd8, 0x96, 0x68, 0xbd, 0x96, 0xeb, 0xff, 0x5e, 0xa2, 0x0b, 0x34, 0xf2, 0x79, 0x84, + 0x6e, 0x2b, 0x13, 0x01, 0x3d, 0xab, 0x1d, 0xa4, 0x07, 0x5a, 0x16, 0xd5, 0x0b, 0x53, 0xb0, + 0xcc, 0x88, + ]; + + macro_rules! test_randnonce { + ($name:ident, $alg:expr, $key:expr) => { + paste! { + #[test] + fn []() { + assert!(RandomizedNonceKey::new($alg, $key).is_err()); + } + } + }; + ($name:ident, $alg:expr, $key:expr, $expect_tag_len:expr, $expect_nonce_len:expr) => { + paste! { + #[test] + fn []() { + let plaintext = from_hex("00112233445566778899aabbccddeeff").unwrap(); + let rand_nonce_key = + RandomizedNonceKey::new($alg, $key).unwrap(); + + assert_eq!($alg, rand_nonce_key.algorithm()); + assert_eq!(*$expect_tag_len, $alg.tag_len()); + assert_eq!(*$expect_nonce_len, $alg.nonce_len()); + + let mut in_out = Vec::from(plaintext.as_slice()); + + let nonce = rand_nonce_key + .seal_in_place_append_tag(Aad::empty(), &mut in_out) + .unwrap(); + + assert_ne!(plaintext, in_out[..plaintext.len()]); + + rand_nonce_key + .open_in_place(nonce, Aad::empty(), &mut in_out) + .unwrap(); + + assert_eq!(plaintext, in_out[..plaintext.len()]); + + let mut in_out = Vec::from(plaintext.as_slice()); + + let (nonce, tag) = rand_nonce_key + .seal_in_place_separate_tag(Aad::empty(), &mut in_out) + .unwrap(); + + assert_ne!(plaintext, in_out[..plaintext.len()]); + + in_out.extend(tag.as_ref()); + + rand_nonce_key + .open_in_place(nonce, Aad::empty(), &mut in_out) + .unwrap(); + + assert_eq!(plaintext, in_out[..plaintext.len()]); + } + } + }; + } + + test_randnonce!(aes_128_gcm, &AES_128_GCM, TEST_128_BIT_KEY, &16, &12); + test_randnonce!(aes_256_gcm, &AES_256_GCM, TEST_256_BIT_KEY, &16, &12); + test_randnonce!(chacha20_poly1305, &CHACHA20_POLY1305, TEST_256_BIT_KEY); +} diff --git a/aws-lc-rs/src/aead/tests/fips.rs b/aws-lc-rs/src/aead/tests/fips.rs index 03545b0fb93..13b681fe634 100644 --- a/aws-lc-rs/src/aead/tests/fips.rs +++ b/aws-lc-rs/src/aead/tests/fips.rs @@ -191,7 +191,7 @@ macro_rules! tls_nonce_api { ($name:ident, $alg:expr, $proto:expr, $key:expr) => { #[test] fn $name() { - let key = TlsRecordSealingKey::new($alg, $proto, $key).unwrap(); + let mut key = TlsRecordSealingKey::new($alg, $proto, $key).unwrap(); let mut in_out = Vec::from(TEST_MESSAGE); diff --git a/aws-lc-rs/src/aead/tls.rs b/aws-lc-rs/src/aead/tls.rs new file mode 100644 index 00000000000..6002087adf1 --- /dev/null +++ b/aws-lc-rs/src/aead/tls.rs @@ -0,0 +1,441 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +use std::fmt::Debug; + +use crate::error::Unspecified; + +use super::{ + aead_ctx::{self, AeadCtx}, + open_within, seal_in_place_append_tag, seal_in_place_separate_tag, Aad, Algorithm, AlgorithmID, + Nonce, Tag, +}; + +/// The Transport Layer Security (TLS) protocol version. +#[allow(clippy::module_name_repetitions)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum TlsProtocolId { + /// TLS 1.2 (RFC 5246) + TLS12, + + /// TLS 1.3 (RFC 8446) + TLS13, +} + +/// AEAD Encryption key used for TLS protocol record encryption. +/// +/// This type encapsulates encryption operations for TLS AEAD algorithms. +/// It validates that the provides nonce values are monotonically increasing for each invocation. +/// +/// The following algorithms are supported: +/// * `AES_128_GCM` +/// * `AES_256_GCM` +/// +/// Prefer this type in place of `LessSafeKey`, `OpeningKey`, `SealingKey` for TLS protocol implementations. +#[allow(clippy::module_name_repetitions)] +pub struct TlsRecordSealingKey { + // The TLS specific construction for TLS ciphers in AWS-LC are not thread-safe! + // The choice here was either wrap the underlying EVP_AEAD_CTX in a Mutex as done here, + // or force this type to !Sync. Since this is an implementation detail of AWS-LC + // we have optex to manage this behavior internally. + ctx: AeadCtx, + algorithm: &'static Algorithm, + protocol: TlsProtocolId, +} + +impl TlsRecordSealingKey { + /// New TLS record sealing key. Only supports `AES_128_GCM` and `AES_256_GCM`. + /// + /// # Errors + /// * `Unspecified`: Returned if the length of `key_bytes` does not match the chosen algorithm, + /// or if an unsupported algorithm is provided. + pub fn new( + algorithm: &'static Algorithm, + protocol: TlsProtocolId, + key_bytes: &[u8], + ) -> Result { + let ctx = match (algorithm.id, protocol) { + (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_128_gcm_tls12( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Seal, + ), + (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_128_gcm_tls13( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Seal, + ), + (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_256_gcm_tls12( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Seal, + ), + (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_256_gcm_tls13( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Seal, + ), + ( + AlgorithmID::AES_128_GCM_SIV + | AlgorithmID::AES_256_GCM_SIV + | AlgorithmID::CHACHA20_POLY1305, + _, + ) => Err(Unspecified), + }?; + Ok(Self { + ctx, + algorithm, + protocol, + }) + } + + /// Accepts a `Nonce` and `Aad` construction that is unique for this key and + /// TLS record sealing operation for the configured TLS protocol version. + /// + /// `nonce` must be unique and incremented per each sealing operation, + /// otherwise an error is returned. + /// + /// # Errors + /// `error::Unspecified` if encryption operation fails. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn seal_in_place_append_tag( + &mut self, + nonce: Nonce, + aad: Aad, + in_out: &mut InOut, + ) -> Result<(), Unspecified> + where + A: AsRef<[u8]>, + InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, + { + seal_in_place_append_tag( + self.algorithm, + &self.ctx, + Some(nonce), + Aad::from(aad.as_ref()), + in_out, + ) + .map(|_| ()) + } + + /// Encrypts and signs (“seals”) data in place. + /// + /// `aad` is the additional authenticated data (AAD), if any. This is + /// authenticated but not encrypted. The type `A` could be a byte slice + /// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec`, etc. + /// If there is no AAD then use `Aad::empty()`. + /// + /// The plaintext is given as the input value of `in_out`. `seal_in_place()` + /// will overwrite the plaintext with the ciphertext and return the tag. + /// For most protocols, the caller must append the tag to the ciphertext. + /// The tag will be `self.algorithm.tag_len()` bytes long. + /// + /// The Nonce used for the operation is randomly generated, and returned to the caller. + /// + /// # Errors + /// `error::Unspecified` if encryption operation fails. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn seal_in_place_separate_tag( + &mut self, + nonce: Nonce, + aad: Aad, + in_out: &mut [u8], + ) -> Result + where + A: AsRef<[u8]>, + { + seal_in_place_separate_tag( + self.algorithm, + &self.ctx, + Some(nonce), + Aad::from(aad.as_ref()), + in_out, + ) + .map(|(_, tag)| tag) + } + + /// The key's AEAD algorithm. + #[inline] + #[must_use] + pub fn algorithm(&self) -> &'static Algorithm { + self.algorithm + } + + /// The key's associated `TlsProtocolId`. + #[must_use] + pub fn tls_protocol_id(&self) -> TlsProtocolId { + self.protocol + } +} + +#[allow(clippy::missing_fields_in_debug)] +impl Debug for TlsRecordSealingKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TlsRecordSealingKey") + .field("algorithm", &self.algorithm) + .field("protocol", &self.protocol) + .finish() + } +} + +/// AEAD Encryption key used for TLS protocol record encryption. +/// +/// This type encapsulates decryption operations for TLS AEAD algorithms. +/// +/// The following algorithms are supported: +/// * `AES_128_GCM` +/// * `AES_256_GCM` +/// +/// Prefer this type in place of `LessSafeKey`, `OpeningKey`, `SealingKey` for TLS protocol implementations. +#[allow(clippy::module_name_repetitions)] +pub struct TlsRecordOpeningKey { + // The TLS specific construction for TLS ciphers in AWS-LC are not thread-safe! + // The choice here was either wrap the underlying EVP_AEAD_CTX in a Mutex as done here, + // or force this type to !Sync. Since this is an implementation detail of AWS-LC + // we have optex to manage this behavior internally. + ctx: AeadCtx, + algorithm: &'static Algorithm, + protocol: TlsProtocolId, +} + +impl TlsRecordOpeningKey { + /// New TLS record opening key. Only supports `AES_128_GCM` and `AES_256_GCM` Algorithms. + /// + /// # Errors + /// * `Unspecified`: Returned if the length of `key_bytes` does not match the chosen algorithm, + /// or if an unsupported algorithm is provided. + pub fn new( + algorithm: &'static Algorithm, + protocol: TlsProtocolId, + key_bytes: &[u8], + ) -> Result { + let ctx = match (algorithm.id, protocol) { + (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_128_gcm_tls12( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Open, + ), + (AlgorithmID::AES_128_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_128_gcm_tls13( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Open, + ), + (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS12) => AeadCtx::aes_256_gcm_tls12( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Open, + ), + (AlgorithmID::AES_256_GCM, TlsProtocolId::TLS13) => AeadCtx::aes_256_gcm_tls13( + key_bytes, + algorithm.tag_len(), + aead_ctx::AeadDirection::Open, + ), + ( + AlgorithmID::AES_128_GCM_SIV + | AlgorithmID::AES_256_GCM_SIV + | AlgorithmID::CHACHA20_POLY1305, + _, + ) => Err(Unspecified), + }?; + Ok(Self { + ctx, + algorithm, + protocol, + }) + } + + /// Accepts a Noce and Aad construction that is unique for this TLS record + /// opening operation. + /// + /// `nonce` must be unique for every use of the key to open data. + /// + /// # Errors + /// `error::Unspecified` when ciphertext is invalid. + #[inline] + pub fn open_in_place<'in_out, A>( + &self, + nonce: Nonce, + aad: Aad, + in_out: &'in_out mut [u8], + ) -> Result<&'in_out mut [u8], Unspecified> + where + A: AsRef<[u8]>, + { + open_within(self.algorithm, &self.ctx, nonce, aad, in_out, 0..) + } + + /// The key's AEAD algorithm. + #[inline] + #[must_use] + pub fn algorithm(&self) -> &'static Algorithm { + self.algorithm + } + + /// The key's associated `TlsProtocolId`. + #[must_use] + pub fn tls_protocol_id(&self) -> TlsProtocolId { + self.protocol + } +} + +#[allow(clippy::missing_fields_in_debug)] +impl Debug for TlsRecordOpeningKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TlsRecordOpeningKey") + .field("algorithm", &self.algorithm) + .field("protocol", &self.protocol) + .finish() + } +} + +#[cfg(test)] +mod tests { + use super::{TlsProtocolId, TlsRecordOpeningKey, TlsRecordSealingKey}; + use crate::{ + aead::Aad, + aead::{Nonce, AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305}, + test::from_hex, + }; + use paste::paste; + + const TEST_128_BIT_KEY: &[u8] = &[ + 0xb0, 0x37, 0x9f, 0xf8, 0xfb, 0x8e, 0xa6, 0x31, 0xf4, 0x1c, 0xe6, 0x3e, 0xb5, 0xc5, 0x20, + 0x7c, + ]; + + const TEST_256_BIT_KEY: &[u8] = &[ + 0x56, 0xd8, 0x96, 0x68, 0xbd, 0x96, 0xeb, 0xff, 0x5e, 0xa2, 0x0b, 0x34, 0xf2, 0x79, 0x84, + 0x6e, 0x2b, 0x13, 0x01, 0x3d, 0xab, 0x1d, 0xa4, 0x07, 0x5a, 0x16, 0xd5, 0x0b, 0x53, 0xb0, + 0xcc, 0x88, + ]; + + struct TlsNonceTestCase { + nonce: &'static str, + expect_err: bool, + } + + const TLS_NONCE_TEST_CASES: &[TlsNonceTestCase] = &[ + TlsNonceTestCase { + nonce: "9fab40177c900aad9fc28cc3", + expect_err: false, + }, + TlsNonceTestCase { + nonce: "9fab40177c900aad9fc28cc4", + expect_err: false, + }, + TlsNonceTestCase { + nonce: "9fab40177c900aad9fc28cc2", + expect_err: true, + }, + ]; + + macro_rules! test_tls_aead { + ($name:ident, $alg:expr, $proto:expr, $key:expr) => { + paste! { + #[test] + fn []() { + assert!(TlsRecordSealingKey::new($alg, $proto, $key).is_err()); + assert!(TlsRecordOpeningKey::new($alg, $proto, $key).is_err()); + } + } + }; + ($name:ident, $alg:expr, $proto:expr, $key:expr, $expect_tag_len:expr, $expect_nonce_len:expr) => { + paste! { + #[test] + fn []() { + let mut sealing_key = + TlsRecordSealingKey::new($alg, $proto, $key).unwrap(); + + let opening_key = + TlsRecordOpeningKey::new($alg, $proto, $key).unwrap(); + + for case in TLS_NONCE_TEST_CASES { + let plaintext = from_hex("00112233445566778899aabbccddeeff").unwrap(); + + assert_eq!($alg, sealing_key.algorithm()); + assert_eq!(*$expect_tag_len, $alg.tag_len()); + assert_eq!(*$expect_nonce_len, $alg.nonce_len()); + + let mut in_out = Vec::from(plaintext.as_slice()); + + let nonce = from_hex(case.nonce).unwrap(); + + let nonce_bytes = nonce.as_slice(); + + let result = sealing_key.seal_in_place_append_tag( + Nonce::try_assume_unique_for_key(nonce_bytes).unwrap(), + Aad::empty(), + &mut in_out, + ); + + match (result, case.expect_err) { + (Ok(()), true) => panic!("expected error for seal_in_place_append_tag"), + (Ok(()), false) => {} + (Err(_), true) => return, + (Err(e), false) => panic!("{e}"), + } + + assert_ne!(plaintext, in_out[..plaintext.len()]); + + opening_key + .open_in_place( + Nonce::try_assume_unique_for_key(nonce_bytes).unwrap(), + Aad::empty(), + &mut in_out, + ) + .unwrap(); + + assert_eq!(plaintext, in_out[..plaintext.len()]); + } + } + } + }; + } + + test_tls_aead!( + aes_128_gcm_tls12, + &AES_128_GCM, + TlsProtocolId::TLS12, + TEST_128_BIT_KEY, + &16, + &12 + ); + test_tls_aead!( + aes_128_gcm_tls13, + &AES_128_GCM, + TlsProtocolId::TLS13, + TEST_128_BIT_KEY, + &16, + &12 + ); + test_tls_aead!( + aes_256_gcm_tls12, + &AES_256_GCM, + TlsProtocolId::TLS12, + TEST_256_BIT_KEY, + &16, + &12 + ); + test_tls_aead!( + aes_256_gcm_tls13, + &AES_256_GCM, + TlsProtocolId::TLS13, + TEST_256_BIT_KEY, + &16, + &12 + ); + test_tls_aead!( + chacha20_poly1305_tls12, + &CHACHA20_POLY1305, + TlsProtocolId::TLS12, + TEST_256_BIT_KEY + ); + test_tls_aead!( + chacha20_poly1305_tls13, + &CHACHA20_POLY1305, + TlsProtocolId::TLS13, + TEST_256_BIT_KEY + ); +} diff --git a/aws-lc-rs/src/agreement.rs b/aws-lc-rs/src/agreement.rs index c23b66388b1..88308e127ec 100644 --- a/aws-lc-rs/src/agreement.rs +++ b/aws-lc-rs/src/agreement.rs @@ -210,12 +210,12 @@ impl EphemeralPrivateKey { /// # *ring* Compatibility /// Our implementation ignores the `SecureRandom` parameter. /// - /// # FIPS - /// Use this function with one of the following algorithms: - /// * `ECDH_P256` - /// * `ECDH_P384` - /// * `ECDH_P521` - /// + // # FIPS + // Use this function with one of the following algorithms: + // * `ECDH_P256` + // * `ECDH_P384` + // * `ECDH_P521` + // /// # Errors /// `error::Unspecified` when operation fails due to internal error. pub fn generate(alg: &'static Algorithm, _rng: &dyn SecureRandom) -> Result { @@ -502,12 +502,12 @@ impl> UnparsedPublicKey { /// key material from the key agreement operation and then returns what `kdf` /// returns. /// -/// # FIPS -/// Use this function with one of the following key algorithms: -/// * `ECDH_P256` -/// * `ECDH_P384` -/// * `ECDH_P521` -/// +// # FIPS +// Use this function with one of the following key algorithms: +// * `ECDH_P256` +// * `ECDH_P384` +// * `ECDH_P521` +// /// # Errors /// `error_value` on internal failure. #[inline] diff --git a/aws-lc-rs/src/cipher.rs b/aws-lc-rs/src/cipher.rs index 1bcf8735fb3..a3d445cb1a4 100644 --- a/aws-lc-rs/src/cipher.rs +++ b/aws-lc-rs/src/cipher.rs @@ -419,11 +419,11 @@ impl PaddedBlockEncryptingKey { /// Constructs a new `PaddedBlockEncryptingKey` cipher with chaining block cipher (CBC) mode. /// Plaintext data is padded following the PKCS#7 scheme. /// - /// # FIPS - /// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: - /// * `AES_128` - /// * `AES_256` - /// + // # FIPS + // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: + // * `AES_128` + // * `AES_256` + // /// # Errors /// * [`Unspecified`]: Returned if there is an error cosntructing a `PaddedBlockEncryptingKey`. pub fn cbc_pkcs7(key: UnboundCipherKey) -> Result { @@ -512,11 +512,11 @@ impl PaddedBlockDecryptingKey { /// Constructs a new `PaddedBlockDecryptingKey` cipher with chaining block cipher (CBC) mode. /// Decrypted data is unpadded following the PKCS#7 scheme. /// - /// # FIPS - /// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: - /// * `AES_128` - /// * `AES_256` - /// + // # FIPS + // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: + // * `AES_128` + // * `AES_256` + // /// # Errors /// * [`Unspecified`]: Returned if there is an error constructing the `PaddedBlockDecryptingKey`. pub fn cbc_pkcs7(key: UnboundCipherKey) -> Result { @@ -589,11 +589,11 @@ pub struct EncryptingKey { impl EncryptingKey { /// Constructs an `EncryptingKey` operating in counter (CTR) mode using the provided key. /// - /// # FIPS - /// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: - /// * `AES_128` - /// * `AES_256` - /// + // # FIPS + // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: + // * `AES_128` + // * `AES_256` + // /// # Errors /// * [`Unspecified`]: Returned if there is an error constructing the `EncryptingKey`. pub fn ctr(key: UnboundCipherKey) -> Result { @@ -668,11 +668,11 @@ pub struct DecryptingKey { impl DecryptingKey { /// Constructs a cipher decrypting key operating in counter (CTR) mode using the provided key and context. /// - /// # FIPS - /// Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: - /// * `AES_128` - /// * `AES_256` - /// + // # FIPS + // Use this function with an `UnboundCipherKey` constructed with one of the following algorithms: + // * `AES_128` + // * `AES_256` + // /// # Errors /// * [`Unspecified`]: Returned if there is an error during decryption. pub fn ctr(key: UnboundCipherKey) -> Result { diff --git a/aws-lc-rs/src/digest.rs b/aws-lc-rs/src/digest.rs index 8c716ae05fb..901487b67c2 100644 --- a/aws-lc-rs/src/digest.rs +++ b/aws-lc-rs/src/digest.rs @@ -49,15 +49,15 @@ use std::mem::MaybeUninit; use std::os::raw::c_uint; /// A context for multi-step (Init-Update-Finish) digest calculations. -/// -/// # FIPS -/// Context must be used with one of the following algorithms: -/// * `SHA1_FOR_LEGACY_USE_ONLY` -/// * `SHA224` -/// * `SHA256` -/// * `SHA384` -/// * `SHA512` -/// * `SHA512_256` +// +// # FIPS +// Context must be used with one of the following algorithms: +// * `SHA1_FOR_LEGACY_USE_ONLY` +// * `SHA224` +// * `SHA256` +// * `SHA384` +// * `SHA512` +// * `SHA512_256` #[derive(Clone)] pub struct Context { /// The context's algorithm. @@ -168,15 +168,15 @@ impl Context { /// Returns the digest of `data` using the given digest algorithm. /// -/// # FIPS -/// This function must only be used with one of the following algorithms: -/// * `SHA1_FOR_LEGACY_USE_ONLY` -/// * `SHA224` -/// * `SHA256` -/// * `SHA384` -/// * `SHA512` -/// * `SHA512_256` -/// +// # FIPS +// This function must only be used with one of the following algorithms: +// * `SHA1_FOR_LEGACY_USE_ONLY` +// * `SHA224` +// * `SHA256` +// * `SHA384` +// * `SHA512` +// * `SHA512_256` +// /// # Examples: /// /// ``` diff --git a/aws-lc-rs/src/ec/key_pair.rs b/aws-lc-rs/src/ec/key_pair.rs index 15fc5d69b29..05f37f0ad11 100644 --- a/aws-lc-rs/src/ec/key_pair.rs +++ b/aws-lc-rs/src/ec/key_pair.rs @@ -146,11 +146,11 @@ impl EcdsaKeyPair { /// /// # Errors /// `error::Unspecified` on internal error. - /// - /// # FIPS - /// The following conditions must be met: - /// * NIST Elliptic Curves: P256, P384, P521 - /// * Digest Algorithms: SHA256, SHA384, SHA512 + // + // # FIPS + // The following conditions must be met: + // * NIST Elliptic Curves: P256, P384, P521 + // * Digest Algorithms: SHA256, SHA384, SHA512 #[inline] pub fn sign(&self, _rng: &dyn SecureRandom, message: &[u8]) -> Result { let mut md_ctx = DigestContext::new_uninit(); diff --git a/aws-lc-rs/src/ed25519.rs b/aws-lc-rs/src/ed25519.rs index 680bdbbb3b6..e58049ac381 100644 --- a/aws-lc-rs/src/ed25519.rs +++ b/aws-lc-rs/src/ed25519.rs @@ -153,9 +153,9 @@ impl Ed25519KeyPair { /// /// Our implementation ignores the `SecureRandom` parameter. /// - /// # FIPS - /// This function must not be used. - /// + // # FIPS + // This function must not be used. + // /// # Errors /// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error. pub fn generate_pkcs8(_rng: &dyn SecureRandom) -> Result { @@ -172,9 +172,9 @@ impl Ed25519KeyPair { /// # *ring* Compatibility /// Our implementation ignores the `SecureRandom` parameter. /// - /// # FIPS - /// This function must not be used. - /// + // # FIPS + // This function must not be used. + // /// # Errors /// `error::Unspecified` if `rng` cannot provide enough bits or if there's an internal error. pub fn generate_pkcs8v1(_rng: &dyn SecureRandom) -> Result { @@ -292,9 +292,9 @@ impl Ed25519KeyPair { /// Returns the signature of the message msg. /// - /// # FIPS - /// This method must not be used. - /// + // # FIPS + // This method must not be used. + // /// # Panics /// Panics if the message is unable to be signed #[inline] diff --git a/aws-lc-rs/src/hkdf.rs b/aws-lc-rs/src/hkdf.rs index c72273b72f7..c12a80820ef 100644 --- a/aws-lc-rs/src/hkdf.rs +++ b/aws-lc-rs/src/hkdf.rs @@ -119,15 +119,15 @@ impl Salt { /// Constructing a `Salt` is relatively expensive so it is good to reuse a /// `Salt` object instead of re-constructing `Salt`s with the same value. /// - /// # FIPS - /// The following conditions must be met: - /// * Algorithm is one of the following: - /// * `HKDF_SHA1_FOR_LEGACY_USE_ONLY` - /// * `HKDF_SHA256` - /// * `HKDF_SHA384` - /// * `HKDF_SHA512` - /// * `value.len() > 0` is true - /// + // # FIPS + // The following conditions must be met: + // * Algorithm is one of the following: + // * `HKDF_SHA1_FOR_LEGACY_USE_ONLY` + // * `HKDF_SHA256` + // * `HKDF_SHA384` + // * `HKDF_SHA512` + // * `value.len() > 0` is true + // /// # Panics /// `new` panics if the salt length exceeds the limit #[must_use] @@ -313,11 +313,11 @@ impl Prk { /// intentionally wants to leak the PRK secret, e.g. to implement /// `SSLKEYLOGFILE` functionality. /// - /// # FIPS - /// This function must not be used. - /// - /// See [`Salt::extract`]. - /// + // # FIPS + // This function must not be used. + // + // See [`Salt::extract`]. + // /// # Panics /// Panics if the given Prk length exceeds the limit #[must_use] @@ -345,11 +345,11 @@ impl Prk { /// # Errors /// `error::Unspecified` if (and only if) `len` is too large. /// - /// # FIPS - /// The following conditions must be met: - /// * `Prk` must be constructed using `Salt::extract` prior to calling - /// this method. - /// * After concatination of the `info` slices the resulting `[u8].len() > 0` is true. + // # FIPS + // The following conditions must be met: + // * `Prk` must be constructed using `Salt::extract` prior to calling + // this method. + // * After concatination of the `info` slices the resulting `[u8].len() > 0` is true. #[inline] pub fn expand<'a, L: KeyType>( &'a self, @@ -426,17 +426,17 @@ impl Okm<'_, L> { /// Fills `out` with the output of the HKDF-Expand operation for the given /// inputs. /// - /// # FIPS - /// The following conditions must be met: - /// * Algorithm is one of the following: - /// * `HKDF_SHA1_FOR_LEGACY_USE_ONLY` - /// * `HKDF_SHA256` - /// * `HKDF_SHA384` - /// * `HKDF_SHA512` - /// * The [`Okm`] was constructed from a [`Prk`] created with [`Salt::extract`] and: - /// * The `value.len()` passed to [`Salt::new`] was non-zero. - /// * The `info_len` from [`Prk::expand`] was non-zero. - /// + // # FIPS + // The following conditions must be met: + // * Algorithm is one of the following: + // * `HKDF_SHA1_FOR_LEGACY_USE_ONLY` + // * `HKDF_SHA256` + // * `HKDF_SHA384` + // * `HKDF_SHA512` + // * The [`Okm`] was constructed from a [`Prk`] created with [`Salt::extract`] and: + // * The `value.len()` passed to [`Salt::new`] was non-zero. + // * The `info_len` from [`Prk::expand`] was non-zero. + // /// # Errors /// `error::Unspecified` if the requested output length differs from the length specified by /// `L: KeyType`. diff --git a/aws-lc-rs/src/hmac.rs b/aws-lc-rs/src/hmac.rs index 6eb213551ea..ea937ec97e8 100644 --- a/aws-lc-rs/src/hmac.rs +++ b/aws-lc-rs/src/hmac.rs @@ -200,14 +200,14 @@ impl Clone for LcHmacCtx { } /// A key to use for HMAC signing. -/// -/// # FIPS -/// Use this type with one of the following algorithms: -/// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` -/// * `HMAC_SHA224` -/// * `HMAC_SHA256` -/// * `HMAC_SHA384` -/// * `HMAC_SHA512` +// +// # FIPS +// Use this type with one of the following algorithms: +// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` +// * `HMAC_SHA224` +// * `HMAC_SHA256` +// * `HMAC_SHA384` +// * `HMAC_SHA512` #[derive(Clone)] pub struct Key { pub(crate) algorithm: Algorithm, @@ -236,16 +236,17 @@ impl Key { /// /// [RFC 2104 Section 3]: https://tools.ietf.org/html/rfc2104#section-3 /// + // + // # FIPS + // Use this function with one of the following algorithms: + // * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` + // * `HMAC_SHA224` + // * `HMAC_SHA256` + // * `HMAC_SHA384` + // * `HMAC_SHA512` + // /// # Errors /// `error::Unspecified` is the `rng` fails. - /// - /// # FIPS - /// Use this function with one of the following algorithms: - /// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` - /// * `HMAC_SHA224` - /// * `HMAC_SHA256` - /// * `HMAC_SHA384` - /// * `HMAC_SHA512` pub fn generate( algorithm: Algorithm, rng: &dyn crate::rand::SecureRandom, @@ -401,14 +402,14 @@ impl Context { /// the return value of `sign` to a tag. Use `verify` for verification /// instead. /// - /// # FIPS - /// Use this method with one of the following algorithms: - /// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` - /// * `HMAC_SHA224` - /// * `HMAC_SHA256` - /// * `HMAC_SHA384` - /// * `HMAC_SHA512` - /// + // # FIPS + // Use this method with one of the following algorithms: + // * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` + // * `HMAC_SHA224` + // * `HMAC_SHA256` + // * `HMAC_SHA384` + // * `HMAC_SHA512` + // /// # Panics /// Panics if the HMAC calculation cannot be finalized #[inline] @@ -442,14 +443,14 @@ impl Context { /// /// It is generally not safe to implement HMAC verification by comparing the /// return value of `sign` to a tag. Use `verify` for verification instead. -/// -/// # FIPS -/// Use this function with one of the following algorithms: -/// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` -/// * `HMAC_SHA224` -/// * `HMAC_SHA256` -/// * `HMAC_SHA384` -/// * `HMAC_SHA512` +// +// # FIPS +// Use this function with one of the following algorithms: +// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` +// * `HMAC_SHA224` +// * `HMAC_SHA256` +// * `HMAC_SHA384` +// * `HMAC_SHA512` #[inline] #[must_use] pub fn sign(key: &Key, data: &[u8]) -> Tag { @@ -468,14 +469,14 @@ pub fn sign(key: &Key, data: &[u8]) -> Tag { /// /// # Errors /// `error::Unspecified` if the inputs are not verified. -/// -/// # FIPS -/// Use this function with one of the following algorithms: -/// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` -/// * `HMAC_SHA224` -/// * `HMAC_SHA256` -/// * `HMAC_SHA384` -/// * `HMAC_SHA512` +// +// # FIPS +// Use this function with one of the following algorithms: +// * `HMAC_SHA1_FOR_LEGACY_USE_ONLY` +// * `HMAC_SHA224` +// * `HMAC_SHA256` +// * `HMAC_SHA384` +// * `HMAC_SHA512` #[inline] pub fn verify(key: &Key, data: &[u8], tag: &[u8]) -> Result<(), Unspecified> { constant_time::verify_slices_are_equal(sign(key, data).as_ref(), tag) diff --git a/aws-lc-rs/src/pbkdf2.rs b/aws-lc-rs/src/pbkdf2.rs index 599d369a1f2..cba6c4bc156 100644 --- a/aws-lc-rs/src/pbkdf2.rs +++ b/aws-lc-rs/src/pbkdf2.rs @@ -166,17 +166,17 @@ const MAX_USIZE32: u64 = u32::MAX as u64; /// /// `derive` panics if `out.len()` is larger than (2**32 - 1) * the digest /// algorithm's output length, per the PBKDF2 specification. -/// -/// # FIPS -/// The following conditions must be met: -/// * Algorithm is one of the following: -/// * `PBKDF2_HMAC_SHA1` -/// * `PBKDF2_HMAC_SHA256` -/// * `PBKDF2_HMAC_SHA384` -/// * `PBKDF2_HMAC_SHA512` -/// * `salt.len()` >= 16 -/// * `sercet.len()` >= 14 -/// * `iterations` >= 1000 +// +// # FIPS +// The following conditions must be met: +// * Algorithm is one of the following: +// * `PBKDF2_HMAC_SHA1` +// * `PBKDF2_HMAC_SHA256` +// * `PBKDF2_HMAC_SHA384` +// * `PBKDF2_HMAC_SHA512` +// * `salt.len()` >= 16 +// * `sercet.len()` >= 14 +// * `iterations` >= 1000 #[inline] pub fn derive( algorithm: Algorithm, @@ -241,17 +241,17 @@ fn try_derive( /// /// `verify` panics if `previously_derived.len()` is larger than (2**32 - 1) * the digest /// algorithm's output length, per the PBKDF2 specification. -/// -/// # FIPS -/// The following conditions must be met: -/// * Algorithm is one of the following: -/// * `PBKDF2_HMAC_SHA1` -/// * `PBKDF2_HMAC_SHA256` -/// * `PBKDF2_HMAC_SHA384` -/// * `PBKDF2_HMAC_SHA512` -/// * `salt.len()` >= 16 -/// * `secret.len()` >= 14 -/// * `iterations` >= 1000 +// +// # FIPS +// The following conditions must be met: +// * Algorithm is one of the following: +// * `PBKDF2_HMAC_SHA1` +// * `PBKDF2_HMAC_SHA256` +// * `PBKDF2_HMAC_SHA384` +// * `PBKDF2_HMAC_SHA512` +// * `salt.len()` >= 16 +// * `secret.len()` >= 14 +// * `iterations` >= 1000 #[inline] pub fn verify( algorithm: Algorithm, diff --git a/aws-lc-rs/src/rand.rs b/aws-lc-rs/src/rand.rs index 8a93ca5dfe6..ecda7d0767c 100644 --- a/aws-lc-rs/src/rand.rs +++ b/aws-lc-rs/src/rand.rs @@ -121,9 +121,9 @@ impl RandomlyConstructable for T where T: sealed::RandomlyConstructable {} /// underlying *AWS-LC* libcrypto. /// /// A single `SystemRandom` may be shared across multiple threads safely. -/// -/// # FIPS -/// Use this implementation for retrieving random bytes. +// +// # FIPS +// Use this implementation for retrieving random bytes. #[derive(Clone, Debug)] pub struct SystemRandom(()); @@ -153,9 +153,9 @@ impl sealed::SecureRandom for SystemRandom { /// Fills `dest` with random bytes. /// -/// # FIPS -/// Use this for retrieving random bytes or [`SystemRandom`]. -/// +// # FIPS +// Use this for retrieving random bytes or [`SystemRandom`]. +// /// # Errors /// `error::Unspecified` if unable to fill `dest`. pub fn fill(dest: &mut [u8]) -> Result<(), error::Unspecified> { diff --git a/aws-lc-rs/src/rsa.rs b/aws-lc-rs/src/rsa.rs index be6c0138ec1..01acfbd1a5a 100644 --- a/aws-lc-rs/src/rsa.rs +++ b/aws-lc-rs/src/rsa.rs @@ -227,11 +227,11 @@ impl RsaKeyPair { /// # *ring* Compatibility /// Our implementation ignores the `SecureRandom` parameter. /// - /// # FIPS - /// The following conditions must be met: - /// * RSA Key Sizes: 2048, 3072, 4096 - /// * Digest Algorithms: SHA256, SHA384, SHA512 - /// + // # FIPS + // The following conditions must be met: + // * RSA Key Sizes: 2048, 3072, 4096 + // * Digest Algorithms: SHA256, SHA384, SHA512 + // /// # Errors /// `error::Unspecified` on error. /// With "fips" feature enabled, errors if digest length is greater than `u32::MAX`. diff --git a/aws-lc-rs/src/signature.rs b/aws-lc-rs/src/signature.rs index bfefd420a87..0276789ed3b 100644 --- a/aws-lc-rs/src/signature.rs +++ b/aws-lc-rs/src/signature.rs @@ -305,12 +305,12 @@ pub trait VerificationAlgorithm: Debug + Sync + sealed::Sealed { /// Verify the signature `signature` of message `msg` with the public key /// `public_key`. /// - /// # FIPS - /// The following conditions must be met: - /// * RSA Key Sizes: 1024, 2048, 3072, 4096 - /// * NIST Elliptic Curves: P256, P384, P521 - /// * Digest Algorithms: SHA1, SHA256, SHA384, SHA512 - /// + // # FIPS + // The following conditions must be met: + // * RSA Key Sizes: 1024, 2048, 3072, 4096 + // * NIST Elliptic Curves: P256, P384, P521 + // * Digest Algorithms: SHA1, SHA256, SHA384, SHA512 + // /// # Errors /// `error::Unspecified` if inputs not verified. #[cfg(feature = "ring-sig-verify")] @@ -325,12 +325,12 @@ pub trait VerificationAlgorithm: Debug + Sync + sealed::Sealed { /// Verify the signature `signature` of message `msg` with the public key /// `public_key`. /// - /// # FIPS - /// The following conditions must be met: - /// * RSA Key Sizes: 1024, 2048, 3072, 4096 - /// * NIST Elliptic Curves: P256, P384, P521 - /// * Digest Algorithms: SHA1, SHA256, SHA384, SHA512 - /// + // # FIPS + // The following conditions must be met: + // * RSA Key Sizes: 1024, 2048, 3072, 4096 + // * NIST Elliptic Curves: P256, P384, P521 + // * Digest Algorithms: SHA1, SHA256, SHA384, SHA512 + // /// # Errors /// `error::Unspecified` if inputs not verified. fn verify_sig( @@ -374,12 +374,12 @@ impl> UnparsedPublicKey { /// /// See the [`crate::signature`] module-level documentation for examples. /// - /// # FIPS - /// The following conditions must be met: - /// * RSA Key Sizes: 1024, 2048, 3072, 4096 - /// * NIST Elliptic Curves: P256, P384, P521 - /// * Digest Algorithms: SHA1, SHA256, SHA384, SHA512 - /// + // # FIPS + // The following conditions must be met: + // * RSA Key Sizes: 1024, 2048, 3072, 4096 + // * NIST Elliptic Curves: P256, P384, P521 + // * Digest Algorithms: SHA1, SHA256, SHA384, SHA512 + // /// # Errors /// `error::Unspecified` if inputs not verified. #[inline] diff --git a/aws-lc-rs/src/tls_prf.rs b/aws-lc-rs/src/tls_prf.rs index 9f216d5e998..7c47e55777d 100644 --- a/aws-lc-rs/src/tls_prf.rs +++ b/aws-lc-rs/src/tls_prf.rs @@ -25,6 +25,8 @@ //! # } //! ``` +use std::fmt::Debug; + use crate::{ digest::match_digest_type, digest::AlgorithmID, error::Unspecified, fips::indicator_check, }; @@ -35,6 +37,12 @@ use aws_lc::CRYPTO_tls1_prf; /// The TLS PRF `P_hash` Algorithm pub struct Algorithm(AlgorithmID); +impl Debug for Algorithm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Debug::fmt(&self.0, f) + } +} + /// SHA-256 `P_hash` algorithm pub const P_SHA256: Algorithm = Algorithm(AlgorithmID::SHA256); @@ -121,6 +129,15 @@ impl TryFrom for [u8; L] { } } +#[allow(clippy::missing_fields_in_debug)] +impl Debug for Secret { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Secret") + .field("algorithm", &self.algorithm) + .finish() + } +} + fn prf( algorithm: &'static Algorithm, secret: &[u8],