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

chacha: Change name/signature of encrypt_{in_place,within}. #2236

Merged
merged 3 commits into from
Jan 17, 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
2 changes: 1 addition & 1 deletion src/aead/aes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ fn encrypt_iv_xor_block_using_encrypt_block(
#[allow(dead_code)]
fn encrypt_iv_xor_block_using_ctr32(key: &impl EncryptCtr32, iv: Iv, mut block: Block) -> Block {
let mut ctr = Counter(iv.0); // This is OK because we're only encrypting one block.
key.ctr32_encrypt_within(Overlapping::in_place(&mut block), &mut ctr);
key.ctr32_encrypt_within(block.as_mut().into(), &mut ctr);
block
}

Expand Down
11 changes: 5 additions & 6 deletions src/aead/aes_gcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,10 +177,9 @@ pub(super) fn seal(
}
};
let (whole, remainder) = slice::as_chunks_mut(ramaining);
aes_key
.ctr32_encrypt_within(Overlapping::in_place(slice::flatten_mut(whole)), &mut ctr);
aes_key.ctr32_encrypt_within(slice::flatten_mut(whole).into(), &mut ctr);
auth.update_blocks(whole);
let remainder = OverlappingPartialBlock::new(Overlapping::in_place(remainder))
let remainder = OverlappingPartialBlock::new(remainder.into())
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
seal_finish(aes_key, auth, remainder, ctr, tag_iv)
}
Expand Down Expand Up @@ -220,7 +219,7 @@ pub(super) fn seal(
)
}
}
let remainder = OverlappingPartialBlock::new(Overlapping::in_place(remainder))
let remainder = OverlappingPartialBlock::new(remainder.into())
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
seal_finish(aes_key, auth, remainder, ctr, tag_iv)
}
Expand Down Expand Up @@ -268,11 +267,11 @@ fn seal_strided<A: aes::EncryptBlock + aes::EncryptCtr32, G: gcm::UpdateBlocks +
let (whole, remainder) = slice::as_chunks_mut(in_out);

for chunk in whole.chunks_mut(CHUNK_BLOCKS) {
aes_key.ctr32_encrypt_within(Overlapping::in_place(slice::flatten_mut(chunk)), &mut ctr);
aes_key.ctr32_encrypt_within(slice::flatten_mut(chunk).into(), &mut ctr);
auth.update_blocks(chunk);
}

let remainder = OverlappingPartialBlock::new(Overlapping::in_place(remainder))
let remainder = OverlappingPartialBlock::new(remainder.into())
.unwrap_or_else(|InputTooLongError { .. }| unreachable!());
seal_finish(aes_key, auth, remainder, ctr, tag_iv)
}
Expand Down
34 changes: 19 additions & 15 deletions src/aead/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::{overlapping, quic::Sample, Nonce};
use crate::cpu;

#[cfg(any(
test,
Expand Down Expand Up @@ -44,39 +45,36 @@ impl Key {
}

impl Key {
#[inline]
pub fn encrypt_in_place(&self, counter: Counter, in_out: &mut [u8]) {
self.encrypt_within(counter, Overlapping::in_place(in_out))
}

// Encrypts `in_out` with the counter 0 and returns counter 1,
// where the counter is derived from the nonce `nonce`.
#[inline]
pub fn encrypt_single_block_with_ctr_0<const N: usize>(
pub(super) fn encrypt_single_block_with_ctr_0<const N: usize>(
&self,
nonce: Nonce,
in_out: &mut [u8; N],
cpu: cpu::Features,
) -> Counter {
assert!(N <= BLOCK_LEN);
let (zero, one) = Counter::zero_one_less_safe(nonce);
self.encrypt_within(zero, Overlapping::in_place(in_out));
self.encrypt(zero, in_out.as_mut().into(), cpu);
one
}

#[inline]
pub fn new_mask(&self, sample: Sample) -> [u8; 5] {
let cpu = cpu::features(); // TODO: Remove this.
let (ctr, nonce) = sample.split_at(4);
let ctr = u32::from_le_bytes(ctr.try_into().unwrap());
let nonce = Nonce::assume_unique_for_key(nonce.try_into().unwrap());
let ctr = Counter::from_nonce_and_ctr(nonce, ctr);

let mut out: [u8; 5] = [0; 5];
self.encrypt_within(ctr, Overlapping::in_place(&mut out));
self.encrypt(ctr, out.as_mut().into(), cpu);
out
}

#[inline(always)]
pub fn encrypt_within(&self, counter: Counter, in_out: Overlapping<'_>) {
pub(super) fn encrypt(&self, counter: Counter, in_out: Overlapping<'_>, _cpu: cpu::Features) {
#[cfg(any(
all(target_arch = "aarch64", target_endian = "little"),
all(target_arch = "arm", target_endian = "little"),
Expand All @@ -95,7 +93,7 @@ impl Key {
all(target_arch = "aarch64", target_endian = "little"),
target_arch = "x86_64"
)))]
let in_out = Overlapping::in_place(in_out.copy_within());
let in_out = Overlapping::from(in_out.copy_within());

let (input, output, len) = in_out.into_input_output_len();

Expand Down Expand Up @@ -197,13 +195,15 @@ mod tests {
} else {
MAX_ALIGNMENT_AND_OFFSET_SUBSET
};
chacha20_test(max_offset, Key::encrypt_within);
chacha20_test(max_offset, Key::encrypt);
}

