diff --git a/src/aead.rs b/src/aead.rs index f1ac50ccb..3c233c528 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -144,20 +144,13 @@ impl hkdf::KeyType for &'static Algorithm { pub struct Algorithm { init: fn(key: &[u8], cpu_features: cpu::Features) -> Result, - seal: fn( - key: &KeyInner, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut [u8], - cpu_features: cpu::Features, - ) -> Tag, + seal: fn(key: &KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8]) -> Tag, open: fn( key: &KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8], src: RangeFrom, - cpu_features: cpu::Features, ) -> Tag, key_len: usize, diff --git a/src/aead/aes_gcm.rs b/src/aead/aes_gcm.rs index 25a5bfbfb..5628f6d44 100644 --- a/src/aead/aes_gcm.rs +++ b/src/aead/aes_gcm.rs @@ -65,13 +65,7 @@ fn init( const CHUNK_BLOCKS: usize = 3 * 1024 / 16; -fn aes_gcm_seal( - key: &aead::KeyInner, - nonce: Nonce, - aad: Aad<&[u8]>, - in_out: &mut [u8], - cpu_features: cpu::Features, -) -> Tag { +fn aes_gcm_seal(key: &aead::KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8]) -> Tag { let Key { aes_key, gcm_key } = match key { aead::KeyInner::AesGcm(key) => key, _ => unreachable!(), @@ -82,7 +76,7 @@ fn aes_gcm_seal( let total_in_out_len = in_out.len(); let aad_len = aad.0.len(); - let mut auth = gcm::Context::new(gcm_key, aad, cpu_features); + let mut auth = gcm::Context::new(gcm_key, aad); #[cfg(target_arch = "x86_64")] let in_out = { @@ -144,7 +138,6 @@ fn aes_gcm_open( aad: Aad<&[u8]>, in_out: &mut [u8], src: RangeFrom, - cpu_features: cpu::Features, ) -> Tag { let Key { aes_key, gcm_key } = match key { aead::KeyInner::AesGcm(key) => key, @@ -155,7 +148,7 @@ fn aes_gcm_open( let tag_iv = ctr.increment(); let aad_len = aad.0.len(); - let mut auth = gcm::Context::new(gcm_key, aad, cpu_features); + let mut auth = gcm::Context::new(gcm_key, aad); let in_prefix_len = src.start; diff --git a/src/aead/chacha.rs b/src/aead/chacha.rs index 880308f91..d47ff19da 100644 --- a/src/aead/chacha.rs +++ b/src/aead/chacha.rs @@ -14,7 +14,10 @@ // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use super::{quic::Sample, Nonce}; -use crate::polyfill::{array_map::Map, ChunksFixed}; +use crate::{ + cpu, + polyfill::{array_map::Map, ChunksFixed}, +}; #[cfg(any( test, @@ -30,13 +33,22 @@ mod fallback; use core::ops::RangeFrom; #[repr(transparent)] -pub struct Key([u32; KEY_LEN / 4]); +pub struct Key { + words: [u32; KEY_LEN / 4], + cpu_features: cpu::Features, +} -impl From<[u8; KEY_LEN]> for Key { - #[inline] - fn from(value: [u8; KEY_LEN]) -> Self { +impl Key { + pub(super) fn new(value: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self { let value: &[[u8; 4]; KEY_LEN / 4] = value.chunks_fixed(); - Self(value.array_map(u32::from_le_bytes)) + Self { + words: value.array_map(u32::from_le_bytes), + cpu_features, + } + } + + pub(super) fn cpu_features(&self) -> cpu::Features { + self.cpu_features } } @@ -140,7 +152,7 @@ impl Key { ))] #[inline] pub(super) fn words_less_safe(&self) -> &[u32; KEY_LEN / 4] { - &self.0 + &self.words } } @@ -261,7 +273,7 @@ mod tests { let key = test_case.consume_bytes("Key"); let key: &[u8; KEY_LEN] = key.as_slice().try_into()?; - let key = Key::from(*key); + let key = Key::new(*key, cpu::features()); let ctr = test_case.consume_usize("Ctr"); let nonce = test_case.consume_bytes("Nonce"); diff --git a/src/aead/chacha20_poly1305.rs b/src/aead/chacha20_poly1305.rs index b2fecf1fa..ef4eff6a3 100644 --- a/src/aead/chacha20_poly1305.rs +++ b/src/aead/chacha20_poly1305.rs @@ -36,10 +36,13 @@ pub static CHACHA20_POLY1305: aead::Algorithm = aead::Algorithm { /// Copies |key| into |ctx_buf|. fn chacha20_poly1305_init( key: &[u8], - _todo: cpu::Features, + cpu_features: cpu::Features, ) -> Result { let key: [u8; chacha::KEY_LEN] = key.try_into()?; - Ok(aead::KeyInner::ChaCha20Poly1305(chacha::Key::from(key))) + Ok(aead::KeyInner::ChaCha20Poly1305(chacha::Key::new( + key, + cpu_features, + ))) } fn chacha20_poly1305_seal( @@ -47,7 +50,6 @@ fn chacha20_poly1305_seal( nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8], - cpu_features: cpu::Features, ) -> Tag { let chacha20_key = match key { aead::KeyInner::ChaCha20Poly1305(key) => key, @@ -56,7 +58,7 @@ fn chacha20_poly1305_seal( #[cfg(target_arch = "x86_64")] { - if cpu::intel::SSE41.available(cpu_features) { + if cpu::intel::SSE41.available(chacha20_key.cpu_features()) { // XXX: BoringSSL uses `alignas(16)` on `key` instead of on the // structure, but Rust can't do that yet; see // https://github.com/rust-lang/rust/issues/73557. @@ -113,7 +115,7 @@ fn chacha20_poly1305_seal( let mut counter = Counter::zero(nonce); let mut auth = { - let key = derive_poly1305_key(chacha20_key, counter.increment(), cpu_features); + let key = derive_poly1305_key(chacha20_key, counter.increment()); poly1305::Context::from_key(key) }; @@ -129,7 +131,6 @@ fn chacha20_poly1305_open( aad: Aad<&[u8]>, in_out: &mut [u8], src: RangeFrom, - cpu_features: cpu::Features, ) -> Tag { let chacha20_key = match key { aead::KeyInner::ChaCha20Poly1305(key) => key, @@ -138,7 +139,7 @@ fn chacha20_poly1305_open( #[cfg(target_arch = "x86_64")] { - if cpu::intel::SSE41.available(cpu_features) { + if cpu::intel::SSE41.available(chacha20_key.cpu_features()) { // XXX: BoringSSL uses `alignas(16)` on `key` instead of on the // structure, but Rust can't do that yet; see // https://github.com/rust-lang/rust/issues/73557. @@ -191,7 +192,7 @@ fn chacha20_poly1305_open( let mut counter = Counter::zero(nonce); let mut auth = { - let key = derive_poly1305_key(chacha20_key, counter.increment(), cpu_features); + let key = derive_poly1305_key(chacha20_key, counter.increment()); poly1305::Context::from_key(key) }; @@ -250,14 +251,10 @@ fn poly1305_update_padded_16(ctx: &mut poly1305::Context, input: &[u8]) { } // Also used by chacha20_poly1305_openssh. -pub(super) fn derive_poly1305_key( - chacha_key: &chacha::Key, - iv: Iv, - cpu_features: cpu::Features, -) -> poly1305::Key { +pub(super) fn derive_poly1305_key(chacha_key: &chacha::Key, iv: Iv) -> poly1305::Key { let mut key_bytes = [0u8; poly1305::KEY_LEN]; chacha_key.encrypt_iv_xor_in_place(iv, &mut key_bytes); - poly1305::Key::new(key_bytes, cpu_features) + poly1305::Key::new(key_bytes, chacha_key.cpu_features()) } #[cfg(test)] diff --git a/src/aead/chacha20_poly1305_openssh.rs b/src/aead/chacha20_poly1305_openssh.rs index c7c5451b6..585914b14 100644 --- a/src/aead/chacha20_poly1305_openssh.rs +++ b/src/aead/chacha20_poly1305_openssh.rs @@ -65,8 +65,7 @@ impl SealingKey { tag_out: &mut [u8; TAG_LEN], ) { let mut counter = make_counter(sequence_number); - let poly_key = - derive_poly1305_key(&self.key.k_2, counter.increment(), self.key.cpu_features); + let poly_key = derive_poly1305_key(&self.key.k_2, counter.increment()); { let (len_in_out, data_and_padding_in_out) = @@ -133,8 +132,7 @@ impl OpeningKey { // We must verify the tag before decrypting so that // `ciphertext_in_plaintext_out` is unmodified if verification fails. // This is beyond what we guarantee. - let poly_key = - derive_poly1305_key(&self.key.k_2, counter.increment(), self.key.cpu_features); + let poly_key = derive_poly1305_key(&self.key.k_2, counter.increment()); verify(poly_key, ciphertext_in_plaintext_out, tag)?; let plaintext_in_ciphertext_out = &mut ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..]; @@ -149,7 +147,6 @@ impl OpeningKey { struct Key { k_1: chacha::Key, k_2: chacha::Key, - cpu_features: cpu::Features, } impl Key { @@ -157,9 +154,8 @@ impl Key { // The first half becomes K_2 and the second half becomes K_1. let &[k_2, k_1]: &[[u8; chacha::KEY_LEN]; 2] = key_material.chunks_fixed(); Self { - k_1: k_1.into(), - k_2: k_2.into(), - cpu_features, + k_1: chacha::Key::new(k_1, cpu_features), + k_2: chacha::Key::new(k_2, cpu_features), } } } diff --git a/src/aead/gcm.rs b/src/aead/gcm.rs index 63356b254..b8f7b7917 100644 --- a/src/aead/gcm.rs +++ b/src/aead/gcm.rs @@ -22,16 +22,22 @@ use core::ops::BitXorAssign; #[cfg(not(target_arch = "aarch64"))] mod gcm_nohw; -pub struct Key(HTable); +pub struct Key { + h_table: HTable, + cpu_features: cpu::Features, +} impl Key { pub(super) fn new(h_be: Block, cpu_features: cpu::Features) -> Self { let h: [u64; 2] = h_be.into(); - let mut key = Self(HTable { - Htable: [u128 { hi: 0, lo: 0 }; HTABLE_LEN], - }); - let h_table = &mut key.0; + let mut key = Self { + h_table: HTable { + Htable: [u128 { hi: 0, lo: 0 }; HTABLE_LEN], + }, + cpu_features, + }; + let h_table = &mut key.h_table; match detect_implementation(cpu_features) { #[cfg(target_arch = "x86_64")] @@ -85,14 +91,14 @@ pub struct Context { } impl Context { - pub(crate) fn new(key: &Key, aad: Aad<&[u8]>, cpu_features: cpu::Features) -> Self { + pub(crate) fn new(key: &Key, aad: Aad<&[u8]>) -> Self { let mut ctx = Self { inner: ContextInner { Xi: Xi(Block::zero()), _unused: Block::zero(), - Htable: key.0.clone(), + Htable: key.h_table.clone(), }, - cpu_features, + cpu_features: key.cpu_features, }; for ad in aad.0.chunks(BLOCK_LEN) { diff --git a/src/aead/less_safe_key.rs b/src/aead/less_safe_key.rs index 14139a1db..55bb6162d 100644 --- a/src/aead/less_safe_key.rs +++ b/src/aead/less_safe_key.rs @@ -23,7 +23,6 @@ use core::ops::RangeFrom; pub struct LessSafeKey { inner: KeyInner, algorithm: &'static Algorithm, - cpu_features: cpu::Features, } impl LessSafeKey { @@ -41,7 +40,6 @@ impl LessSafeKey { Ok(Self { inner: (algorithm.init)(key_bytes, cpu_features)?, algorithm, - cpu_features, }) } @@ -153,8 +151,7 @@ fn open_within_<'in_out>( .ok_or(error::Unspecified)?; check_per_nonce_max_bytes(key.algorithm, ciphertext_len)?; let (in_out, received_tag) = in_out.split_at_mut(src.start + ciphertext_len); - let Tag(calculated_tag) = - (key.algorithm.open)(&key.inner, nonce, aad, in_out, src, key.cpu_features); + let Tag(calculated_tag) = (key.algorithm.open)(&key.inner, nonce, aad, in_out, src); if constant_time::verify_slices_are_equal(calculated_tag.as_ref(), received_tag).is_err() { // Zero out the plaintext so that it isn't accidentally leaked or used // after verification fails. It would be safest if we could check the @@ -177,13 +174,7 @@ pub(super) fn seal_in_place_separate_tag_( in_out: &mut [u8], ) -> Result { check_per_nonce_max_bytes(key.algorithm(), in_out.len())?; - Ok((key.algorithm.seal)( - &key.inner, - nonce, - aad, - in_out, - key.cpu_features, - )) + Ok((key.algorithm.seal)(&key.inner, nonce, aad, in_out)) } fn check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified> { diff --git a/src/aead/quic.rs b/src/aead/quic.rs index ac667aeda..1996121f7 100644 --- a/src/aead/quic.rs +++ b/src/aead/quic.rs @@ -171,9 +171,12 @@ pub static CHACHA20: Algorithm = Algorithm { id: AlgorithmID::CHACHA20, }; -fn chacha20_init(key: &[u8], _todo: cpu::Features) -> Result { +fn chacha20_init(key: &[u8], cpu_features: cpu::Features) -> Result { let chacha20_key: [u8; chacha::KEY_LEN] = key.try_into()?; - Ok(KeyInner::ChaCha20(chacha::Key::from(chacha20_key))) + Ok(KeyInner::ChaCha20(chacha::Key::new( + chacha20_key, + cpu_features, + ))) } fn chacha20_new_mask(key: &KeyInner, sample: Sample) -> [u8; 5] {