From 50d17631902b77b7c3626a4aa213beee00aeae61 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Mon, 2 Dec 2024 23:24:16 +0000 Subject: [PATCH 1/5] Add ability access next operation nonce from OpeningKey and SealingKey --- aws-lc-rs/src/aead.rs | 159 ++++++++++++++++++++++++++++++++++- aws-lc-rs/tests/aead_test.rs | 92 +++++++++++++++++++- 2 files changed, 249 insertions(+), 2 deletions(-) diff --git a/aws-lc-rs/src/aead.rs b/aws-lc-rs/src/aead.rs index 1667b5d4bc2..55b59c7f457 100644 --- a/aws-lc-rs/src/aead.rs +++ b/aws-lc-rs/src/aead.rs @@ -55,7 +55,7 @@ //! # Nonce Sequence APIs //! //! The [`UnboundKey`], [`OpeningKey`], [`SealingKey`], and [`LessSafeKey`] types are the -//! AEAD API's provided for compatability with the original *ring* API. +//! AEAD API's provided for compatibility with the original *ring* API. //! //! Users should prefer [`RandomizedNonceKey`] which provides a simplified experience around //! Nonce construction. @@ -117,6 +117,7 @@ use crate::{derive_debug_via_id, error::Unspecified, hkdf}; use aead_ctx::AeadCtx; use core::{fmt::Debug, ops::RangeFrom}; +use paste::paste; mod aead_ctx; mod aes_gcm; @@ -307,6 +308,13 @@ impl OpeningKey { ciphertext_and_tag, ) } + + /// Returns a `OpeningKeyOpMut` with the next computed `Nonce` from the `NonceSequence` for the next operation. + /// # Errors + /// `Unspecified` if there is a failure computing the nonce for the next operation. + pub fn prepare_operation(&mut self) -> Result, Unspecified> { + OpeningKeyOpMut::new(self) + } } /// An AEAD key for encrypting and signing ("sealing"), bound to a nonce @@ -433,6 +441,149 @@ impl SealingKey { .seal_in_place_separate_tag(Some(self.nonce_sequence.advance()?), aad.as_ref(), in_out) .map(|(_, tag)| tag) } + + /// Returns a `SealingKeyOpMut` with the next computed `Nonce` from the `NonceSequence` for the next operation. + /// # Errors + /// `Unspecified` if there is a failure computing the nonce for the next operation. + pub fn prepare_operation(&mut self) -> Result, Unspecified> { + SealingKeyOpMut::new(self) + } +} + +macro_rules! nonce_sequence_key_iterator { + ($name:ident) => { + paste! { + /// A key operation with a precomputed nonce from a key's associated `NonceSequence`. + pub struct [<$name OpMut>]<'a, N: NonceSequence> { + key: &'a mut $name, + nonce: Nonce, + } + + impl<'a, N: NonceSequence> [<$name OpMut>]<'a, N> { + fn new(key: &'a mut $name) -> Result { + let nonce = key.nonce_sequence.advance()?; + Ok(Self { + key, + nonce, + }) + } + } + + impl<'a, N: NonceSequence> Debug for [<$name OpMut>]<'a, N> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { + f.debug_struct("[<$name OpMut>]").finish_non_exhaustive() + } + } + } + }; +} + +nonce_sequence_key_iterator!(OpeningKey); +nonce_sequence_key_iterator!(SealingKey); + +impl OpeningKeyOpMut<'_, N> { + /// Returns the Nonce that will be used for this operation. + #[must_use] + pub fn nonce(&self) -> Nonce { + let nonce_bytes = self.nonce.0.as_ref(); + let nonce: Nonce = Nonce(nonce_bytes.into()); + nonce + } + + /// Authenticates and decrypts (“opens”) data in place. + /// + /// See [OpeningKey::open_in_place] for additional API information. + /// + /// # Errors + /// `error::Unspecified` when ciphertext is invalid. In this case, `in_out` may have been + /// overwritten in an unspecified way. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn open_in_place(self, aad: Aad, in_out: &mut [u8]) -> Result<&mut [u8], Unspecified> + where + A: AsRef<[u8]>, + { + self.open_within(aad, in_out, 0..) + } + + /// Authenticates and decrypts (“opens”) data in place, with a shift. + /// + /// See [OpeningKey::open_within] for additional API information. + /// + /// # Errors + /// `error::Unspecified` when ciphertext is invalid. In this case, `in_out` may have been + /// overwritten in an unspecified way. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn open_within( + self, + aad: Aad, + in_out: &mut [u8], + ciphertext_and_tag: RangeFrom, + ) -> Result<&mut [u8], Unspecified> + where + A: AsRef<[u8]>, + { + self.key + .key + .open_within(self.nonce, aad.as_ref(), in_out, ciphertext_and_tag) + } +} + +impl SealingKeyOpMut<'_, N> { + /// Returns the Nonce that will be used for this operation. + #[must_use] + pub fn nonce(&self) -> Nonce { + let nonce_bytes = self.nonce.0.as_ref(); + let nonce: Nonce = Nonce(nonce_bytes.into()); + nonce + } + + /// Encrypts and signs (“seals”) data in place, appending the tag to the + /// resulting ciphertext. + /// + /// See [SealingKey::seal_in_place_append_tag] for additional API information. + /// + /// # Errors + /// `error::Unspecified` when `nonce_sequence` cannot be advanced. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn seal_in_place_append_tag( + self, + aad: Aad, + in_out: &mut InOut, + ) -> Result<(), Unspecified> + where + A: AsRef<[u8]>, + InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>, + { + self.key + .key + .seal_in_place_append_tag(Some(self.nonce), aad.as_ref(), in_out) + .map(|_| ()) + } + + /// Encrypts and signs (“seals”) data in place. + /// + /// See [`SealingKey::seal_in_place_separate_tag`] for additional API information. + /// + /// # Errors + /// `error::Unspecified` when `nonce_sequence` cannot be advanced. + #[inline] + #[allow(clippy::needless_pass_by_value)] + pub fn seal_in_place_separate_tag( + self, + aad: Aad, + in_out: &mut [u8], + ) -> Result + where + A: AsRef<[u8]>, + { + self.key + .key + .seal_in_place_separate_tag(Some(self.nonce), aad.as_ref(), in_out) + .map(|(_, tag)| tag) + } } /// The additionally authenticated data (AAD) for an opening or sealing @@ -786,6 +937,12 @@ impl AsRef<[u8]> for Tag { } } +impl core::fmt::Debug for Tag { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_tuple("Tag").finish() + } +} + #[allow(dead_code)] const MAX_KEY_LEN: usize = 32; diff --git a/aws-lc-rs/tests/aead_test.rs b/aws-lc-rs/tests/aead_test.rs index 3b521dd71b5..e734d3c50b9 100644 --- a/aws-lc-rs/tests/aead_test.rs +++ b/aws-lc-rs/tests/aead_test.rs @@ -3,9 +3,12 @@ // Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR ISC +use aws_lc_rs::aead::nonce_sequence::Counter32Builder; use aws_lc_rs::{aead, error, test, test_file}; -use aws_lc_rs::aead::{Nonce, NONCE_LEN}; +use aws_lc_rs::aead::{ + Aad, BoundKey, Nonce, OpeningKey, SealingKey, UnboundKey, AES_128_GCM, NONCE_LEN, +}; use core::ops::RangeFrom; #[test] @@ -660,3 +663,90 @@ impl aead::NonceSequence for OneNonceSequence { self.0.take().ok_or(error::Unspecified) } } + +#[test] +fn prepare_operation() { + const KEY: &[u8] = &[ + 0x52, 0x05, 0x19, 0x7a, 0xcc, 0x88, 0xdb, 0x78, 0x39, 0x59, 0xbc, 0x03, 0xb8, 0x1d, 0x4a, + 0x6c, + ]; + const MESSAGE: &[u8] = &[ + 0x52, 0x61, 0x63, 0x63, 0x6f, 0x6f, 0x6e, 0x20, 0x4d, 0x69, 0x73, 0x63, 0x68, 0x69, 0x65, + 0x66, + ]; + const LIMIT: u32 = 10; + + let mut sk = SealingKey::new( + UnboundKey::new(&AES_128_GCM, KEY).unwrap(), + Counter32Builder::new().limit(LIMIT).build(), + ); + let mut ok = OpeningKey::new( + UnboundKey::new(&AES_128_GCM, KEY).unwrap(), + Counter32Builder::new().limit(LIMIT).build(), + ); + + let mut nonces: Vec> = vec![]; + + for _ in 0..(LIMIT / 2) { + let so = sk.prepare_operation().unwrap(); + let oo = ok.prepare_operation().unwrap(); + let so_nonce = Vec::from(so.nonce().as_ref()); + let oo_nonce = Vec::from(oo.nonce().as_ref()); + + assert_eq!(so_nonce.as_slice(), oo_nonce.as_slice()); + assert!(!nonces.contains(&so_nonce)); + nonces.push(so_nonce); + nonces.push(oo_nonce); + + let mut message: Vec = vec![]; + message.extend_from_slice(MESSAGE); + + so.seal_in_place_append_tag(Aad::empty(), &mut message) + .unwrap(); + assert_ne!(MESSAGE, message.as_slice()); + + let message = oo.open_in_place(Aad::empty(), &mut message).unwrap(); + assert_eq!(MESSAGE, message); + + let so = sk.prepare_operation().unwrap(); + let oo = ok.prepare_operation().unwrap(); + let so_nonce = Vec::from(so.nonce().as_ref()); + let oo_nonce = Vec::from(oo.nonce().as_ref()); + + assert_eq!(so_nonce.as_slice(), oo_nonce.as_slice()); + assert!(!nonces.contains(&so_nonce)); + nonces.push(so_nonce); + nonces.push(oo_nonce); + + let mut message: Vec = vec![]; + message.extend_from_slice(MESSAGE); + + let tag = so + .seal_in_place_separate_tag(Aad::empty(), &mut message) + .unwrap(); + assert_ne!(MESSAGE, message.as_slice()); + message.extend_from_slice(tag.as_ref()); + + let message = oo.open_within(Aad::empty(), &mut message, 0..).unwrap(); + assert_eq!(MESSAGE, message); + } + + let nonce_chunks = nonces.chunks_exact(2); + assert_eq!(0, nonce_chunks.remainder().len()); + for chunk in nonce_chunks { + assert_eq!(chunk[0].as_slice(), chunk[1].as_slice()); + } + + let mut message: Vec = vec![]; + message.extend_from_slice(MESSAGE); + + // Subsequent usage should fail now since the sequence is exhausted in each key. + sk.prepare_operation().expect_err("sequence limit reached"); + ok.prepare_operation().expect_err("sequence limit reached"); + sk.seal_in_place_append_tag(Aad::empty(), &mut message) + .expect_err("sequence limit reached"); + sk.seal_in_place_separate_tag(Aad::empty(), &mut message) + .expect_err("sequence limit reached"); + ok.open_in_place(Aad::empty(), &mut message) + .expect_err("sequence limit reached"); +} From 2d71e35a945a1030ef3cf0a7abd28a509d099d1b Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Mon, 2 Dec 2024 23:47:21 +0000 Subject: [PATCH 2/5] Rename macro --- aws-lc-rs/src/aead.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aws-lc-rs/src/aead.rs b/aws-lc-rs/src/aead.rs index 55b59c7f457..0579405000d 100644 --- a/aws-lc-rs/src/aead.rs +++ b/aws-lc-rs/src/aead.rs @@ -450,7 +450,7 @@ impl SealingKey { } } -macro_rules! nonce_sequence_key_iterator { +macro_rules! key_op_mut { ($name:ident) => { paste! { /// A key operation with a precomputed nonce from a key's associated `NonceSequence`. @@ -478,8 +478,8 @@ macro_rules! nonce_sequence_key_iterator { }; } -nonce_sequence_key_iterator!(OpeningKey); -nonce_sequence_key_iterator!(SealingKey); +key_op_mut!(OpeningKey); +key_op_mut!(SealingKey); impl OpeningKeyOpMut<'_, N> { /// Returns the Nonce that will be used for this operation. From 4a5481f7a0be751422793e41ce7a5ee9b30a9475 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Tue, 3 Dec 2024 00:17:29 +0000 Subject: [PATCH 3/5] Fix debug --- aws-lc-rs/src/aead.rs | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/aws-lc-rs/src/aead.rs b/aws-lc-rs/src/aead.rs index 0579405000d..25286781a5c 100644 --- a/aws-lc-rs/src/aead.rs +++ b/aws-lc-rs/src/aead.rs @@ -116,7 +116,7 @@ use crate::{derive_debug_via_id, error::Unspecified, hkdf}; use aead_ctx::AeadCtx; -use core::{fmt::Debug, ops::RangeFrom}; +use core::{fmt::Debug, ops::RangeFrom, stringify}; use paste::paste; mod aead_ctx; @@ -450,7 +450,7 @@ impl SealingKey { } } -macro_rules! key_op_mut { +macro_rules! nonce_seq_key_op_mut { ($name:ident) => { paste! { /// A key operation with a precomputed nonce from a key's associated `NonceSequence`. @@ -471,15 +471,15 @@ macro_rules! key_op_mut { impl<'a, N: NonceSequence> Debug for [<$name OpMut>]<'a, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - f.debug_struct("[<$name OpMut>]").finish_non_exhaustive() + f.debug_struct(stringify!([<$name OpMut>])).finish_non_exhaustive() } } } }; } -key_op_mut!(OpeningKey); -key_op_mut!(SealingKey); +nonce_seq_key_op_mut!(OpeningKey); +nonce_seq_key_op_mut!(SealingKey); impl OpeningKeyOpMut<'_, N> { /// Returns the Nonce that will be used for this operation. @@ -954,6 +954,8 @@ pub const MAX_TAG_LEN: usize = TAG_LEN; #[cfg(test)] mod tests { + use nonce_sequence::Counter32Builder; + use super::*; use crate::{iv::FixedLength, test::from_hex}; @@ -1010,4 +1012,26 @@ mod tests { assert_eq!(plaintext, in_out[..plaintext.len()]); } + + #[test] + fn debug_key_op_mut() { + let mut sk = SealingKey::new( + UnboundKey::new(&AES_128_GCM, &[0u8; 16]).unwrap(), + Counter32Builder::new().build(), + ); + let mut ok = OpeningKey::new( + UnboundKey::new(&AES_128_GCM, &[0u8; 16]).unwrap(), + Counter32Builder::new().build(), + ); + let so = sk.prepare_operation().unwrap(); + let oo = ok.prepare_operation().unwrap(); + assert_eq!("SealingKeyOpMut { .. }", format!("{so:?}")); + assert_eq!("OpeningKeyOpMut { .. }", format!("{oo:?}")); + } + + #[test] + fn debug_tag() { + let tag = Tag([0u8; MAX_TAG_LEN], MAX_TAG_LEN); + assert_eq!("Tag", format!("{tag:?}")) + } } From 2054e8ab009f2bb7a6272252ef81f1699b30d975 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Tue, 3 Dec 2024 17:25:15 +0000 Subject: [PATCH 4/5] Make clippy happy --- aws-lc-rs/src/aead.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws-lc-rs/src/aead.rs b/aws-lc-rs/src/aead.rs index 25286781a5c..b3e52c6b312 100644 --- a/aws-lc-rs/src/aead.rs +++ b/aws-lc-rs/src/aead.rs @@ -1032,6 +1032,6 @@ mod tests { #[test] fn debug_tag() { let tag = Tag([0u8; MAX_TAG_LEN], MAX_TAG_LEN); - assert_eq!("Tag", format!("{tag:?}")) + assert_eq!("Tag", format!("{tag:?}")); } } From 5c5652415cf451c793f76cd1c8a618cf1383cb71 Mon Sep 17 00:00:00 2001 From: Sean McGrail Date: Wed, 4 Dec 2024 00:20:26 +0000 Subject: [PATCH 5/5] Address feedback --- aws-lc-rs/src/aead.rs | 157 ++++++++++++++++++++++++----------- aws-lc-rs/tests/aead_test.rs | 22 ++--- 2 files changed, 120 insertions(+), 59 deletions(-) diff --git a/aws-lc-rs/src/aead.rs b/aws-lc-rs/src/aead.rs index b3e52c6b312..1c0e743bab0 100644 --- a/aws-lc-rs/src/aead.rs +++ b/aws-lc-rs/src/aead.rs @@ -113,6 +113,72 @@ //! //! assert_eq!(plaintext, decrypted_plaintext); //! ``` +//! +//! ## Prepared Nonce API's with Nonce Sequence +//! +//! If you prefer to use the [NonceSequence] based API's, and need to know the [Nonce] explicit nonce used for a +//! cryptographic key operation operation, then [SealingKeyPreparedNonce] and +//! [OpeningKeyPreparedNonce] are available to you. +//! +//! ```rust +//! # use std::error::Error; +//! # +//! # fn main() -> Result<(), Box> { +//! use aws_lc_rs::aead::{ +//! nonce_sequence::Counter32Builder, Aad, BoundKey, OpeningKey, SealingKey, UnboundKey, +//! AES_128_GCM, +//! }; +//! use std::vec::Vec; +//! +//! let key_bytes = &[ +//! 0xa5, 0xf3, 0x8d, 0x0d, 0x2d, 0x7c, 0x48, 0x56, 0xe7, 0xf3, 0xc3, 0x63, 0x0d, 0x40, 0x5b, +//! 0x9e, +//! ]; +//! +//! // Create AES-128-GCM SealingKey +//! let mut sealing_key = SealingKey::new( +//! UnboundKey::new(&AES_128_GCM, key_bytes)?, +//! Counter32Builder::new() +//! .identifier([0, 1, 2, 3, 4, 5, 6, 7]) +//! .build(), +//! ); +//! +//! // Create AES-128-GCM OpeningKey +//! let mut opening_key = OpeningKey::new( +//! UnboundKey::new(&AES_128_GCM, key_bytes)?, +//! Counter32Builder::new() +//! .identifier([0, 1, 2, 3, 4, 5, 6, 7]) +//! .build(), +//! ); +//! +//! let message = "test message"; +//! let mut in_out = Vec::from(message); +//! +//! // Create a SealingKeyPreparedNonce which consumes a nonce from the underlying sequence +//! let seal_prepared_nonce = sealing_key.prepare_nonce()?; +//! +//! // Query the nonce that will be used for our seal operation with our prepared nonce +//! let seal_nonce_bytes = Vec::from(seal_prepared_nonce.nonce().as_ref()); +//! +//! // Use the prepared nonce and seal the plaintext +//! seal_prepared_nonce.seal_in_place_append_tag(Aad::empty(), &mut in_out)?; +//! +//! // Create a OpeningKeyPreparedNonce which consumes a nonce from the underlying sequence +//! let open_prepared_nonce = opening_key.prepare_nonce()?; +//! +//! // Query the nonce that will be used for our seal operation with our prepared nonce +//! let open_nonce_bytes = Vec::from(open_prepared_nonce.nonce().as_ref()); +//! +//! // Since we initialized the Counter32Builder the same between both builders the nonce here +//! // will match the one from the opening key. +//! assert_eq!(seal_nonce_bytes.as_slice(), open_nonce_bytes.as_slice()); +//! +//! let plaintext = open_prepared_nonce.open_in_place(Aad::empty(), &mut in_out)?; +//! +//! assert_eq!(message.as_bytes(), plaintext); +//! # Ok(()) +//! # } +//! ``` use crate::{derive_debug_via_id, error::Unspecified, hkdf}; use aead_ctx::AeadCtx; @@ -215,7 +281,6 @@ impl OpeningKey { /// plaintext without the tag. /// /// Prefer [`RandomizedNonceKey::open_in_place`]. - /// // # FIPS // Use this method with one of the following algorithms: // * `AES_128_GCM` @@ -281,7 +346,6 @@ impl OpeningKey { /// This reassembly be accomplished with three calls to `open_within()`. /// /// Prefer [`RandomizedNonceKey::open_in_place`]. - /// // # FIPS // Use this method with one of the following algorithms: // * `AES_128_GCM` @@ -309,11 +373,19 @@ impl OpeningKey { ) } - /// Returns a `OpeningKeyOpMut` with the next computed `Nonce` from the `NonceSequence` for the next operation. + /// Returns a `OpeningKeyPreparedNonce` containing the next computed `Nonce` consumed from `NonceSequence`. + /// + /// The encapsulated Nonce will be used **if and only if** either + /// [OpeningKeyPreparedNonce::open_in_place] or [OpeningKeyPreparedNonce::open_within] + /// are invoked. Dropping `OpeningKeyPreparedNonce` without invoking either method results in the nonce remaining + /// consumed and unused within the associated `NonceSequence`. Subsequent calls to [OpeningKey] methods will + /// always use a proceeding nonce from the `NonceSequence` regardless of whether + /// a `OpeningKeyPreparedNonce` is consumed or not. + /// /// # Errors - /// `Unspecified` if there is a failure computing the nonce for the next operation. - pub fn prepare_operation(&mut self) -> Result, Unspecified> { - OpeningKeyOpMut::new(self) + /// `Unspecified` if there is a failure computing the nonce for the next operation, i.e. `NonceSequence` exhausted. + pub fn prepare_nonce(&mut self) -> Result, Unspecified> { + OpeningKeyPreparedNonce::new(self) } } @@ -355,7 +427,6 @@ impl SealingKey { /// Deprecated. Renamed to `seal_in_place_append_tag`. /// /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. - /// // # FIPS // This method must not be used. // @@ -386,7 +457,6 @@ impl SealingKey { /// ``` /// /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. - /// // # FIPS // This method must not be used. // @@ -421,7 +491,6 @@ impl SealingKey { /// The tag will be `self.algorithm.tag_len()` bytes long. /// /// Prefer [`RandomizedNonceKey::seal_in_place_separate_tag`]. - /// // # FIPS // This method must not be used. // @@ -442,11 +511,19 @@ impl SealingKey { .map(|(_, tag)| tag) } - /// Returns a `SealingKeyOpMut` with the next computed `Nonce` from the `NonceSequence` for the next operation. + /// Returns a `SealingKeyPreparedNonce` containing the next computed `Nonce` consumed from `NonceSequence`. + /// + /// The encapsulated Nonce will be used **if and only if** either + /// [SealingKeyPreparedNonce::seal_in_place_append_tag] or [SealingKeyPreparedNonce::seal_in_place_separate_tag] + /// are invoked. Dropping `SealingKeyPreparedNonce` without invoking either method results in the nonce remaining + /// consumed and unused within the associated `NonceSequence`. Subsequent calls to [SealingKey] methods will + /// always use a proceeding nonce from the `NonceSequence` regardless of whether + /// a `SealingKeyPreparedNonce` is consumed or not. + /// /// # Errors - /// `Unspecified` if there is a failure computing the nonce for the next operation. - pub fn prepare_operation(&mut self) -> Result, Unspecified> { - SealingKeyOpMut::new(self) + /// `Unspecified` if there is a failure computing the nonce for the next operation, i.e. `NonceSequence` exhausted. + pub fn prepare_nonce(&mut self) -> Result, Unspecified> { + SealingKeyPreparedNonce::new(self) } } @@ -454,12 +531,12 @@ macro_rules! nonce_seq_key_op_mut { ($name:ident) => { paste! { /// A key operation with a precomputed nonce from a key's associated `NonceSequence`. - pub struct [<$name OpMut>]<'a, N: NonceSequence> { + pub struct [<$name PreparedNonce>]<'a, N: NonceSequence> { key: &'a mut $name, nonce: Nonce, } - impl<'a, N: NonceSequence> [<$name OpMut>]<'a, N> { + impl<'a, N: NonceSequence> [<$name PreparedNonce>]<'a, N> { fn new(key: &'a mut $name) -> Result { let nonce = key.nonce_sequence.advance()?; Ok(Self { @@ -469,9 +546,17 @@ macro_rules! nonce_seq_key_op_mut { } } - impl<'a, N: NonceSequence> Debug for [<$name OpMut>]<'a, N> { + impl [<$name PreparedNonce>]<'_, N> { + /// Returns the prepared Nonce that is used for key methods invoked on [Self]. + #[must_use] + pub fn nonce(&self) -> &Nonce { + &self.nonce + } + } + + impl Debug for [<$name PreparedNonce>]<'_, N> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { - f.debug_struct(stringify!([<$name OpMut>])).finish_non_exhaustive() + f.debug_struct(stringify!([<$name PreparedNonce>])).finish_non_exhaustive() } } } @@ -481,15 +566,7 @@ macro_rules! nonce_seq_key_op_mut { nonce_seq_key_op_mut!(OpeningKey); nonce_seq_key_op_mut!(SealingKey); -impl OpeningKeyOpMut<'_, N> { - /// Returns the Nonce that will be used for this operation. - #[must_use] - pub fn nonce(&self) -> Nonce { - let nonce_bytes = self.nonce.0.as_ref(); - let nonce: Nonce = Nonce(nonce_bytes.into()); - nonce - } - +impl OpeningKeyPreparedNonce<'_, N> { /// Authenticates and decrypts (“opens”) data in place. /// /// See [OpeningKey::open_in_place] for additional API information. @@ -530,15 +607,7 @@ impl OpeningKeyOpMut<'_, N> { } } -impl SealingKeyOpMut<'_, N> { - /// Returns the Nonce that will be used for this operation. - #[must_use] - pub fn nonce(&self) -> Nonce { - let nonce_bytes = self.nonce.0.as_ref(); - let nonce: Nonce = Nonce(nonce_bytes.into()); - nonce - } - +impl SealingKeyPreparedNonce<'_, N> { /// Encrypts and signs (“seals”) data in place, appending the tag to the /// resulting ciphertext. /// @@ -629,7 +698,6 @@ impl hkdf::KeyType for &'static Algorithm { /// `NonceSequence` cannot reasonably be used. /// /// Prefer [`RandomizedNonceKey`] when practical. -/// // # FIPS // The following conditions must be met: // * `UnboundKey`'s algorithm is one of: @@ -652,7 +720,6 @@ impl LessSafeKey { /// `nonce` must be unique for every use of the key to open data. /// /// Prefer [`RandomizedNonceKey::open_in_place`]. - /// // # FIPS // Use this method with one of the following algorithms: // * `AES_128_GCM` @@ -678,7 +745,6 @@ impl LessSafeKey { /// `nonce` must be unique for every use of the key to open data. /// /// Prefer [`RandomizedNonceKey::open_in_place`]. - /// // # FIPS // Use this method with one of the following algorithms: // * `AES_128_GCM` @@ -714,7 +780,6 @@ impl LessSafeKey { /// # Errors /// `error::Unspecified` when ciphertext is invalid. In this case, `out_plaintext` may /// have been overwritten in an unspecified way. - /// #[inline] #[allow(clippy::needless_pass_by_value)] pub fn open_separate_gather( @@ -735,7 +800,6 @@ impl LessSafeKey { /// Deprecated. Renamed to `seal_in_place_append_tag()`. /// /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. - /// // # FIPS // This method must not be used. // @@ -761,7 +825,6 @@ impl LessSafeKey { /// `nonce` must be unique for every use of the key to seal data. /// /// Prefer [`RandomizedNonceKey::seal_in_place_append_tag`]. - /// // # FIPS // This method must not be used. // @@ -790,7 +853,6 @@ impl LessSafeKey { /// `nonce` must be unique for every use of the key to seal data. /// /// Prefer [`RandomizedNonceKey::seal_in_place_separate_tag`]. - /// // # FIPS // This method must not be used. // @@ -825,7 +887,6 @@ impl LessSafeKey { /// The `extra_out_and_tag` length must be equal to the `extra_len` and `self.algorithm.tag_len()`. /// /// `nonce` must be unique for every use of the key to seal data. - /// // # FIPS // This method must not be used. // @@ -1014,7 +1075,7 @@ mod tests { } #[test] - fn debug_key_op_mut() { + fn debug_prepared_nonce() { let mut sk = SealingKey::new( UnboundKey::new(&AES_128_GCM, &[0u8; 16]).unwrap(), Counter32Builder::new().build(), @@ -1023,10 +1084,10 @@ mod tests { UnboundKey::new(&AES_128_GCM, &[0u8; 16]).unwrap(), Counter32Builder::new().build(), ); - let so = sk.prepare_operation().unwrap(); - let oo = ok.prepare_operation().unwrap(); - assert_eq!("SealingKeyOpMut { .. }", format!("{so:?}")); - assert_eq!("OpeningKeyOpMut { .. }", format!("{oo:?}")); + let so = sk.prepare_nonce().unwrap(); + let oo = ok.prepare_nonce().unwrap(); + assert_eq!("SealingKeyPreparedNonce { .. }", format!("{so:?}")); + assert_eq!("OpeningKeyPreparedNonce { .. }", format!("{oo:?}")); } #[test] diff --git a/aws-lc-rs/tests/aead_test.rs b/aws-lc-rs/tests/aead_test.rs index e734d3c50b9..1423fff187d 100644 --- a/aws-lc-rs/tests/aead_test.rs +++ b/aws-lc-rs/tests/aead_test.rs @@ -665,7 +665,7 @@ impl aead::NonceSequence for OneNonceSequence { } #[test] -fn prepare_operation() { +fn prepare_nonce() { const KEY: &[u8] = &[ 0x52, 0x05, 0x19, 0x7a, 0xcc, 0x88, 0xdb, 0x78, 0x39, 0x59, 0xbc, 0x03, 0xb8, 0x1d, 0x4a, 0x6c, @@ -688,10 +688,10 @@ fn prepare_operation() { let mut nonces: Vec> = vec![]; for _ in 0..(LIMIT / 2) { - let so = sk.prepare_operation().unwrap(); - let oo = ok.prepare_operation().unwrap(); - let so_nonce = Vec::from(so.nonce().as_ref()); - let oo_nonce = Vec::from(oo.nonce().as_ref()); + let skpn = sk.prepare_nonce().unwrap(); + let okpn = ok.prepare_nonce().unwrap(); + let so_nonce = Vec::from(skpn.nonce().as_ref()); + let oo_nonce = Vec::from(okpn.nonce().as_ref()); assert_eq!(so_nonce.as_slice(), oo_nonce.as_slice()); assert!(!nonces.contains(&so_nonce)); @@ -701,15 +701,15 @@ fn prepare_operation() { let mut message: Vec = vec![]; message.extend_from_slice(MESSAGE); - so.seal_in_place_append_tag(Aad::empty(), &mut message) + skpn.seal_in_place_append_tag(Aad::empty(), &mut message) .unwrap(); assert_ne!(MESSAGE, message.as_slice()); - let message = oo.open_in_place(Aad::empty(), &mut message).unwrap(); + let message = okpn.open_in_place(Aad::empty(), &mut message).unwrap(); assert_eq!(MESSAGE, message); - let so = sk.prepare_operation().unwrap(); - let oo = ok.prepare_operation().unwrap(); + let so = sk.prepare_nonce().unwrap(); + let oo = ok.prepare_nonce().unwrap(); let so_nonce = Vec::from(so.nonce().as_ref()); let oo_nonce = Vec::from(oo.nonce().as_ref()); @@ -741,8 +741,8 @@ fn prepare_operation() { message.extend_from_slice(MESSAGE); // Subsequent usage should fail now since the sequence is exhausted in each key. - sk.prepare_operation().expect_err("sequence limit reached"); - ok.prepare_operation().expect_err("sequence limit reached"); + sk.prepare_nonce().expect_err("sequence limit reached"); + ok.prepare_nonce().expect_err("sequence limit reached"); sk.seal_in_place_append_tag(Aad::empty(), &mut message) .expect_err("sequence limit reached"); sk.seal_in_place_separate_tag(Aad::empty(), &mut message)