// Smoketest the fallback implementation.
#[test]
fn chacha20_test_fallback() {
chacha20_test(MAX_ALIGNMENT_AND_OFFSET_SUBSET, fallback::ChaCha20_ctr32);
chacha20_test(MAX_ALIGNMENT_AND_OFFSET_SUBSET, |key, ctr, in_out, _cpu| {
fallback::ChaCha20_ctr32(key, ctr, in_out)
});
}

// Verifies the encryption is successful when done on overlapping buffers.
Expand All @@ -215,8 +215,10 @@ mod tests {
// works around that.
fn chacha20_test(
max_alignment_and_offset: (usize, usize),
f: impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>),
f: impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>, cpu::Features),
) {
let cpu = cpu::features();

// Reuse a buffer to avoid slowing down the tests with allocations.
let mut buf = vec![0u8; 1300];

Expand Down Expand Up @@ -245,6 +247,7 @@ mod tests {
&output[..len],
&mut buf,
max_alignment_and_offset,
cpu,
&f,
);
}
Expand All @@ -261,7 +264,8 @@ mod tests {
expected: &[u8],
buf: &mut [u8],
(max_alignment, max_offset): (usize, usize),
f: &impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>),
cpu: cpu::Features,
f: &impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>, cpu::Features),
) {
const ARBITRARY: u8 = 123;

Expand All @@ -281,7 +285,7 @@ mod tests {
let in_out = Overlapping::new(buf, src)
.map_err(error::erase::<IndexError>)
.unwrap();
f(key, ctr, in_out);
f(key, ctr, in_out, cpu);
assert_eq!(&buf[..input.len()], expected)
}
}
Expand Down
19 changes: 10 additions & 9 deletions src/aead/chacha20_poly1305/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ pub(super) fn seal_fallback(
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
cpu_features: cpu::Features,
cpu: cpu::Features,
) -> Result<Tag, InputTooLongError> {
let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out)?;
let mut auth = poly1305::Context::from_key(poly1305_key, cpu_features);
let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out, cpu)?;
let mut auth = poly1305::Context::from_key(poly1305_key, cpu);

poly1305_update_padded_16(&mut auth, aad.as_ref());
chacha20_key.encrypt_in_place(counter, in_out);
chacha20_key.encrypt(counter, in_out.into(), cpu);
poly1305_update_padded_16(&mut auth, in_out);
Ok(finish(auth, aad.as_ref().len(), in_out.len()))
}
Expand Down Expand Up @@ -105,15 +105,15 @@ pub(super) fn open_fallback(
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: Overlapping<'_>,
cpu_features: cpu::Features,
cpu: cpu::Features,
) -> Result<Tag, InputTooLongError> {
let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out.input())?;
let mut auth = poly1305::Context::from_key(poly1305_key, cpu_features);
let (counter, poly1305_key) = begin(chacha20_key, nonce, aad, in_out.input(), cpu)?;
let mut auth = poly1305::Context::from_key(poly1305_key, cpu);

