diff --git a/src/aead.rs b/src/aead.rs index dd1999832..be059c7fc 100644 --- a/src/aead.rs +++ b/src/aead.rs @@ -134,13 +134,20 @@ 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]) -> Tag, + seal: fn( + key: &KeyInner, + nonce: Nonce, + aad: Aad<&[u8]>, + in_out: &mut [u8], + cpu_features: cpu::Features, + ) -> 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.rs b/src/aead/aes.rs index f87427b58..fdacbfbb2 100644 --- a/src/aead/aes.rs +++ b/src/aead/aes.rs @@ -29,7 +29,6 @@ use core::ops::RangeFrom; #[derive(Clone)] pub(super) struct Key { inner: AES_KEY, - cpu_features: cpu::Features, } macro_rules! set_encrypt_key { @@ -172,15 +171,12 @@ impl Key { } }; - Ok(Self { - inner: key, - cpu_features, - }) + Ok(Self { inner: key }) } #[inline] - pub fn encrypt_block(&self, a: Block) -> Block { - match detect_implementation(self.cpu_features) { + pub fn encrypt_block(&self, a: Block, cpu_features: cpu::Features) -> Block { + match detect_implementation(cpu_features) { #[cfg(any( target_arch = "aarch64", target_arch = "arm", @@ -203,8 +199,8 @@ impl Key { } #[inline] - pub fn encrypt_iv_xor_block(&self, iv: Iv, input: Block) -> Block { - let encrypted_iv = self.encrypt_block(iv.into_block_less_safe()); + pub fn encrypt_iv_xor_block(&self, iv: Iv, input: Block, cpu_features: cpu::Features) -> Block { + let encrypted_iv = self.encrypt_block(iv.into_block_less_safe(), cpu_features); encrypted_iv ^ input } @@ -214,12 +210,13 @@ impl Key { in_out: &mut [u8], src: RangeFrom, ctr: &mut Counter, + cpu_features: cpu::Features, ) { let in_out_len = in_out[src.clone()].len(); assert_eq!(in_out_len % BLOCK_LEN, 0); - match detect_implementation(self.cpu_features) { + match detect_implementation(cpu_features) { #[cfg(any( target_arch = "aarch64", target_arch = "arm", @@ -271,7 +268,7 @@ impl Key { #[cfg(target_arch = "x86")] Implementation::VPAES_BSAES => { super::shift::shift_full_blocks(in_out, src, |input| { - self.encrypt_iv_xor_block(ctr.increment(), Block::from(input)) + self.encrypt_iv_xor_block(ctr.increment(), Block::from(input), cpu_features) }); } @@ -283,7 +280,7 @@ impl Key { } pub fn new_mask(&self, sample: Sample) -> [u8; 5] { - let block = self.encrypt_block(Block::from(&sample)); + let block = self.encrypt_block(Block::from(&sample), cpu::features()); let mut out: [u8; 5] = [0; 5]; out.copy_from_slice(&block.as_ref()[..5]); @@ -293,11 +290,8 @@ impl Key { #[cfg(target_arch = "x86_64")] #[must_use] - pub fn is_aes_hw(&self) -> bool { - matches!( - detect_implementation(self.cpu_features), - Implementation::HWAES - ) + pub fn is_aes_hw(&self, cpu_features: cpu::Features) -> bool { + matches!(detect_implementation(cpu_features), Implementation::HWAES) } #[cfg(target_arch = "x86_64")] @@ -445,6 +439,7 @@ mod tests { #[test] pub fn test_aes() { + let cpu_features = cpu::features(); test::run(test_file!("aes_tests.txt"), |section, test_case| { assert_eq!(section, ""); let key = consume_key(test_case, "Key"); @@ -453,7 +448,7 @@ mod tests { let expected_output = test_case.consume_bytes("Output"); let block = Block::from(input); - let output = key.encrypt_block(block); + let output = key.encrypt_block(block, cpu_features); assert_eq!(output.as_ref(), &expected_output[..]); Ok(()) diff --git a/src/aead/aes_gcm.rs b/src/aead/aes_gcm.rs index ca2548506..73e4ef6ce 100644 --- a/src/aead/aes_gcm.rs +++ b/src/aead/aes_gcm.rs @@ -63,13 +63,22 @@ fn init( cpu_features: cpu::Features, ) -> Result { let aes_key = aes::Key::new(key, variant, cpu_features)?; - let gcm_key = gcm::Key::new(aes_key.encrypt_block(Block::zero()), cpu_features); + let gcm_key = gcm::Key::new( + aes_key.encrypt_block(Block::zero(), cpu_features), + cpu_features, + ); Ok(aead::KeyInner::AesGcm(Key { gcm_key, aes_key })) } const CHUNK_BLOCKS: usize = 3 * 1024 / 16; -fn aes_gcm_seal(key: &aead::KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8]) -> Tag { +fn aes_gcm_seal( + key: &aead::KeyInner, + nonce: Nonce, + aad: Aad<&[u8]>, + in_out: &mut [u8], + cpu_features: cpu::Features, +) -> Tag { let Key { gcm_key, aes_key } = match key { aead::KeyInner::AesGcm(key) => key, _ => unreachable!(), @@ -80,11 +89,11 @@ fn aes_gcm_seal(key: &aead::KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mu let total_in_out_len = in_out.len(); let aad_len = aad.0.len(); - let mut auth = gcm::Context::new(gcm_key, aad); + let mut auth = gcm::Context::new(gcm_key, aad, cpu_features); #[cfg(target_arch = "x86_64")] let in_out = { - if !aes_key.is_aes_hw() || !auth.is_avx() { + if !aes_key.is_aes_hw(cpu_features) || !auth.is_avx() { in_out } else { use crate::c; @@ -124,20 +133,27 @@ fn aes_gcm_seal(key: &aead::KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mu }; for chunk in whole.chunks_mut(CHUNK_BLOCKS * BLOCK_LEN) { - aes_key.ctr32_encrypt_within(chunk, 0.., &mut ctr); + aes_key.ctr32_encrypt_within(chunk, 0.., &mut ctr, cpu_features); auth.update_blocks(chunk); } if !remainder.is_empty() { let mut input = Block::zero(); input.overwrite_part_at(0, remainder); - let mut output = aes_key.encrypt_iv_xor_block(ctr.into(), input); + let mut output = aes_key.encrypt_iv_xor_block(ctr.into(), input, cpu_features); output.zero_from(remainder.len()); auth.update_block(output); remainder.copy_from_slice(&output.as_ref()[..remainder.len()]); } - finish(aes_key, auth, tag_iv, aad_len, total_in_out_len) + finish( + aes_key, + auth, + tag_iv, + aad_len, + total_in_out_len, + cpu_features, + ) } fn aes_gcm_open( @@ -146,6 +162,7 @@ fn aes_gcm_open( aad: Aad<&[u8]>, in_out: &mut [u8], src: RangeFrom, + cpu_features: cpu::Features, ) -> Tag { let Key { gcm_key, aes_key } = match key { aead::KeyInner::AesGcm(key) => key, @@ -156,7 +173,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); + let mut auth = gcm::Context::new(gcm_key, aad, cpu_features); let in_prefix_len = src.start; @@ -164,7 +181,7 @@ fn aes_gcm_open( #[cfg(target_arch = "x86_64")] let in_out = { - if !aes_key.is_aes_hw() || !auth.is_avx() { + if !aes_key.is_aes_hw(cpu_features) || !auth.is_avx() { in_out } else { use crate::c; @@ -218,6 +235,7 @@ fn aes_gcm_open( &mut in_out[output..][..(chunk_len + in_prefix_len)], in_prefix_len.., &mut ctr, + cpu_features, ); output += chunk_len; input += chunk_len; @@ -229,10 +247,17 @@ fn aes_gcm_open( let mut input = Block::zero(); input.overwrite_part_at(0, remainder); auth.update_block(input); - aes_key.encrypt_iv_xor_block(ctr.into(), input) + aes_key.encrypt_iv_xor_block(ctr.into(), input, cpu_features) }); - finish(aes_key, auth, tag_iv, aad_len, total_in_out_len) + finish( + aes_key, + auth, + tag_iv, + aad_len, + total_in_out_len, + cpu_features, + ) } fn finish( @@ -241,6 +266,7 @@ fn finish( tag_iv: aes::Iv, aad_len: usize, in_out_len: usize, + cpu_features: cpu::Features, ) -> Tag { // Authenticate the final block containing the input lengths. let aad_bits = polyfill::u64_from_usize(aad_len) << 3; @@ -251,7 +277,7 @@ fn finish( // Finalize the tag and return it. gcm_ctx.pre_finish(|pre_tag| { - let encrypted_iv = aes_key.encrypt_block(tag_iv.into_block_less_safe()); + let encrypted_iv = aes_key.encrypt_block(tag_iv.into_block_less_safe(), cpu_features); let tag = pre_tag ^ encrypted_iv; Tag(*tag.as_ref()) }) diff --git a/src/aead/chacha.rs b/src/aead/chacha.rs index 660cf34c2..a8771b4a9 100644 --- a/src/aead/chacha.rs +++ b/src/aead/chacha.rs @@ -14,7 +14,6 @@ // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use super::{quic::Sample, Nonce}; -use crate::cpu; #[cfg(any( test, @@ -33,20 +32,14 @@ use core::ops::RangeFrom; #[derive(Clone)] pub struct Key { words: [u32; KEY_LEN / 4], - cpu_features: cpu::Features, } impl Key { - pub(super) fn new(value: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self { + pub(super) fn new(value: [u8; KEY_LEN]) -> Self { Self { words: value.array_split_map(u32::from_le_bytes), - cpu_features, } } - - pub(super) fn cpu_features(&self) -> cpu::Features { - self.cpu_features - } } impl Key { @@ -261,7 +254,7 @@ mod tests { let key = test_case.consume_bytes("Key"); let key: &[u8; KEY_LEN] = key.as_slice().try_into()?; - let key = Key::new(*key, cpu::features()); + let key = Key::new(*key); 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 10c707bf3..1c9359fc0 100644 --- a/src/aead/chacha20_poly1305.rs +++ b/src/aead/chacha20_poly1305.rs @@ -39,13 +39,10 @@ pub static CHACHA20_POLY1305: aead::Algorithm = aead::Algorithm { /// Copies |key| into |ctx_buf|. fn chacha20_poly1305_init( key: &[u8], - cpu_features: cpu::Features, + _cpu_features: cpu::Features, ) -> Result { let key: [u8; chacha::KEY_LEN] = key.try_into()?; - Ok(aead::KeyInner::ChaCha20Poly1305(chacha::Key::new( - key, - cpu_features, - ))) + Ok(aead::KeyInner::ChaCha20Poly1305(chacha::Key::new(key))) } fn chacha20_poly1305_seal( @@ -53,6 +50,7 @@ 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, @@ -61,9 +59,7 @@ fn chacha20_poly1305_seal( #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] { - if cpu::intel::SSE41.available(chacha20_key.cpu_features()) - || cpu::arm::NEON.available(chacha20_key.cpu_features()) - { + if cpu::intel::SSE41.available(cpu_features) || cpu::arm::NEON.available(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. @@ -121,7 +117,7 @@ fn chacha20_poly1305_seal( let mut counter = Counter::zero(nonce); let mut auth = { let key = derive_poly1305_key(chacha20_key, counter.increment()); - poly1305::Context::from_key(key) + poly1305::Context::from_key(key, cpu_features) }; poly1305_update_padded_16(&mut auth, aad.as_ref()); @@ -136,6 +132,7 @@ 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, @@ -144,9 +141,7 @@ fn chacha20_poly1305_open( #[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))] { - if cpu::intel::SSE41.available(chacha20_key.cpu_features()) - || cpu::arm::NEON.available(chacha20_key.cpu_features()) - { + if cpu::intel::SSE41.available(cpu_features) || cpu::arm::NEON.available(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. @@ -200,7 +195,7 @@ fn chacha20_poly1305_open( let mut counter = Counter::zero(nonce); let mut auth = { let key = derive_poly1305_key(chacha20_key, counter.increment()); - poly1305::Context::from_key(key) + poly1305::Context::from_key(key, cpu_features) }; poly1305_update_padded_16(&mut auth, aad.as_ref()); @@ -258,7 +253,7 @@ fn poly1305_update_padded_16(ctx: &mut poly1305::Context, input: &[u8]) { 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, chacha_key.cpu_features()) + poly1305::Key::new(key_bytes) } #[cfg(test)] diff --git a/src/aead/chacha20_poly1305_openssh.rs b/src/aead/chacha20_poly1305_openssh.rs index 015d41787..306c9a89a 100644 --- a/src/aead/chacha20_poly1305_openssh.rs +++ b/src/aead/chacha20_poly1305_openssh.rs @@ -45,7 +45,7 @@ impl SealingKey { /// Constructs a new `SealingKey`. pub fn new(key_material: &[u8; KEY_LEN]) -> Self { Self { - key: Key::new(key_material, cpu::features()), + key: Key::new(key_material), } } @@ -62,6 +62,7 @@ impl SealingKey { plaintext_in_ciphertext_out: &mut [u8], tag_out: &mut [u8; TAG_LEN], ) { + let cpu_features = cpu::features(); let mut counter = make_counter(sequence_number); let poly_key = derive_poly1305_key(&self.key.k_2, counter.increment()); @@ -77,7 +78,7 @@ impl SealingKey { .encrypt_in_place(counter, data_and_padding_in_out); } - let Tag(tag) = poly1305::sign(poly_key, plaintext_in_ciphertext_out); + let Tag(tag) = poly1305::sign(poly_key, plaintext_in_ciphertext_out, cpu_features); tag_out.copy_from_slice(tag.as_ref()); } } @@ -91,7 +92,7 @@ impl OpeningKey { /// Constructs a new `OpeningKey`. pub fn new(key_material: &[u8; KEY_LEN]) -> Self { Self { - key: Key::new(key_material, cpu::features()), + key: Key::new(key_material), } } @@ -148,12 +149,12 @@ struct Key { } impl Key { - fn new(key_material: &[u8; KEY_LEN], cpu_features: cpu::Features) -> Self { + fn new(key_material: &[u8; KEY_LEN]) -> Self { // The first half becomes K_2 and the second half becomes K_1. let (k_2, k_1) = key_material.split_at(chacha::KEY_LEN); Self { - k_1: chacha::Key::new(k_1.try_into().unwrap(), cpu_features), - k_2: chacha::Key::new(k_2.try_into().unwrap(), cpu_features), + k_1: chacha::Key::new(k_1.try_into().unwrap()), + k_2: chacha::Key::new(k_2.try_into().unwrap()), } } } @@ -174,6 +175,6 @@ pub const PACKET_LENGTH_LEN: usize = 4; // 32 bits pub const TAG_LEN: usize = super::TAG_LEN; fn verify(key: poly1305::Key, msg: &[u8], tag: &[u8; TAG_LEN]) -> Result<(), error::Unspecified> { - let Tag(calculated_tag) = poly1305::sign(key, msg); + let Tag(calculated_tag) = poly1305::sign(key, msg, cpu::features()); constant_time::verify_slices_are_equal(calculated_tag.as_ref(), tag) } diff --git a/src/aead/gcm.rs b/src/aead/gcm.rs index 9fb20bc7e..2771113a1 100644 --- a/src/aead/gcm.rs +++ b/src/aead/gcm.rs @@ -25,7 +25,6 @@ mod gcm_nohw; #[derive(Clone)] pub struct Key { h_table: HTable, - cpu_features: cpu::Features, } impl Key { @@ -36,7 +35,6 @@ impl Key { h_table: HTable { Htable: [u128 { hi: 0, lo: 0 }; HTABLE_LEN], }, - cpu_features, }; let h_table = &mut key.h_table; @@ -92,13 +90,13 @@ pub struct Context { } impl Context { - pub(crate) fn new(key: &Key, aad: Aad<&[u8]>) -> Self { + pub(crate) fn new(key: &Key, aad: Aad<&[u8]>, cpu_features: cpu::Features) -> Self { let mut ctx = Self { inner: ContextInner { Xi: Xi(Block::zero()), Htable: key.h_table.clone(), }, - cpu_features: key.cpu_features, + 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 009bb3559..1762b5c90 100644 --- a/src/aead/less_safe_key.rs +++ b/src/aead/less_safe_key.rs @@ -171,7 +171,8 @@ fn open_within_<'in_out>( let ciphertext_len = in_out.get(src.clone()).ok_or(error::Unspecified)?.len(); check_per_nonce_max_bytes(key.algorithm, ciphertext_len)?; - let Tag(calculated_tag) = (key.algorithm.open)(&key.inner, nonce, aad, in_out, src); + let Tag(calculated_tag) = + (key.algorithm.open)(&key.inner, nonce, aad, in_out, src, cpu::features()); if constant_time::verify_slices_are_equal(calculated_tag.as_ref(), received_tag.as_ref()) .is_err() @@ -198,7 +199,13 @@ 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)) + Ok((key.algorithm.seal)( + &key.inner, + nonce, + aad, + in_out, + cpu::features(), + )) } fn check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified> { diff --git a/src/aead/poly1305.rs b/src/aead/poly1305.rs index f7c202c49..3817e1d2b 100644 --- a/src/aead/poly1305.rs +++ b/src/aead/poly1305.rs @@ -21,7 +21,6 @@ use crate::{c, cpu}; /// A Poly1305 key. pub(super) struct Key { key_and_nonce: [u8; KEY_LEN], - cpu_features: cpu::Features, } pub(super) const BLOCK_LEN: usize = 16; @@ -29,11 +28,8 @@ pub(super) const KEY_LEN: usize = 2 * BLOCK_LEN; impl Key { #[inline] - pub(super) fn new(key_and_nonce: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self { - Self { - key_and_nonce, - cpu_features, - } + pub(super) fn new(key_and_nonce: [u8; KEY_LEN]) -> Self { + Self { key_and_nonce } } } @@ -79,12 +75,7 @@ macro_rules! dispatch { impl Context { #[inline] - pub(super) fn from_key( - Key { - key_and_nonce, - cpu_features, - }: Key, - ) -> Self { + pub(super) fn from_key(Key { key_and_nonce }: Key, cpu_features: cpu::Features) -> Self { let mut ctx = Self { state: poly1305_state([0u8; OPAQUE_LEN]), cpu_features, @@ -123,8 +114,8 @@ impl Context { /// /// This is used by chacha20_poly1305_openssh and the standalone /// poly1305 test vectors. -pub(super) fn sign(key: Key, input: &[u8]) -> Tag { - let mut ctx = Context::from_key(key); +pub(super) fn sign(key: Key, input: &[u8], cpu_features: cpu::Features) -> Tag { + let mut ctx = Context::from_key(key, cpu_features); ctx.update(input); ctx.finish() } @@ -144,8 +135,8 @@ mod tests { let key: &[u8; KEY_LEN] = key.as_slice().try_into().unwrap(); let input = test_case.consume_bytes("Input"); let expected_mac = test_case.consume_bytes("MAC"); - let key = Key::new(*key, cpu_features); - let Tag(actual_mac) = sign(key, &input); + let key = Key::new(*key); + let Tag(actual_mac) = sign(key, &input, cpu_features); assert_eq!(expected_mac, actual_mac.as_ref()); Ok(()) diff --git a/src/aead/quic.rs b/src/aead/quic.rs index 9af4771ff..a5d2d738d 100644 --- a/src/aead/quic.rs +++ b/src/aead/quic.rs @@ -170,12 +170,9 @@ pub static CHACHA20: Algorithm = Algorithm { id: AlgorithmID::CHACHA20, }; -fn chacha20_init(key: &[u8], cpu_features: 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::new( - chacha20_key, - cpu_features, - ))) + Ok(KeyInner::ChaCha20(chacha::Key::new(chacha20_key))) } fn chacha20_new_mask(key: &KeyInner, sample: Sample) -> [u8; 5] {