Skip to content

Commit

Permalink
chacha20-poly1305 internals: Start using Overlapping in open().
Browse files Browse the repository at this point in the history
  • Loading branch information
briansmith committed Jan 1, 2025
1 parent 800bb76 commit 6df99ff
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 55 deletions.
4 changes: 3 additions & 1 deletion src/aead/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use core::ops::RangeFrom;
use super::{
aes, aes_gcm, chacha20_poly1305,
nonce::{Nonce, NONCE_LEN},
overlapping::{Overlapping, SrcIndexError},
Aad, KeyInner, Tag, TAG_LEN,
};

Expand Down Expand Up @@ -259,5 +260,6 @@ fn chacha20_poly1305_open(
KeyInner::ChaCha20Poly1305(key) => key,
_ => unreachable!(),
};
chacha20_poly1305::open(key, nonce, aad, in_out, src, cpu_features)
let in_out = Overlapping::new(in_out, src).map_err(error::erase::<SrcIndexError>)?;
chacha20_poly1305::open(key, nonce, aad, in_out, cpu_features)
}
47 changes: 20 additions & 27 deletions src/aead/chacha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

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

#[cfg(any(
test,
Expand All @@ -27,7 +27,8 @@ use super::{quic::Sample, Nonce};
mod fallback;

use crate::polyfill::ArraySplitMap;
use core::ops::RangeFrom;

pub type Overlapping<'o> = overlapping::Overlapping<'o, u8>;

#[derive(Clone)]
pub struct Key {
Expand All @@ -45,7 +46,7 @@ impl Key {
impl Key {
#[inline]
pub fn encrypt_in_place(&self, counter: Counter, in_out: &mut [u8]) {
self.encrypt_within(counter, in_out, 0..);
self.encrypt_within(counter, Overlapping::in_place(in_out))
}

#[inline]
Expand All @@ -67,37 +68,26 @@ impl Key {
out
}

/// Analogous to `slice::copy_within()`.
#[inline(always)]
pub fn encrypt_within(&self, counter: Counter, in_out: &mut [u8], src: RangeFrom<usize>) {
pub fn encrypt_within(&self, counter: Counter, in_out: Overlapping<'_>) {
#[cfg(any(
target_arch = "aarch64",
target_arch = "arm",
target_arch = "x86",
target_arch = "x86_64"
))]
#[inline(always)]
pub(super) fn ChaCha20_ctr32(
key: &Key,
counter: Counter,
in_out: &mut [u8],
src: RangeFrom<usize>,
) {
let in_out_len = in_out.len().checked_sub(src.start).unwrap();

pub(super) fn ChaCha20_ctr32(key: &Key, counter: Counter, in_out: Overlapping<'_>) {
// XXX: The x86 and at least one branch of the ARM assembly language
// code doesn't allow overlapping input and output unless they are
// exactly overlapping. TODO: Figure out which branch of the ARM code
// has this limitation and come up with a better solution.
//
// https://rt.openssl.org/Ticket/Display.html?id=4362
let (output, input) =
if cfg!(any(target_arch = "aarch64", target_arch = "x86_64")) || src.start == 0 {
(in_out.as_mut_ptr(), in_out[src].as_ptr())
} else {
in_out.copy_within(src, 0);
(in_out.as_mut_ptr(), in_out.as_ptr())
};
#[cfg(not(any(target_arch = "aarch64", target_arch = "x86_64")))]
let in_out = Overlapping::in_place(in_out.copy_within());

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

// There's no need to worry if `counter` is incremented because it is
// owned here and we drop immediately after the call.
Expand All @@ -110,7 +100,7 @@ impl Key {
counter: &Counter,
);
}
unsafe { ChaCha20_ctr32(output, input, in_out_len, key.words_less_safe(), &counter) }
unsafe { ChaCha20_ctr32(output, input, len, key.words_less_safe(), &counter) }
}

#[cfg(not(any(
Expand All @@ -121,7 +111,7 @@ impl Key {
)))]
use fallback::ChaCha20_ctr32;

ChaCha20_ctr32(self, counter, in_out, src);
ChaCha20_ctr32(self, counter, in_out)
}

