Skip to content

Commit

Permalink
chacha20_poly1305 internals: DRY per-packet initialization.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
briansmith committed Jan 16, 2025
1 parent f2116eb commit 34c10b0
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 32 deletions.
33 changes: 15 additions & 18 deletions src/aead/chacha20_poly1305.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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());
Expand All @@ -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);
Expand Down Expand Up @@ -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)
}
29 changes: 15 additions & 14 deletions src/aead/chacha20_poly1305_openssh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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) =
Expand Down Expand Up @@ -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..];
Expand Down Expand Up @@ -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.
Expand All @@ -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)
}

0 comments on commit 34c10b0

Please sign in to comment.