diff --git a/src/aead/chacha20_poly1305/mod.rs b/src/aead/chacha20_poly1305/mod.rs index b2506d46a..c45de4b0a 100644 --- a/src/aead/chacha20_poly1305/mod.rs +++ b/src/aead/chacha20_poly1305/mod.rs @@ -73,8 +73,7 @@ pub(super) fn seal_fallback( in_out: &mut [u8], cpu_features: cpu::Features, ) -> Result { - check_input_lengths(aad, in_out)?; - let (counter, poly1305_key) = begin(chacha20_key, nonce); + let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out)?; let mut auth = poly1305::Context::from_key(poly1305_key, cpu_features); poly1305_update_padded_16(&mut auth, aad.as_ref()); @@ -108,8 +107,7 @@ pub(super) fn open_fallback( in_out: Overlapping<'_>, cpu_features: cpu::Features, ) -> Result { - check_input_lengths(aad, in_out.input())?; - let (counter, poly1305_key) = begin(chacha20_key, nonce); + let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out.input())?; let mut auth = poly1305::Context::from_key(poly1305_key, cpu_features); poly1305_update_padded_16(&mut auth, aad.as_ref()); @@ -134,11 +132,18 @@ fn check_input_lengths(aad: Aad<&[u8]>, input: &[u8]) -> Result<(), InputTooLong } // Also used by chacha20_poly1305_openssh. -pub(super) fn begin(key: &chacha::Key, nonce: Nonce) -> (Counter, poly1305::Key) { +pub(super) fn begin( + key: &chacha::Key, + nonce: Nonce, + aad: Aad<&[u8]>, + input: &[u8], +) -> Result<(Counter, poly1305::Key), InputTooLongError> { + check_input_lengths(aad, input)?; + let mut key_bytes = [0u8; poly1305::KEY_LEN]; let counter = key.encrypt_single_block_with_ctr_0(nonce, &mut key_bytes); let poly1305_key = poly1305::Key::new(key_bytes); - (counter, poly1305_key) + Ok((counter, poly1305_key)) } fn finish(mut auth: poly1305::Context, aad_len: usize, in_out_len: usize) -> Tag { diff --git a/src/aead/chacha20_poly1305_openssh.rs b/src/aead/chacha20_poly1305_openssh.rs index f1993b053..cc6a19237 100644 --- a/src/aead/chacha20_poly1305_openssh.rs +++ b/src/aead/chacha20_poly1305_openssh.rs @@ -31,9 +31,13 @@ use super::{ chacha::{self, *}, - chacha20_poly1305, cpu, poly1305, Nonce, Tag, + chacha20_poly1305, cpu, poly1305, Aad, Nonce, Tag, +}; +use crate::{ + constant_time, + error::{self, InputTooLongError}, + polyfill::slice, }; -use crate::{constant_time, error, polyfill::slice}; /// A key for sealing packets. pub struct SealingKey { @@ -59,6 +63,10 @@ impl SealingKey { /// # Panics /// /// Panics if `plaintext_in_ciphertext_out.len() < PACKET_LENGTH_LEN`. + /// + /// Panics if `plaintext_in_ciphertext_out` is longer than the maximum + /// input size for ChaCha20-Poly1305. Note that this limit is much, + /// much larger than SSH's 256KB maximum record size. pub fn seal_in_place( &self, sequence_number: u32, @@ -70,8 +78,15 @@ impl SealingKey { slice::split_first_chunk_mut(plaintext_in_ciphertext_out).unwrap(); let cpu_features = cpu::features(); - let (counter, poly_key) = - chacha20_poly1305::begin(&self.key.k_2, make_nonce(sequence_number)); + // XXX/TODO(SemVer): Refactor API to return an error. + let (counter, poly_key) = chacha20_poly1305::begin( + &self.key.k_2, + make_nonce(sequence_number), + Aad::from(len_in_out), + data_and_padding_in_out, + ) + .map_err(error::erase::) + .unwrap(); let _: Counter = self .key @@ -131,13 +146,17 @@ impl OpeningKey { ciphertext_in_plaintext_out: &'a mut [u8], tag: &[u8; TAG_LEN], ) -> Result<&'a [u8], error::Unspecified> { - if ciphertext_in_plaintext_out.len() < PACKET_LENGTH_LEN { - return Err(error::Unspecified); - } + let (packet_length, after_packet_length): (&mut [u8; PACKET_LENGTH_LEN], _) = + slice::split_first_chunk_mut(ciphertext_in_plaintext_out).ok_or(error::Unspecified)?; let cpu = cpu::features(); - let (counter, poly_key) = - chacha20_poly1305::begin(&self.key.k_2, make_nonce(sequence_number)); + let (counter, poly_key) = chacha20_poly1305::begin( + &self.key.k_2, + make_nonce(sequence_number), + Aad::from(packet_length), + after_packet_length, + ) + .map_err(error::erase::)?; // We must verify the tag before decrypting so that // `ciphertext_in_plaintext_out` is unmodified if verification fails.