Skip to content

Commit

Permalink
chacha20_poly1305_openssh: Enforce maximum input lengths.
Browse files Browse the repository at this point in the history
  • Loading branch information
briansmith committed Jan 17, 2025
1 parent 9725878 commit 404b106
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 15 deletions.
17 changes: 11 additions & 6 deletions src/aead/chacha20_poly1305/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ pub(super) fn seal_fallback(
in_out: &mut [u8],
cpu_features: cpu::Features,
) -> Result<Tag, InputTooLongError> {
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());
Expand Down Expand Up @@ -108,8 +107,7 @@ pub(super) fn open_fallback(
in_out: Overlapping<'_>,
cpu_features: cpu::Features,
) -> Result<Tag, InputTooLongError> {
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());
Expand All @@ -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 {
Expand Down
37 changes: 28 additions & 9 deletions src/aead/chacha20_poly1305_openssh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand All @@ -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::<InputTooLongError>)
.unwrap();

let _: Counter = self
.key
Expand Down Expand Up @@ -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::<InputTooLongError>)?;

// We must verify the tag before decrypting so that
// `ciphertext_in_plaintext_out` is unmodified if verification fails.
Expand Down

0 comments on commit 404b106

Please sign in to comment.