poly1305_update_padded_16(&mut auth, aad.as_ref());
poly1305_update_padded_16(&mut auth, in_out.input());
let in_out_len = in_out.len();
chacha20_key.encrypt_within(counter, in_out);
chacha20_key.encrypt(counter, in_out, cpu);
Ok(finish(auth, aad.as_ref().len(), in_out_len))
}

Expand All @@ -137,11 +137,12 @@ pub(super) fn begin(
nonce: Nonce,
aad: Aad<&[u8]>,
input: &[u8],
cpu: cpu::Features,
) -> 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 counter = key.encrypt_single_block_with_ctr_0(nonce, &mut key_bytes, cpu);
let poly1305_key = poly1305::Key::new(key_bytes);
Ok((counter, poly1305_key))
}
Expand Down
31 changes: 19 additions & 12 deletions src/aead/chacha20_poly1305_openssh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,28 @@
let (len_in_out, data_and_padding_in_out): (&mut [u8; PACKET_LENGTH_LEN], _) =
slice::split_first_chunk_mut(plaintext_in_ciphertext_out).unwrap();

let cpu_features = cpu::features();
let cpu = cpu::features();
// 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,
cpu,
)
.map_err(error::erase::<InputTooLongError>)
.unwrap();

let _: Counter = self
.key
.k_1
.encrypt_single_block_with_ctr_0(make_nonce(sequence_number), len_in_out);
let _: Counter = self.key.k_1.encrypt_single_block_with_ctr_0(
make_nonce(sequence_number),
len_in_out,
cpu,
);
self.key
.k_2
.encrypt_in_place(counter, data_and_padding_in_out);
.encrypt(counter, data_and_padding_in_out.into(), cpu);

let Tag(tag) = poly1305::sign(poly_key, plaintext_in_ciphertext_out, cpu_features);
let Tag(tag) = poly1305::sign(poly_key, plaintext_in_ciphertext_out, cpu);
*tag_out = tag;
}
}
Expand All @@ -123,11 +125,13 @@
sequence_number: u32,
encrypted_packet_length: [u8; PACKET_LENGTH_LEN],
) -> [u8; PACKET_LENGTH_LEN] {
let cpu = cpu::features();

Check warning on line 128 in src/aead/chacha20_poly1305_openssh.rs

View check run for this annotation

Codecov / codecov/patch

src/aead/chacha20_poly1305_openssh.rs#L128

Added line #L128 was not covered by tests
let mut packet_length = encrypted_packet_length;
let _: Counter = self
.key
.k_1
.encrypt_single_block_with_ctr_0(make_nonce(sequence_number), &mut packet_length);
let _: Counter = self.key.k_1.encrypt_single_block_with_ctr_0(
make_nonce(sequence_number),
&mut packet_length,
cpu,
);

Check warning on line 134 in src/aead/chacha20_poly1305_openssh.rs

View check run for this annotation

Codecov / codecov/patch

src/aead/chacha20_poly1305_openssh.rs#L130-L134

Added lines #L130 - L134 were not covered by tests
packet_length
}

Expand Down Expand Up @@ -155,6 +159,7 @@
make_nonce(sequence_number),
Aad::from(packet_length),
after_packet_length,
cpu,
)
.map_err(error::erase::<InputTooLongError>)?;

Expand All @@ -167,7 +172,9 @@
// Won't panic because the length was checked above.
let after_packet_length = &mut ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..];

self.key.k_2.encrypt_in_place(counter, after_packet_length);
self.key
.k_2
.encrypt(counter, after_packet_length.into(), cpu);

Ok(after_packet_length)
}
Expand Down
6 changes: 4 additions & 2 deletions src/aead/overlapping/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ pub struct Overlapping<'o, T> {
src: RangeFrom<usize>,
}

impl<'o, T> Overlapping<'o, T> {
pub fn in_place(in_out: &'o mut [T]) -> Self {
impl<'o, T> From<&'o mut [T]> for Overlapping<'o, T> {
fn from(in_out: &'o mut [T]) -> Self {
Self { in_out, src: 0.. }
}
}

impl<'o, T> Overlapping<'o, T> {
pub fn new(in_out: &'o mut [T], src: RangeFrom<usize>) -> Result<Self, IndexError> {
match in_out.get(src.clone()) {
Some(_) => Ok(Self { in_out, src }),
Expand Down