From 34c10b0a0443e2e0a7d5d479a1c9a2ecca898e14 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 15 Jan 2025 13:02:03 -0800 Subject: [PATCH] chacha20_poly1305 internals: DRY per-packet initialization. Create a new function `begin` that is used by all the opening and sealing operations in both `chacha20_poly1305` and `chacha20_poly1305_openssh`. Inline `derive_poly1305_key` into it. --- src/aead/chacha20_poly1305.rs | 33 ++++++++++++--------------- src/aead/chacha20_poly1305_openssh.rs | 29 +++++++++++------------ 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/src/aead/chacha20_poly1305.rs b/src/aead/chacha20_poly1305.rs index 451a18d48..186afe0b2 100644 --- a/src/aead/chacha20_poly1305.rs +++ b/src/aead/chacha20_poly1305.rs @@ -13,7 +13,7 @@ // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use super::{ - chacha::{self, Counter, Iv, Overlapping}, + chacha::{self, Counter, Overlapping}, poly1305, Aad, Nonce, Tag, }; use crate::{ @@ -113,11 +113,8 @@ pub(super) fn seal( return Ok(Tag(out.tag)); } - let mut counter = Counter::zero(nonce); - let mut auth = { - let key = derive_poly1305_key(chacha20_key, counter.increment()); - poly1305::Context::from_key(key, cpu_features) - }; + let (counter, poly1305_key) = begin(chacha20_key, nonce); + let mut auth = poly1305::Context::from_key(poly1305_key, cpu_features); poly1305_update_padded_16(&mut auth, aad.as_ref()); chacha20_key.encrypt_in_place(counter, in_out); @@ -197,11 +194,8 @@ pub(super) fn open( return Ok(Tag(out.tag)); } - let mut counter = Counter::zero(nonce); - let mut auth = { - let key = derive_poly1305_key(chacha20_key, counter.increment()); - poly1305::Context::from_key(key, cpu_features) - }; + let (counter, poly1305_key) = begin(chacha20_key, nonce); + let mut auth = poly1305::Context::from_key(poly1305_key, cpu_features); poly1305_update_padded_16(&mut auth, aad.as_ref()); poly1305_update_padded_16(&mut auth, in_out.input()); @@ -228,6 +222,16 @@ fn has_integrated(cpu_features: cpu::Features) -> bool { } } +// Also used by chacha20_poly1305_openssh. +pub(super) fn begin(key: &chacha::Key, nonce: Nonce) -> (Counter, poly1305::Key) { + let mut counter = Counter::zero(nonce); + let iv = counter.increment(); + let mut key_bytes = [0u8; poly1305::KEY_LEN]; + key.encrypt_iv_xor_in_place(iv, &mut key_bytes); + let poly1305_key = poly1305::Key::new(key_bytes); + (counter, poly1305_key) +} + fn finish(mut auth: poly1305::Context, aad_len: usize, in_out_len: usize) -> Tag { let mut block = [0u8; poly1305::BLOCK_LEN]; let (alen, clen) = block.split_at_mut(poly1305::BLOCK_LEN / 2); @@ -285,10 +289,3 @@ 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) -> 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) -} diff --git a/src/aead/chacha20_poly1305_openssh.rs b/src/aead/chacha20_poly1305_openssh.rs index 027f1c300..a147e7947 100644 --- a/src/aead/chacha20_poly1305_openssh.rs +++ b/src/aead/chacha20_poly1305_openssh.rs @@ -31,8 +31,7 @@ use super::{ chacha::{self, *}, - chacha20_poly1305::derive_poly1305_key, - cpu, poly1305, Nonce, Tag, + chacha20_poly1305, cpu, poly1305, Nonce, Tag, }; use crate::{constant_time, error}; @@ -67,8 +66,8 @@ impl SealingKey { 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()); + let (counter, poly_key) = + chacha20_poly1305::begin(&self.key.k_2, make_nonce(sequence_number)); { let (len_in_out, data_and_padding_in_out) = @@ -134,13 +133,15 @@ impl OpeningKey { return Err(error::Unspecified); } - let mut counter = make_counter(sequence_number); + let cpu = cpu::features(); + let (counter, poly_key) = + chacha20_poly1305::begin(&self.key.k_2, make_nonce(sequence_number)); // 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()); - verify(poly_key, ciphertext_in_plaintext_out, tag)?; + let calculated_tag = poly1305::sign(poly_key, ciphertext_in_plaintext_out, cpu); + constant_time::verify_slices_are_equal(calculated_tag.as_ref(), tag)?; // Won't panic because the length was checked above. let plaintext_in_ciphertext_out = &mut ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..]; @@ -169,10 +170,15 @@ impl Key { } } -fn make_counter(sequence_number: u32) -> Counter { +fn make_nonce(sequence_number: u32) -> Nonce { let [s0, s1, s2, s3] = sequence_number.to_be_bytes(); let nonce = [0, 0, 0, 0, 0, 0, 0, 0, s0, s1, s2, s3]; - Counter::zero(Nonce::assume_unique_for_key(nonce)) + Nonce::assume_unique_for_key(nonce) +} + +fn make_counter(sequence_number: u32) -> Counter { + let nonce = make_nonce(sequence_number); + Counter::zero(nonce) } /// The length of key. @@ -183,8 +189,3 @@ pub const PACKET_LENGTH_LEN: usize = 4; // 32 bits /// The length in bytes of an authentication tag. 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, cpu::features()); - constant_time::verify_slices_are_equal(calculated_tag.as_ref(), tag) -}