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

aead-stream: move the remaining items from aead #647

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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 aead-stream/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ categories = ["cryptography", "no-std"]
rust-version = "1.81"

[dependencies]
aead = { version = "=0.6.0-rc.0", default-features = false, features = ["stream"] }
aead = { version = "=0.6.0-rc.0", default-features = false }

[features]
alloc = ["aead/alloc"]
309 changes: 300 additions & 9 deletions aead-stream/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@
#[cfg(feature = "alloc")]
extern crate alloc;

use aead::array::{
typenum::{Unsigned, U4, U5},
Array, ArraySize,
use aead::{
array::{
typenum::{Unsigned, U4, U5},
Array, ArraySize,
},
AeadCore, AeadInPlace, Buffer, Error, Result,
};
use aead::{AeadCore, AeadInPlace, Buffer, Error, Result};
use core::ops::Sub;
use core::ops::{AddAssign, Sub};

pub use aead;

pub use aead::{
stream::{Decryptor, Encryptor, NewStream, StreamPrimitive},
Key, KeyInit,
};
pub use aead::{Key, KeyInit};

#[cfg(feature = "alloc")]
use {aead::Payload, alloc::vec::Vec};

/// Nonce as used by a given AEAD construction and STREAM primitive.
pub type Nonce<A, S> = Array<u8, NonceSize<A, S>>;
Expand All @@ -27,6 +29,295 @@ pub type Nonce<A, S> = Array<u8, NonceSize<A, S>>;
pub type NonceSize<A, S> =
<<A as AeadCore>::NonceSize as Sub<<S as StreamPrimitive<A>>::NonceOverhead>>::Output;

/// Create a new STREAM from the provided AEAD.
pub trait NewStream<A>: StreamPrimitive<A>
where
A: AeadInPlace,
A::NonceSize: Sub<Self::NonceOverhead>,
NonceSize<A, Self>: ArraySize,
{
/// Create a new STREAM with the given key and nonce.
fn new(key: &Key<A>, nonce: &Nonce<A, Self>) -> Self
where
A: KeyInit,
Self: Sized,
{
Self::from_aead(A::new(key), nonce)
}

/// Create a new STREAM from the given AEAD cipher.
fn from_aead(aead: A, nonce: &Nonce<A, Self>) -> Self;
}

/// Low-level STREAM implementation.
///
/// This trait provides a particular "flavor" of STREAM, as there are
/// different ways the specifics of the construction can be implemented.
///
/// Deliberately immutable and stateless to permit parallel operation.
pub trait StreamPrimitive<A>
where
A: AeadInPlace,
A::NonceSize: Sub<Self::NonceOverhead>,
NonceSize<A, Self>: ArraySize,
{
/// Number of bytes this STREAM primitive requires from the nonce.
type NonceOverhead: ArraySize;

/// Type used as the STREAM counter.
type Counter: AddAssign + Copy + Default + Eq;

/// Value to use when incrementing the STREAM counter (i.e. one)
const COUNTER_INCR: Self::Counter;

/// Maximum value of the STREAM counter.
const COUNTER_MAX: Self::Counter;

/// Encrypt an AEAD message in-place at the given position in the STREAM.
fn encrypt_in_place(
&self,
position: Self::Counter,
last_block: bool,
associated_data: &[u8],
buffer: &mut dyn Buffer,
) -> Result<()>;

/// Decrypt an AEAD message in-place at the given position in the STREAM.
fn decrypt_in_place(
&self,
position: Self::Counter,
last_block: bool,
associated_data: &[u8],
buffer: &mut dyn Buffer,
) -> Result<()>;

/// Encrypt the given plaintext payload, and return the resulting
/// ciphertext as a vector of bytes.
#[cfg(feature = "alloc")]
fn encrypt<'msg, 'aad>(
&self,
position: Self::Counter,
last_block: bool,
plaintext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>> {
let payload = plaintext.into();
let mut buffer = Vec::with_capacity(payload.msg.len() + A::TagSize::to_usize());
buffer.extend_from_slice(payload.msg);
self.encrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
Ok(buffer)
}

/// Decrypt the given ciphertext slice, and return the resulting plaintext
/// as a vector of bytes.
#[cfg(feature = "alloc")]
fn decrypt<'msg, 'aad>(
&self,
position: Self::Counter,
last_block: bool,
ciphertext: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>> {
let payload = ciphertext.into();
let mut buffer = Vec::from(payload.msg);
self.decrypt_in_place(position, last_block, payload.aad, &mut buffer)?;
Ok(buffer)
}

/// Obtain [`Encryptor`] for this [`StreamPrimitive`].
fn encryptor(self) -> Encryptor<A, Self>
where
Self: Sized,
{
Encryptor::from_stream_primitive(self)
}

/// Obtain [`Decryptor`] for this [`StreamPrimitive`].
fn decryptor(self) -> Decryptor<A, Self>
where
Self: Sized,
{
Decryptor::from_stream_primitive(self)
}
}

/// Implement a stateful STREAM object (i.e. encryptor or decryptor)
macro_rules! impl_stream_object {
(
$name:ident,
$next_method:tt,
$next_in_place_method:tt,
$last_method:tt,
$last_in_place_method:tt,
$op:tt,
$in_place_op:tt,
$op_desc:expr,
$obj_desc:expr
) => {
#[doc = "Stateful STREAM object which can"]
#[doc = $op_desc]
#[doc = "AEAD messages one-at-a-time."]
#[doc = ""]
#[doc = "This corresponds to the "]
#[doc = $obj_desc]
#[doc = "object as defined in the paper"]
#[doc = "[Online Authenticated-Encryption and its Nonce-Reuse Misuse-Resistance][1]."]
#[doc = ""]
#[doc = "[1]: https://eprint.iacr.org/2015/189.pdf"]
#[derive(Debug)]
pub struct $name<A, S>
where
A: AeadInPlace,
S: StreamPrimitive<A>,
A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
NonceSize<A, S>: ArraySize,
{
/// Underlying STREAM primitive.
stream: S,

/// Current position in the STREAM.
position: S::Counter,
}

impl<A, S> $name<A, S>
where
A: AeadInPlace,
S: StreamPrimitive<A>,
A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
NonceSize<A, S>: ArraySize,
{
#[doc = "Create a"]
#[doc = $obj_desc]
#[doc = "object from the given AEAD key and nonce."]
pub fn new(key: &Key<A>, nonce: &Nonce<A, S>) -> Self
where
A: KeyInit,
S: NewStream<A>,
{
Self::from_stream_primitive(S::new(key, nonce))
}

#[doc = "Create a"]
#[doc = $obj_desc]
#[doc = "object from the given AEAD primitive."]
pub fn from_aead(aead: A, nonce: &Nonce<A, S>) -> Self
where
A: KeyInit,
S: NewStream<A>,
{
Self::from_stream_primitive(S::from_aead(aead, nonce))
}

#[doc = "Create a"]
#[doc = $obj_desc]
#[doc = "object from the given STREAM primitive."]
pub fn from_stream_primitive(stream: S) -> Self {
Self {
stream,
position: Default::default(),
}
}

#[doc = "Use the underlying AEAD to"]
#[doc = $op_desc]
#[doc = "the next AEAD message in this STREAM, returning the"]
#[doc = "result as a [`Vec`]."]
#[cfg(feature = "alloc")]
pub fn $next_method<'msg, 'aad>(
&mut self,
payload: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>> {
if self.position == S::COUNTER_MAX {
// Counter overflow. Note that the maximum counter value is
// deliberately disallowed, as it would preclude being able
// to encrypt a last block (i.e. with `$last_in_place_method`)
return Err(Error);
}

let result = self.stream.$op(self.position, false, payload)?;

// Note: overflow checked above
self.position += S::COUNTER_INCR;
Ok(result)
}

#[doc = "Use the underlying AEAD to"]
#[doc = $op_desc]
#[doc = "the next AEAD message in this STREAM in-place."]
pub fn $next_in_place_method(
&mut self,
associated_data: &[u8],
buffer: &mut dyn Buffer,
) -> Result<()> {
if self.position == S::COUNTER_MAX {
// Counter overflow. Note that the maximum counter value is
// deliberately disallowed, as it would preclude being able
// to encrypt a last block (i.e. with `$last_in_place_method`)
return Err(Error);
}

self.stream
.$in_place_op(self.position, false, associated_data, buffer)?;

// Note: overflow checked above
self.position += S::COUNTER_INCR;
Ok(())
}

#[doc = "Use the underlying AEAD to"]
#[doc = $op_desc]
#[doc = "the last AEAD message in this STREAM,"]
#[doc = "consuming the "]
#[doc = $obj_desc]
#[doc = "object in order to prevent further use."]
#[cfg(feature = "alloc")]
pub fn $last_method<'msg, 'aad>(
self,
payload: impl Into<Payload<'msg, 'aad>>,
) -> Result<Vec<u8>> {
self.stream.$op(self.position, true, payload)
}

#[doc = "Use the underlying AEAD to"]
#[doc = $op_desc]
#[doc = "the last AEAD message in this STREAM in-place,"]
#[doc = "consuming the "]
#[doc = $obj_desc]
#[doc = "object in order to prevent further use."]
pub fn $last_in_place_method(
self,
associated_data: &[u8],
buffer: &mut dyn Buffer,
) -> Result<()> {
self.stream
.$in_place_op(self.position, true, associated_data, buffer)
}
}
};
}

impl_stream_object!(
Encryptor,
encrypt_next,
encrypt_next_in_place,
encrypt_last,
encrypt_last_in_place,
encrypt,
encrypt_in_place,
"encrypt",
"ℰ STREAM encryptor"
);

impl_stream_object!(
Decryptor,
decrypt_next,
decrypt_next_in_place,
decrypt_last,
decrypt_last_in_place,
decrypt,
decrypt_in_place,
"decrypt",
"𝒟 STREAM decryptor"
);

/// STREAM encryptor instantiated with [`StreamBE32`] as the underlying
/// STREAM primitive.
pub type EncryptorBE32<A> = Encryptor<A, StreamBE32<A>>;
Expand Down