Skip to content

Commit 80dffed

Browse files
authored
aead: add AeadCore::TAG_POSITION and move AeadInPlace methods to AeadInOut (#1798)
1 parent 8efa5bd commit 80dffed

File tree

3 files changed

+113
-116
lines changed

3 files changed

+113
-116
lines changed

aead/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@ such as AES-GCM as ChaCha20Poly1305, which provide a high-level API
1717

1818
[dependencies]
1919
crypto-common = { version = "0.2.0-rc.1", path = "../crypto-common" }
20+
inout = "0.2.0-rc.4"
2021

2122
# optional dependencies
2223
arrayvec = { version = "0.7", optional = true, default-features = false }
2324
blobby = { version = "0.4.0-pre.0", optional = true }
2425
bytes = { version = "1", optional = true, default-features = false }
2526
heapless = { version = "0.8", optional = true, default-features = false }
26-
inout = { version = "0.2.0-rc.4", optional = true, default-features = false }
2727

2828
[features]
29-
default = ["inout", "rand_core"]
29+
default = ["rand_core"]
3030
alloc = []
3131
dev = ["blobby"]
3232
os_rng = ["crypto-common/os_rng", "rand_core"]

aead/src/lib.rs

Lines changed: 106 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,18 @@ pub use bytes;
3434
pub use crypto_common::rand_core;
3535
#[cfg(feature = "heapless")]
3636
pub use heapless;
37-
#[cfg(feature = "inout")]
3837
pub use inout;
3938

4039
use core::fmt;
41-
use crypto_common::array::{Array, ArraySize};
40+
use crypto_common::array::{Array, ArraySize, typenum::Unsigned};
41+
use inout::InOutBuf;
4242

4343
#[cfg(feature = "alloc")]
4444
use alloc::vec::Vec;
4545
#[cfg(feature = "bytes")]
4646
use bytes::BytesMut;
47-
#[cfg(any(feature = "alloc", feature = "inout"))]
48-
use crypto_common::array::typenum::Unsigned;
4947
#[cfg(feature = "os_rng")]
5048
use crypto_common::rand_core::{OsError, OsRng, TryRngCore};
51-
#[cfg(feature = "inout")]
52-
use inout::InOutBuf;
5349
#[cfg(feature = "rand_core")]
5450
use rand_core::{CryptoRng, TryCryptoRng};
5551

@@ -77,17 +73,26 @@ pub type Nonce<A> = Array<u8, <A as AeadCore>::NonceSize>;
7773
/// Tag: authentication code which ensures ciphertexts are authentic
7874
pub type Tag<A> = Array<u8, <A as AeadCore>::TagSize>;
7975

80-
/// Authenticated Encryption with Associated Data (AEAD) algorithm core trait.
81-
///
82-
/// Defines nonce, tag, and overhead sizes that are consumed by various other
83-
/// `Aead*` traits.
76+
/// Enum which specifies tag position used by an AEAD algorithm.
77+
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
78+
pub enum TagPosition {
79+
/// Postfix tag
80+
Postfix,
81+
/// Prefix tag
82+
Prefix,
83+
}
84+
85+
/// Authenticated Encryption with Associated Data (AEAD) algorithm.
8486
pub trait AeadCore {
8587
/// The length of a nonce.
8688
type NonceSize: ArraySize;
8789

8890
/// The maximum length of the tag.
8991
type TagSize: ArraySize;
9092

93+
/// The AEAD tag position.
94+
const TAG_POSITION: TagPosition;
95+
9196
/// Generate a random nonce for this AEAD algorithm.
9297
///
9398
/// AEAD algorithms accept a parameter to encryption/decryption called
@@ -155,6 +160,94 @@ pub trait AeadCore {
155160
}
156161
}
157162

163+
/// In-place and inout AEAD trait which handles the authentication tag as a return value/separate parameter.
164+
pub trait AeadInOut: AeadCore {
165+
/// Encrypt the data in the provided [`InOutBuf`], returning the authentication tag.
166+
fn encrypt_inout_detached(
167+
&self,
168+
nonce: &Nonce<Self>,
169+
associated_data: &[u8],
170+
buffer: InOutBuf<'_, '_, u8>,
171+
) -> Result<Tag<Self>>;
172+
173+
/// Decrypt the data in the provided [`InOutBuf`], returning an error in the event the
174+
/// provided authentication tag is invalid for the given ciphertext (i.e. ciphertext
175+
/// is modified/unauthentic)
176+
fn decrypt_inout_detached(
177+
&self,
178+
nonce: &Nonce<Self>,
179+
associated_data: &[u8],
180+
buffer: InOutBuf<'_, '_, u8>,
181+
tag: &Tag<Self>,
182+
) -> Result<()>;
183+
184+
/// Encrypt the given buffer containing a plaintext message in-place.
185+
///
186+
/// The buffer must have sufficient capacity to store the ciphertext
187+
/// message, which will always be larger than the original plaintext.
188+
/// The exact size needed is cipher-dependent, but generally includes
189+
/// the size of an authentication tag.
190+
///
191+
/// Returns an error if the buffer has insufficient capacity to store the
192+
/// resulting ciphertext message.
193+
fn encrypt_in_place(
194+
&self,
195+
nonce: &Nonce<Self>,
196+
associated_data: &[u8],
197+
buffer: &mut dyn Buffer,
198+
) -> Result<()> {
199+
match Self::TAG_POSITION {
200+
TagPosition::Prefix => {
201+
let msg_len = buffer.len();
202+
buffer.extend_from_slice(&Tag::<Self>::default())?;
203+
let buffer = buffer.as_mut();
204+
let tag_size = Self::TagSize::USIZE;
205+
buffer.copy_within(..msg_len, tag_size);
206+
let (tag_dst, msg) = buffer.split_at_mut(tag_size);
207+
let tag = self.encrypt_inout_detached(nonce, associated_data, msg.into())?;
208+
tag_dst.copy_from_slice(&tag);
209+
}
210+
TagPosition::Postfix => {
211+
let tag =
212+
self.encrypt_inout_detached(nonce, associated_data, buffer.as_mut().into())?;
213+
buffer.extend_from_slice(tag.as_slice())?;
214+
}
215+
}
216+
Ok(())
217+
}
218+
219+
/// Decrypt the message in-place, returning an error in the event the
220+
/// provided authentication tag does not match the given ciphertext.
221+
///
222+
/// The buffer will be truncated to the length of the original plaintext
223+
/// message upon success.
224+
fn decrypt_in_place(
225+
&self,
226+
nonce: &Nonce<Self>,
227+
associated_data: &[u8],
228+
buffer: &mut dyn Buffer,
229+
) -> Result<()> {
230+
let tag_size = Self::TagSize::USIZE;
231+
let tagless_len = buffer.len().checked_sub(tag_size).ok_or(Error)?;
232+
233+
match Self::TAG_POSITION {
234+
TagPosition::Prefix => {
235+
let (tag, msg) = buffer.as_mut().split_at_mut(tag_size);
236+
let tag = Tag::<Self>::try_from(&*tag).expect("tag length mismatch");
237+
self.decrypt_inout_detached(nonce, associated_data, msg.into(), &tag)?;
238+
buffer.as_mut().copy_within(tag_size.., 0);
239+
}
240+
TagPosition::Postfix => {
241+
let (msg, tag) = buffer.as_mut().split_at_mut(tagless_len);
242+
let tag = Tag::<Self>::try_from(&*tag).expect("tag length mismatch");
243+
self.decrypt_inout_detached(nonce, associated_data, msg.into(), &tag)?;
244+
}
245+
}
246+
buffer.truncate(tagless_len);
247+
Ok(())
248+
}
249+
}
250+
158251
/// Authenticated Encryption with Associated Data (AEAD) algorithm.
159252
#[cfg(feature = "alloc")]
160253
pub trait Aead: AeadCore {
@@ -211,70 +304,8 @@ pub trait Aead: AeadCore {
211304
) -> Result<Vec<u8>>;
212305
}
213306

214-
/// In-place AEAD trait.
215-
///
216-
/// This trait is both object safe and has no dependencies on `alloc` or `std`.
217-
pub trait AeadInPlace: AeadCore {
218-
/// Encrypt the given buffer containing a plaintext message in-place.
219-
///
220-
/// The buffer must have sufficient capacity to store the ciphertext
221-
/// message, which will always be larger than the original plaintext.
222-
/// The exact size needed is cipher-dependent, but generally includes
223-
/// the size of an authentication tag.
224-
///
225-
/// Returns an error if the buffer has insufficient capacity to store the
226-
/// resulting ciphertext message.
227-
fn encrypt_in_place(
228-
&self,
229-
nonce: &Nonce<Self>,
230-
associated_data: &[u8],
231-
buffer: &mut dyn Buffer,
232-
) -> Result<()>;
233-
234-
/// Decrypt the message in-place, returning an error in the event the
235-
/// provided authentication tag does not match the given ciphertext.
236-
///
237-
/// The buffer will be truncated to the length of the original plaintext
238-
/// message upon success.
239-
fn decrypt_in_place(
240-
&self,
241-
nonce: &Nonce<Self>,
242-
associated_data: &[u8],
243-
buffer: &mut dyn Buffer,
244-
) -> Result<()>;
245-
}
246-
247-
/// In-place AEAD trait which handles the authentication tag as a return value/separate parameter.
248-
#[cfg(feature = "inout")]
249-
pub trait AeadInOut: AeadCore {
250-
/// Encrypt the data in the provided [`InOutBuf`], returning the authentication tag.
251-
fn encrypt_inout_detached(
252-
&self,
253-
nonce: &Nonce<Self>,
254-
associated_data: &[u8],
255-
buffer: InOutBuf<'_, '_, u8>,
256-
) -> Result<Tag<Self>>;
257-
258-
/// Decrypt the data in the provided [`InOutBuf`], returning an error in the event the
259-
/// provided authentication tag is invalid for the given ciphertext (i.e. ciphertext
260-
/// is modified/unauthentic)
261-
fn decrypt_inout_detached(
262-
&self,
263-
nonce: &Nonce<Self>,
264-
associated_data: &[u8],
265-
buffer: InOutBuf<'_, '_, u8>,
266-
tag: &Tag<Self>,
267-
) -> Result<()>;
268-
}
269-
270-
/// Marker trait for AEAD algorithms which append the authentication tag to the end of the
271-
/// ciphertext message.
272-
///
273-
/// This is the common convention for AEAD algorithms.
274-
pub trait PostfixTagged {}
275-
276307
#[cfg(feature = "alloc")]
277-
impl<Alg: AeadInPlace> Aead for Alg {
308+
impl<T: AeadInOut> Aead for T {
278309
fn encrypt<'msg, 'aad>(
279310
&self,
280311
nonce: &Nonce<Self>,
@@ -299,39 +330,6 @@ impl<Alg: AeadInPlace> Aead for Alg {
299330
}
300331
}
301332

302-
#[cfg(feature = "inout")]
303-
impl<T: AeadInOut + PostfixTagged> AeadInPlace for T {
304-
fn encrypt_in_place(
305-
&self,
306-
nonce: &Nonce<Self>,
307-
associated_data: &[u8],
308-
buffer: &mut dyn Buffer,
309-
) -> Result<()> {
310-
let tag = self.encrypt_inout_detached(nonce, associated_data, buffer.as_mut().into())?;
311-
buffer.extend_from_slice(tag.as_slice())?;
312-
Ok(())
313-
}
314-
315-
fn decrypt_in_place(
316-
&self,
317-
nonce: &Nonce<Self>,
318-
associated_data: &[u8],
319-
buffer: &mut dyn Buffer,
320-
) -> Result<()> {
321-
let tag_pos = buffer
322-
.len()
323-
.checked_sub(Self::TagSize::to_usize())
324-
.ok_or(Error)?;
325-
326-
let (msg, tag) = buffer.as_mut().split_at_mut(tag_pos);
327-
let tag = Tag::<Self>::try_from(&*tag).expect("tag length mismatch");
328-
329-
self.decrypt_inout_detached(nonce, associated_data, msg.into(), &tag)?;
330-
buffer.truncate(tag_pos);
331-
Ok(())
332-
}
333-
}
334-
335333
/// AEAD payloads (message + AAD).
336334
///
337335
/// Combination of a message (plaintext or ciphertext) and
@@ -340,7 +338,6 @@ impl<T: AeadInOut + PostfixTagged> AeadInPlace for T {
340338
///
341339
/// If you don't care about AAD, you can pass a `&[u8]` as the payload to
342340
/// `encrypt`/`decrypt` and it will automatically be coerced to this type.
343-
#[cfg(feature = "alloc")]
344341
#[derive(Debug)]
345342
pub struct Payload<'msg, 'aad> {
346343
/// Message to be encrypted/decrypted
@@ -353,7 +350,6 @@ pub struct Payload<'msg, 'aad> {
353350
pub aad: &'aad [u8],
354351
}
355352

356-
#[cfg(feature = "alloc")]
357353
impl<'msg> From<&'msg [u8]> for Payload<'msg, '_> {
358354
fn from(msg: &'msg [u8]) -> Self {
359355
Self { msg, aad: b"" }
@@ -436,11 +432,12 @@ impl<const N: usize> Buffer for heapless::Vec<u8, N> {
436432
}
437433
}
438434

435+
#[cfg(feature = "alloc")]
439436
#[cfg(test)]
440437
mod tests {
441438
use super::*;
442439

443440
/// Ensure that `AeadInPlace` is object-safe
444441
#[allow(dead_code)]
445-
type DynAeadInPlace<N, T> = dyn AeadInPlace<NonceSize = N, TagSize = T>;
442+
type DynAeadInPlace<N, T> = dyn Aead<NonceSize = N, TagSize = T>;
446443
}

aead/src/stream.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
#![allow(clippy::upper_case_acronyms)]
88

9-
use crate::{AeadCore, AeadInPlace, Buffer, Error, Key, KeyInit, Result};
9+
use crate::{AeadCore, AeadInOut, Buffer, Error, Key, KeyInit, Result};
1010
use core::ops::{AddAssign, Sub};
1111
use crypto_common::array::{Array, ArraySize};
1212

@@ -24,7 +24,7 @@ pub type NonceSize<A, S> =
2424
/// Create a new STREAM from the provided AEAD.
2525
pub trait NewStream<A>: StreamPrimitive<A>
2626
where
27-
A: AeadInPlace,
27+
A: AeadInOut,
2828
A::NonceSize: Sub<Self::NonceOverhead>,
2929
NonceSize<A, Self>: ArraySize,
3030
{
@@ -49,7 +49,7 @@ where
4949
/// Deliberately immutable and stateless to permit parallel operation.
5050
pub trait StreamPrimitive<A>
5151
where
52-
A: AeadInPlace,
52+
A: AeadInOut,
5353
A::NonceSize: Sub<Self::NonceOverhead>,
5454
NonceSize<A, Self>: ArraySize,
5555
{
@@ -157,7 +157,7 @@ macro_rules! impl_stream_object {
157157
#[derive(Debug)]
158158
pub struct $name<A, S>
159159
where
160-
A: AeadInPlace,
160+
A: AeadInOut,
161161
S: StreamPrimitive<A>,
162162
A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
163163
NonceSize<A, S>: ArraySize,
@@ -171,7 +171,7 @@ macro_rules! impl_stream_object {
171171

172172
impl<A, S> $name<A, S>
173173
where
174-
A: AeadInPlace,
174+
A: AeadInOut,
175175
S: StreamPrimitive<A>,
176176
A::NonceSize: Sub<<S as StreamPrimitive<A>>::NonceOverhead>,
177177
NonceSize<A, S>: ArraySize,

0 commit comments

Comments
 (0)