Skip to content

Commit 6288426

Browse files
committed
Add "aead::encrypt_fixed_length" and "aead::decrypt_fixed_length"
I wanted to suggest adding these two APIs which provide alternative ways to use aead in a no-alloc build environment, without using the heapless library. Instead it uses `GenericArray::{split, concat}` to put the tag at the end of the buffer. I liked using this API in the context when, a struct containing fixed length buffers is where we need to place the ciphertext. The mc-crypto-box trait is based closely on this aead trait, and that's where I got experience using this version of the `encrypt` function: https://github.com/mobilecoinofficial/mobilecoin/blob/master/crypto/box/src/traits.rs#L140 I thought I would propose this extension upstream here.
1 parent 42ebb8f commit 6288426

1 file changed

Lines changed: 126 additions & 3 deletions

File tree

aead/src/lib.rs

Lines changed: 126 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,10 @@ pub use generic_array::{self, typenum::consts};
3030
#[cfg(feature = "heapless")]
3131
pub use heapless;
3232

33-
use core::fmt;
34-
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
35-
3633
#[cfg(feature = "alloc")]
3734
use alloc::vec::Vec;
35+
use core::{fmt, ops::{Add, Sub}};
36+
use generic_array::{sequence::{Split, Concat}, typenum::{Sum, Diff, Unsigned}, ArrayLength, GenericArray};
3837

3938
/// Error type.
4039
///
@@ -231,6 +230,25 @@ pub trait AeadInPlace {
231230
Ok(())
232231
}
233232

