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 e8fcc8e37..6ef86795a 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}; @@ -66,13 +65,13 @@ 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()); - let (len_in_out, data_and_padding_in_out) = plaintext_in_ciphertext_out.split_at_mut(PACKET_LENGTH_LEN); + let cpu_features = cpu::features(); + let (counter, poly_key) = + chacha20_poly1305::begin(&self.key.k_2, make_nonce(sequence_number)); + self.key .k_1 .encrypt_in_place(make_counter(sequence_number), len_in_out); @@ -132,13 +131,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 after_packet_length = &mut ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..]; @@ -165,10 +166,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. @@ -179,8 +185,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) -}