#[inline]
Expand Down Expand Up @@ -189,8 +179,8 @@ const BLOCK_LEN: usize = 64;
mod tests {
extern crate alloc;

use super::*;
use crate::test;
use super::{super::overlapping::SrcIndexError, *};
use crate::{error, test};
use alloc::vec;

const MAX_ALIGNMENT_AND_OFFSET: (usize, usize) = (15, 259);
Expand Down Expand Up @@ -232,7 +222,7 @@ mod tests {
// works around that.
fn chacha20_test(
max_alignment_and_offset: (usize, usize),
f: impl for<'k, 'i> Fn(&'k Key, Counter, &'i mut [u8], RangeFrom<usize>),
f: impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>),
) {
// Reuse a buffer to avoid slowing down the tests with allocations.
let mut buf = vec![0u8; 1300];
Expand Down Expand Up @@ -278,7 +268,7 @@ mod tests {
expected: &[u8],
buf: &mut [u8],
(max_alignment, max_offset): (usize, usize),
f: &impl for<'k, 'i> Fn(&'k Key, Counter, &'i mut [u8], RangeFrom<usize>),
f: &impl for<'k, 'o> Fn(&'k Key, Counter, Overlapping<'o>),
) {
const ARBITRARY: u8 = 123;

Expand All @@ -295,7 +285,10 @@ mod tests {
Nonce::try_assume_unique_for_key(nonce).unwrap(),
ctr,
);
f(key, ctr, buf, src);
let in_out = Overlapping::new(buf, src)
.map_err(error::erase::<SrcIndexError>)
.unwrap();
f(key, ctr, in_out);
assert_eq!(&buf[..input.len()], expected)
}
}
Expand Down
15 changes: 4 additions & 11 deletions src/aead/chacha/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@
// Adapted from the public domain, estream code by D. Bernstein.
// Adapted from the BoringSSL crypto/chacha/chacha.c.

use super::{Counter, Key, BLOCK_LEN};
use core::{mem::size_of, ops::RangeFrom};
use super::{Counter, Key, Overlapping, BLOCK_LEN};
use core::mem::size_of;

pub(super) fn ChaCha20_ctr32(
key: &Key,
counter: Counter,
in_out: &mut [u8],
src: RangeFrom<usize>,
) {
pub(super) fn ChaCha20_ctr32(key: &Key, counter: Counter, in_out: Overlapping<'_>) {
const SIGMA: [u32; 4] = [
u32::from_le_bytes(*b"expa"),
u32::from_le_bytes(*b"nd 3"),
Expand All @@ -39,9 +34,7 @@ pub(super) fn ChaCha20_ctr32(
key[6], key[7], counter[0], counter[1], counter[2], counter[3],
];

let mut in_out_len = in_out.len().checked_sub(src.start).unwrap();
let mut input = in_out[src].as_ptr();
let mut output = in_out.as_mut_ptr();
let (mut input, mut output, mut in_out_len) = in_out.into_input_output_len();

let mut buf = [0u8; BLOCK_LEN];
while in_out_len > 0 {
Expand Down
26 changes: 11 additions & 15 deletions src/aead/chacha20_poly1305.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::{
chacha::{self, Counter, Iv},
chacha::{self, Counter, Iv, Overlapping},
poly1305, Aad, Nonce, Tag,
};
use crate::{
cpu, error,
polyfill::{u64_from_usize, usize_from_u64_saturated},
};
use core::ops::RangeFrom;

pub(super) const KEY_LEN: usize = chacha::KEY_LEN;

Expand Down Expand Up @@ -126,17 +125,12 @@ pub(super) fn open(
key: &Key,
nonce: Nonce,
aad: Aad<&[u8]>,
in_out: &mut [u8],
src: RangeFrom<usize>,
in_out: Overlapping<'_>,
cpu_features: cpu::Features,
) -> Result<Tag, error::Unspecified> {
let Key(chacha20_key) = key;

let unprefixed_len = in_out
.len()
.checked_sub(src.start)
.ok_or(error::Unspecified)?;
if unprefixed_len > MAX_IN_OUT_LEN {
if in_out.len() > MAX_IN_OUT_LEN {
return Err(error::Unspecified);
}
// RFC 8439 Section 2.8 says the maximum AAD length is 2**64 - 1, which is
Expand Down Expand Up @@ -180,11 +174,12 @@ pub(super) fn open(
);
}

let (input, output, len) = in_out.into_input_output_len();
let out = unsafe {
chacha20_poly1305_open(
in_out.as_mut_ptr(),
in_out.as_ptr().add(src.start),
unprefixed_len,
output,
input,
len,
aad.as_ref().as_ptr(),
aad.as_ref().len(),
&mut data,
Expand All @@ -202,9 +197,10 @@ pub(super) fn open(
};

poly1305_update_padded_16(&mut auth, aad.as_ref());
poly1305_update_padded_16(&mut auth, &in_out[src.clone()]);
chacha20_key.encrypt_within(counter, in_out, src.clone());
Ok(finish(auth, aad.as_ref().len(), unprefixed_len))
poly1305_update_padded_16(&mut auth, in_out.input());
let in_out_len = in_out.len();
chacha20_key.encrypt_within(counter, in_out);
Ok(finish(auth, aad.as_ref().len(), in_out_len))
}

#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
Expand Down
25 changes: 24 additions & 1 deletion src/aead/overlapping/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use core::ops::RangeFrom;

pub struct Overlapping<'o, T> {
// Invariant: self.src.start <= in_out.len().
in_out: &'o mut [T],
src: RangeFrom<usize>,
}
Expand All @@ -31,6 +32,20 @@ impl<'o, T> Overlapping<'o, T> {
}
}

#[cfg(any(target_arch = "arm", target_arch = "x86"))]
pub fn copy_within(self) -> &'o mut [T]
where
T: Copy,
{
if self.src.start == 0 {
self.in_out
} else {
let len = self.len();
self.in_out.copy_within(self.src, 0);
&mut self.in_out[..len]
}
}

#[cfg(any(target_arch = "arm", target_arch = "x86"))]
pub fn into_slice_src_mut(self) -> (&'o mut [T], RangeFrom<usize>) {
(self.in_out, self.src)
Expand All @@ -39,8 +54,16 @@ impl<'o, T> Overlapping<'o, T> {

impl<T> Overlapping<'_, T> {
pub fn len(&self) -> usize {
self.in_out[self.src.clone()].len()
self.input().len()
}

pub fn input(&self) -> &[T] {
self.in_out.get(self.src.clone()).unwrap_or_else(|| {
// Ensured by invariant.
unreachable!()

Check warning on line 63 in src/aead/overlapping/base.rs

View check run for this annotation

Codecov / codecov/patch

src/aead/overlapping/base.rs#L62-L63

Added lines #L62 - L63 were not covered by tests
})
}

pub fn into_input_output_len(self) -> (*const T, *mut T, usize) {
let len = self.len();
let output = self.in_out.as_mut_ptr();
Expand Down

0 comments on commit 6df99ff

Please sign in to comment.