AEAD internals: Have each AEAD key type remember the CPU features.
Move the `cpu_features` field from `KeyInner` to the (inner) inner key types. This makes the AES-GCM code clearer.
This commit is contained in:
parent
4a0c4830af
commit
2be8976f70
@ -144,20 +144,13 @@ impl hkdf::KeyType for &'static Algorithm {
|
||||
pub struct Algorithm {
|
||||
init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>,
|
||||
|
||||
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<usize>,
|
||||
cpu_features: cpu::Features,
|
||||
) -> Tag,
|
||||
|
||||
key_len: usize,
|
||||
|
@ -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<usize>,
|
||||
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;
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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<aead::KeyInner, error::Unspecified> {
|
||||
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<usize>,
|
||||
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)]
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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<Tag, error::Unspecified> {
|
||||
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> {
|
||||
|
@ -171,9 +171,12 @@ pub static CHACHA20: Algorithm = Algorithm {
|
||||
id: AlgorithmID::CHACHA20,
|
||||
};
|
||||
|
||||
fn chacha20_init(key: &[u8], _todo: cpu::Features) -> Result<KeyInner, error::Unspecified> {
|
||||
fn chacha20_init(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified> {
|
||||
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] {
|
||||
|
Loading…
x
Reference in New Issue
Block a user