Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chacha20_poly1305 internals: DRY per-packet initialization. #2230

Merged
merged 2 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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);

Check warning on line 117 in src/aead/chacha20_poly1305.rs

View check run for this annotation

Codecov / codecov/patch

src/aead/chacha20_poly1305.rs#L116-L117

Added lines #L116 - L117 were not covered by tests

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 @@
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);

Check warning on line 198 in src/aead/chacha20_poly1305.rs

View check run for this annotation

Codecov / codecov/patch

src/aead/chacha20_poly1305.rs#L197-L198

Added lines #L197 - L198 were not covered by tests

poly1305_update_padded_16(&mut auth, aad.as_ref());
poly1305_update_padded_16(&mut auth, in_out.input());
Expand All @@ -228,6 +222,16 @@
}
}

// 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 @@
}
}
}

// 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)
}
51 changes: 25 additions & 26 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 @@ -66,21 +65,19 @@ impl SealingKey {
plaintext_in_ciphertext_out: &mut [u8],
tag_out: &mut [u8; TAG_LEN],
) {
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 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);

self.key
.k_1
.encrypt_in_place(make_counter(sequence_number), len_in_out);
self.key
.k_2
.encrypt_in_place(counter, data_and_padding_in_out);
}
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);
self.key
.k_2
.encrypt_in_place(counter, data_and_padding_in_out);

let Tag(tag) = poly1305::sign(poly_key, plaintext_in_ciphertext_out, cpu_features);
*tag_out = tag;
Expand Down Expand Up @@ -134,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 plaintext_in_ciphertext_out = &mut ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..];
Expand Down Expand Up @@ -169,10 +168,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 +187,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)
}