233+
/// Encrypt the given buffer containing a plaintext message of fixed length.
234+
/// The result will include the encrypted buffer, followed by the tag, and
235+
/// also be fixed length.
236+
/// This can be used without relying on alloc or heapless
237+
fn encrypt_fixed_length<L>(
238+
&self,
239+
nonce: &GenericArray<u8, Self::NonceSize>,
240+
associated_data: &[u8],
241+
buffer: &GenericArray<u8, L>,
242+
) -> Result<GenericArray<u8, Sum<L, Self::TagSize>>, Error>
243+
where
244+
L: ArrayLength<u8> + Add<Self::TagSize>,
245+
Sum<L, Self::TagSize>: ArrayLength<u8>,
246+
{
247+
let mut buffer = buffer.clone();
248+
let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut_slice())?;
249+
Ok(buffer.concat(tag))
250+
}
251+
234252
/// Encrypt the data in-place, returning the authentication tag
235253
fn encrypt_in_place_detached(
236254
&self,
@@ -253,6 +271,27 @@ pub trait AeadInPlace {
253271
impl_decrypt_in_place!(self, nonce, associated_data, buffer)
254272
}
255273

274+
/// Decrypt the given buffer containing a ciphertext of fixed length, with
275+
/// a postfix tag.
276+
/// This can be used without relying on alloc or heapless
277+
fn decrypt_fixed_length<L>(
278+
&self,
279+
nonce: &GenericArray<u8, Self::NonceSize>,
280+
associated_data: &[u8],
281+
buffer: &GenericArray<u8, L>,
282+
) -> Result<GenericArray<u8, Diff<L, Self::TagSize>>, Error>
283+
where
284+
L: ArrayLength<u8>
285+
+ Sub<Self::TagSize>
286+
+ Sub<Diff<L, Self::TagSize>, Output = Self::TagSize>,
287+
Diff<L, Self::TagSize>: ArrayLength<u8>,
288+
{
289+
let (ciphertext, tag) = Split::<u8, Diff<L, Self::TagSize>>::split(buffer);
290+
let mut result = ciphertext.clone();
291+
self.decrypt_in_place_detached(nonce, associated_data, result.as_mut_slice(), tag)?;
292+
Ok(result)
293+
}
294+
256295
/// Decrypt the message in-place, returning an error in the event the provided
257296
/// authentication tag does not match the given ciphertext (i.e. ciphertext
258297
/// is modified/unauthentic)
@@ -299,6 +338,25 @@ pub trait AeadMutInPlace {
299338
Ok(())
300339
}
301340

341+
/// Encrypt the given buffer containing a plaintext message of fixed length.
342+
/// The result will include the encrypted buffer, followed by the tag, and
343+
/// also be fixed length.
344+
/// This can be used without relying on alloc or heapless
345+
fn encrypt_fixed_length<L>(
346+
&mut self,
347+
nonce: &GenericArray<u8, Self::NonceSize>,
348+
associated_data: &[u8],
349+
buffer: &GenericArray<u8, L>,
350+
) -> Result<GenericArray<u8, Sum<L, Self::TagSize>>, Error>
351+
where
352+
L: ArrayLength<u8> + Add<Self::TagSize>,
353+
Sum<L, Self::TagSize>: ArrayLength<u8>,
354+
{
355+
let mut buffer = buffer.clone();
356+
let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut_slice())?;
357+
Ok(buffer.concat(tag))
358+
}
359+
302360
/// Encrypt the data in-place, returning the authentication tag
303361
fn encrypt_in_place_detached(
304362
&mut self,
@@ -321,6 +379,27 @@ pub trait AeadMutInPlace {
321379
impl_decrypt_in_place!(self, nonce, associated_data, buffer)
322380
}
323381

382+
/// Decrypt the given buffer containing a ciphertext of fixed length, with
383+
/// a postfix tag.
384+
/// This can be used without relying on alloc or heapless
385+
fn decrypt_fixed_length<L>(
386+
&self,
387+
nonce: &GenericArray<u8, Self::NonceSize>,
388+
associated_data: &[u8],
389+
buffer: &GenericArray<u8, L>,
390+
) -> Result<GenericArray<u8, Diff<L, Self::TagSize>>, Error>
391+
where
392+
L: ArrayLength<u8>
393+
+ Sub<Self::TagSize>
394+
+ Sub<Diff<L, Self::TagSize>, Output = Self::TagSize>,
395+
Diff<L, Self::TagSize>: ArrayLength<u8>,
396+
{
397+
let (ciphertext, tag) = Split::<u8, Diff<L, Self::TagSize>>::split(buffer);
398+
let mut result = ciphertext.clone();
399+
self.decrypt_in_place_detached(nonce, associated_data, result.as_mut_slice(), tag)?;
400+
Ok(result)
401+
}
402+
324403
/// Decrypt the data in-place, returning an error in the event the provided
325404
/// authentication tag does not match the given ciphertext (i.e. ciphertext
326405
/// is modified/unauthentic)
@@ -407,6 +486,26 @@ impl<Alg: AeadInPlace> AeadMutInPlace for Alg {
407486
<Self as AeadInPlace>::encrypt_in_place(self, nonce, associated_data, buffer)
408487
}
409488

489+
/// Encrypt the given buffer containing a plaintext message of fixed length.
490+
/// The result will include the encrypted buffer, followed by the tag, and
491+
/// also be fixed length.
492+
/// This can be used without relying on alloc or heapless
493+
fn encrypt_fixed_length<L>(
494+
&mut self,
495+
nonce: &GenericArray<u8, Self::NonceSize>,
496+
associated_data: &[u8],
497+
buffer: &GenericArray<u8, L>,
498+
) -> Result<GenericArray<u8, Sum<L, Self::TagSize>>, Error>
499+
where
500+
L: ArrayLength<u8> + Add<Self::TagSize>,
501+
Sum<L, Self::TagSize>: ArrayLength<u8>,
502+
{
503+
let mut buffer = buffer.clone();
504+
let tag = self.encrypt_in_place_detached(nonce, associated_data, buffer.as_mut_slice())?;
505+
Ok(buffer.concat(tag))
506+
}
507+
508+
/// Encrypt the data in-place, returning the authentication tag
410509
fn encrypt_in_place_detached(
411510
&mut self,
412511
nonce: &Nonce<Self::NonceSize>,
@@ -425,6 +524,30 @@ impl<Alg: AeadInPlace> AeadMutInPlace for Alg {
425524
<Self as AeadInPlace>::decrypt_in_place(self, nonce, associated_data, buffer)
426525
}
427526

527+
/// Decrypt the given buffer containing a ciphertext of fixed length, with
528+
/// a postfix tag.
529+
/// This can be used without relying on alloc or heapless
530+
fn decrypt_fixed_length<L>(
531+
&mut self,
532+
nonce: &GenericArray<u8, Self::NonceSize>,
533+
associated_data: &[u8],
534+
buffer: &GenericArray<u8, L>,
535+
) -> Result<GenericArray<u8, Diff<L, Self::TagSize>>, Error>
536+
where
537+
L: ArrayLength<u8>
538+
+ Sub<Self::TagSize>
539+
+ Sub<Diff<L, Self::TagSize>, Output = Self::TagSize>,
540+
Diff<L, Self::TagSize>: ArrayLength<u8>,
541+
{
542+
let (ciphertext, tag) = Split::<u8, Diff<L, Self::TagSize>>::split(buffer);
543+
let mut result = ciphertext.clone();
544+
self.decrypt_in_place_detached(nonce, associated_data, result.as_mut_slice(), tag)?;
545+
Ok(result)
546+
}
547+
548+
/// Decrypt the data in-place, returning an error in the event the provided
549+
/// authentication tag does not match the given ciphertext (i.e. ciphertext
550+
/// is modified/unauthentic)
428551
fn decrypt_in_place_detached(
429552
&mut self,
430553
nonce: &Nonce<Self::NonceSize>,

0 commit comments

Comments
 (0)