KeyInit for Ascon {
impl AeadCore for Ascon {
type NonceSize = U16;
type TagSize = U16;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
-impl PostfixTagged for Ascon {}
-
-impl AeadInPlaceDetached for Ascon {
- fn encrypt_in_place_detached(
+impl AeadInOut for Ascon {
+ fn encrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> Result, Error> {
if (buffer.len() as u64)
.checked_add(associated_data.len() as u64)
@@ -154,14 +153,14 @@ impl AeadInPlaceDetached for Ascon {
}
let mut core = AsconCore::
::new(&self.key, nonce);
- Ok(core.encrypt_inplace(buffer, associated_data))
+ Ok(core.encrypt_inout(buffer, associated_data))
}
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
if (buffer.len() as u64)
@@ -172,7 +171,7 @@ impl AeadInPlaceDetached for Ascon {
}
let mut core = AsconCore::
::new(&self.key, nonce);
- core.decrypt_inplace(buffer, associated_data, tag)
+ core.decrypt_inout(buffer, associated_data, tag)
}
}
@@ -198,31 +197,30 @@ impl KeyInit for AsconAead128 {
impl AeadCore for AsconAead128 {
type NonceSize = U16;
type TagSize = U16;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
-impl PostfixTagged for AsconAead128 {}
-
-impl AeadInPlaceDetached for AsconAead128 {
+impl AeadInOut for AsconAead128 {
#[inline(always)]
- fn encrypt_in_place_detached(
+ fn encrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> Result, Error> {
self.0
- .encrypt_in_place_detached(nonce, associated_data, buffer)
+ .encrypt_inout_detached(nonce, associated_data, buffer)
}
#[inline(always)]
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
self.0
- .decrypt_in_place_detached(nonce, associated_data, buffer, tag)
+ .decrypt_inout_detached(nonce, associated_data, buffer, tag)
}
}
diff --git a/ascon-aead/tests/kats_test.rs b/ascon-aead/tests/kats_test.rs
index a364393d..dedf9341 100644
--- a/ascon-aead/tests/kats_test.rs
+++ b/ascon-aead/tests/kats_test.rs
@@ -3,11 +3,11 @@
use ascon_aead::{
AsconAead128,
- aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, Tag},
+ aead::{Aead, AeadInOut, KeyInit, Payload, Tag, dev::MockBuffer},
};
use hex_literal::hex;
-fn run_tv(
+fn run_tv(
key: &[u8],
nonce: &[u8],
plaintext: &[u8],
@@ -40,9 +40,28 @@ fn run_tv(
let bad_tag = Tag::::default();
let mut buf = ciphertext[..ciphertext.len() - bad_tag.len()].to_vec();
- let res = core.decrypt_in_place_detached(nonce, associated_data, &mut buf, &bad_tag);
+ let res =
+ core.decrypt_inout_detached(nonce, associated_data, buf.as_mut_slice().into(), &bad_tag);
assert!(res.is_err());
assert!(buf.iter().all(|b| *b == 0));
+
+ let mut buf = MockBuffer::from(&plaintext[..ciphertext.len() - bad_tag.len()]);
+ let tag_encryption = core
+ .encrypt_inout_detached(nonce, associated_data, buf.to_in_out_buf())
+ .expect("encryption failed");
+ assert_eq!(
+ tag_encryption.as_slice(),
+ &ciphertext[ciphertext.len() - bad_tag.len()..]
+ );
+ assert_eq!(
+ buf.as_ref(),
+ &ciphertext[..ciphertext.len() - bad_tag.len()]
+ );
+
+ let mut buf = MockBuffer::from(&ciphertext[..ciphertext.len() - bad_tag.len()]);
+ core.decrypt_inout_detached(nonce, associated_data, buf.to_in_out_buf(), &tag_encryption)
+ .expect("decryption failed");
+ assert_eq!(buf.as_ref(), plaintext);
}
#[test]
diff --git a/ccm/src/lib.rs b/ccm/src/lib.rs
index bd51999b..a75e094f 100644
--- a/ccm/src/lib.rs
+++ b/ccm/src/lib.rs
@@ -42,12 +42,13 @@
//! [aead]: https://docs.rs/aead
//! [1]: https://en.wikipedia.org/wiki/Authenticated_encryption
-pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser, consts};
+pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, consts};
use aead::{
- PostfixTagged,
+ TagPosition,
array::{Array, ArraySize, typenum::Unsigned},
consts::U16,
+ inout::InOutBuf,
};
use cipher::{
Block, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipher, StreamCipherSeek,
@@ -211,29 +212,22 @@ where
{
type NonceSize = N;
type TagSize = M;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
-impl PostfixTagged for Ccm
+impl AeadInOut for Ccm
where
C: BlockSizeUser + BlockCipherEncrypt,
M: ArraySize + TagSize,
N: ArraySize + NonceSize,
{
-}
-
-impl AeadInPlaceDetached for Ccm
-where
- C: BlockSizeUser + BlockCipherEncrypt,
- M: ArraySize + TagSize,
- N: ArraySize + NonceSize,
-{
- fn encrypt_in_place_detached(
+ fn encrypt_inout_detached(
&self,
nonce: &Nonce,
adata: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> Result, Error> {
- let mut full_tag = self.calc_mac(nonce, adata, buffer)?;
+ let mut full_tag = self.calc_mac(nonce, adata, buffer.get_in())?;
let ext_nonce = Self::extend_nonce(nonce);
// number of bytes left for counter (max 8)
@@ -242,21 +236,21 @@ where
if cb > 4 {
let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
ctr.apply_keystream(&mut full_tag);
- ctr.apply_keystream(buffer);
+ ctr.apply_keystream_inout(buffer);
} else {
let mut ctr = Ctr32BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
ctr.apply_keystream(&mut full_tag);
- ctr.apply_keystream(buffer);
+ ctr.apply_keystream_inout(buffer);
}
Ok(Tag::try_from(&full_tag[..M::to_usize()]).expect("tag size mismatch"))
}
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &Nonce,
adata: &[u8],
- buffer: &mut [u8],
+ mut buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
let ext_nonce = Self::extend_nonce(nonce);
@@ -266,14 +260,14 @@ where
if cb > 4 {
let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
ctr.seek(C::BlockSize::USIZE);
- ctr.apply_keystream(buffer);
+ ctr.apply_keystream_inout(buffer.reborrow());
} else {
let mut ctr = Ctr32BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
ctr.seek(C::BlockSize::USIZE);
- ctr.apply_keystream(buffer);
+ ctr.apply_keystream_inout(buffer.reborrow());
}
- let mut full_tag = self.calc_mac(nonce, adata, buffer)?;
+ let mut full_tag = self.calc_mac(nonce, adata, buffer.get_out())?;
if cb > 4 {
let mut ctr = Ctr64BE::from_core(CtrCore::inner_iv_init(&self.cipher, &ext_nonce));
@@ -286,7 +280,7 @@ where
if full_tag[..tag.len()].ct_eq(tag).into() {
Ok(())
} else {
- buffer.iter_mut().for_each(|v| *v = 0);
+ buffer.get_out().fill(0);
Err(Error)
}
}
diff --git a/ccm/tests/mod.rs b/ccm/tests/mod.rs
index 10ce7276..f4b20fb8 100644
--- a/ccm/tests/mod.rs
+++ b/ccm/tests/mod.rs
@@ -1,6 +1,6 @@
#![cfg(feature = "alloc")]
-use aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array};
+use aead::{Aead, AeadInOut, KeyInit, Payload, array::Array};
use aes::{Aes128, Aes192, Aes256};
use ccm::{
Ccm,
@@ -19,11 +19,11 @@ fn test_data_len_check() {
let c = Cipher::new(&key);
let mut buf1 = [1; u16::MAX as usize];
- let res = c.encrypt_in_place_detached(&nonce, &[], &mut buf1);
+ let res = c.encrypt_inout_detached(&nonce, &[], buf1.as_mut_slice().into());
assert!(res.is_ok());
let mut buf2 = [1; u16::MAX as usize + 1];
- let res = c.encrypt_in_place_detached(&nonce, &[], &mut buf2);
+ let res = c.encrypt_inout_detached(&nonce, &[], buf2.as_mut_slice().into());
assert!(res.is_err());
}
diff --git a/chacha20poly1305/src/cipher.rs b/chacha20poly1305/src/cipher.rs
index 76bb4bf8..5c8df500 100644
--- a/chacha20poly1305/src/cipher.rs
+++ b/chacha20poly1305/src/cipher.rs
@@ -2,7 +2,7 @@
use ::cipher::{StreamCipher, StreamCipherSeek};
use aead::Error;
-use aead::array::Array;
+use aead::{array::Array, inout::InOutBuf};
use poly1305::{
Poly1305,
universal_hash::{KeyInit, UniversalHash},
@@ -50,10 +50,10 @@ where
}
/// Encrypt the given message in-place, returning the authentication tag
- pub(crate) fn encrypt_in_place_detached(
+ pub(crate) fn encrypt_inout_detached(
mut self,
associated_data: &[u8],
- buffer: &mut [u8],
+ mut buffer: InOutBuf<'_, '_, u8>,
) -> Result {
if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS {
return Err(Error);
@@ -63,19 +63,19 @@ where
// TODO(tarcieri): interleave encryption with Poly1305
// See:
- self.cipher.apply_keystream(buffer);
- self.mac.update_padded(buffer);
+ self.cipher.apply_keystream_inout(buffer.reborrow());
+ self.mac.update_padded(buffer.get_out());
- self.authenticate_lengths(associated_data, buffer)?;
+ self.authenticate_lengths(associated_data, buffer.get_out())?;
Ok(self.mac.finalize())
}
/// Decrypt the given message, first authenticating ciphertext integrity
/// and returning an error if it's been tampered with.
- pub(crate) fn decrypt_in_place_detached(
+ pub(crate) fn decrypt_inout_detached(
mut self,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
if buffer.len() / BLOCK_SIZE >= MAX_BLOCKS {
@@ -83,14 +83,14 @@ where
}
self.mac.update_padded(associated_data);
- self.mac.update_padded(buffer);
- self.authenticate_lengths(associated_data, buffer)?;
+ self.mac.update_padded(buffer.get_in());
+ self.authenticate_lengths(associated_data, buffer.get_in())?;
// This performs a constant-time comparison using the `subtle` crate
if self.mac.verify(tag).is_ok() {
// TODO(tarcieri): interleave decryption with Poly1305
// See:
- self.cipher.apply_keystream(buffer);
+ self.cipher.apply_keystream_inout(buffer);
Ok(())
} else {
Err(Error)
diff --git a/chacha20poly1305/src/lib.rs b/chacha20poly1305/src/lib.rs
index c42e057d..d829f8a7 100644
--- a/chacha20poly1305/src/lib.rs
+++ b/chacha20poly1305/src/lib.rs
@@ -46,7 +46,7 @@
//! This crate has an optional `alloc` feature which can be disabled in e.g.
//! microcontroller environments that don't have a heap.
//!
-//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`]
+//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`]
//! methods accept any type that impls the [`aead::Buffer`] trait which
//! contains the plaintext for encryption or ciphertext for decryption.
//!
@@ -60,7 +60,7 @@
#![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")]
//! # fn main() -> Result<(), Box> {
//! use chacha20poly1305::{
-//! aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec},
+//! aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec},
//! ChaCha20Poly1305, Nonce,
//! };
//!
@@ -139,14 +139,15 @@
mod cipher;
-pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, KeyInit, KeySizeUser, consts};
+pub use aead::{self, AeadCore, AeadInOut, Error, KeyInit, KeySizeUser, consts};
use self::cipher::Cipher;
use ::cipher::{KeyIvInit, StreamCipher, StreamCipherSeek};
use aead::{
- PostfixTagged,
+ TagPosition,
array::{Array, ArraySize},
consts::{U12, U16, U24, U32},
+ inout::InOutBuf,
};
use core::marker::PhantomData;
@@ -245,41 +246,31 @@ where
{
type NonceSize = N;
type TagSize = U16;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
-impl PostfixTagged for ChaChaPoly1305
+impl AeadInOut for ChaChaPoly1305
where
C: KeyIvInit + StreamCipher + StreamCipherSeek,
N: ArraySize,
{
-}
-
-impl AeadInPlaceDetached for ChaChaPoly1305
-where
- C: KeyIvInit + StreamCipher + StreamCipherSeek,
- N: ArraySize,
-{
- fn encrypt_in_place_detached(
+ fn encrypt_inout_detached(
&self,
nonce: &aead::Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> Result {
- Cipher::new(C::new(&self.key, nonce)).encrypt_in_place_detached(associated_data, buffer)
+ Cipher::new(C::new(&self.key, nonce)).encrypt_inout_detached(associated_data, buffer)
}
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &aead::Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
- Cipher::new(C::new(&self.key, nonce)).decrypt_in_place_detached(
- associated_data,
- buffer,
- tag,
- )
+ Cipher::new(C::new(&self.key, nonce)).decrypt_inout_detached(associated_data, buffer, tag)
}
}
diff --git a/deoxys/Cargo.toml b/deoxys/Cargo.toml
index 7c360207..dbf9bef8 100644
--- a/deoxys/Cargo.toml
+++ b/deoxys/Cargo.toml
@@ -20,6 +20,7 @@ rust-version = "1.85"
[dependencies]
aead = { version = "0.6.0-rc.0", default-features = false }
aes = { version = "=0.9.0-pre.3", features = ["hazmat"], default-features = false }
+inout = { version = "0.2.0-rc.4", default-features = false }
subtle = { version = "2", default-features = false }
zeroize = { version = "1", optional = true, default-features = false }
diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs
index 63df0f7b..14ceac6a 100644
--- a/deoxys/src/lib.rs
+++ b/deoxys/src/lib.rs
@@ -62,7 +62,7 @@
//! This crate has an optional `alloc` feature which can be disabled in e.g.
//! microcontroller environments that don't have a heap.
//!
-//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`]
+//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`]
//! methods accept any type that impls the [`aead::Buffer`] trait which
//! contains the plaintext for encryption or ciphertext for decryption.
//!
@@ -76,7 +76,7 @@
//! # #[cfg(feature = "heapless")]
//! # {
//! use deoxys::{DeoxysII256, Nonce}; // Can be `DeoxysI128`, `DeoxysI256`, `DeoxysII128` of `DeoxysII256`
-//! use deoxys::aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec};
+//! use deoxys::aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec};
//!
//! let key = DeoxysII256::generate_key().expect("generate key");
//! let cipher = DeoxysII256::new(&key);
@@ -110,12 +110,13 @@ mod deoxys_bc;
/// Operation modes for Deoxys.
mod modes;
-pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser, consts};
+pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, consts};
use aead::{
- PostfixTagged,
+ TagPosition,
array::{Array, ArraySize},
consts::U16,
+ inout::{InOut, InOutBuf},
};
use core::marker::PhantomData;
@@ -156,19 +157,19 @@ where
/// Encrypts the data in place with the specified parameters
/// Returns the tag
- fn encrypt_in_place(
+ fn encrypt_inout(
nonce: &Array,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
subkeys: &Array,
) -> Tag;
/// Decrypts the data in place with the specified parameters
/// Returns an error if the tag verification fails
- fn decrypt_in_place(
+ fn decrypt_inout(
nonce: &Array,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
subkeys: &Array,
) -> Result<(), aead::Error>;
@@ -184,25 +185,23 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal {
fn precompute_subkeys(key: &Array) -> Array;
/// Encrypts a block of data in place.
- fn encrypt_in_place(
- block: &mut Block,
+ fn encrypt_inout(
+ mut block: InOut<'_, '_, Block>,
tweak: &Tweak,
subkeys: &Array,
) {
let keys = Self::key_schedule(tweak, subkeys);
- for (b, k) in block.iter_mut().zip(keys[0].iter()) {
- *b ^= k;
- }
+ block.xor_in2out(&keys[0]);
for k in &keys[1..] {
- aes::hazmat::cipher_round(block, k);
+ aes::hazmat::cipher_round(block.get_out(), k);
}
}
/// Decrypts a block of data in place.
- fn decrypt_in_place(
- block: &mut Block,
+ fn decrypt_inout(
+ mut block: InOut<'_, '_, Block>,
tweak: &Tweak,
subkeys: &Array,
) {
@@ -210,18 +209,16 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal {
let r = keys.len();
- for (b, k) in block.iter_mut().zip(keys[r - 1].iter()) {
- *b ^= k;
- }
+ block.xor_in2out(&keys[r - 1]);
- aes::hazmat::inv_mix_columns(block);
+ aes::hazmat::inv_mix_columns(block.get_out());
for k in keys[..r - 1].iter_mut().rev() {
aes::hazmat::inv_mix_columns(k);
- aes::hazmat::equiv_inv_cipher_round(block, k);
+ aes::hazmat::equiv_inv_cipher_round(block.get_out(), k);
}
- aes::hazmat::mix_columns(block);
+ aes::hazmat::mix_columns(block.get_out());
}
}
@@ -265,27 +262,21 @@ where
{
type NonceSize = M::NonceSize;
type TagSize = U16;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
-impl PostfixTagged for Deoxys
-where
- M: DeoxysMode,
- B: DeoxysBcType,
-{
-}
-
-impl AeadInPlaceDetached for Deoxys
+impl AeadInOut for Deoxys
where
M: DeoxysMode,
B: DeoxysBcType,
{
- fn encrypt_in_place_detached(
+ fn encrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> Result {
- Ok(Tag::from(M::encrypt_in_place(
+ Ok(Tag::from(M::encrypt_inout(
nonce,
associated_data,
buffer,
@@ -293,14 +284,14 @@ where
)))
}
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
- M::decrypt_in_place(nonce, associated_data, buffer, tag, &self.subkeys)
+ M::decrypt_inout(nonce, associated_data, buffer, tag, &self.subkeys)
}
}
diff --git a/deoxys/src/modes.rs b/deoxys/src/modes.rs
index ccb2b117..7d859606 100644
--- a/deoxys/src/modes.rs
+++ b/deoxys/src/modes.rs
@@ -2,6 +2,7 @@ use super::{Block, DeoxysBcType, DeoxysKey, DeoxysMode, Tag, Tweak};
use aead::{
array::Array,
consts::{U8, U15, U16},
+ inout::InOutBuf,
};
use core::marker::PhantomData;
use subtle::ConstantTimeEq;
@@ -47,7 +48,7 @@ where
let mut block = Block::default();
block.copy_from_slice(ad);
- B::encrypt_in_place(&mut block, tweak, subkeys);
+ B::encrypt_inout((&mut block).into(), tweak, subkeys);
for (t, b) in tag.iter_mut().zip(block.iter()) {
*t ^= b;
@@ -61,7 +62,7 @@ where
block[ad.len()] = 0x80;
- B::encrypt_in_place(&mut block, tweak, subkeys);
+ B::encrypt_inout((&mut block).into(), tweak, subkeys);
for (t, b) in tag.iter_mut().zip(block.iter()) {
*t ^= b;
@@ -82,15 +83,16 @@ where
{
type NonceSize = U8;
- fn encrypt_in_place(
+ fn encrypt_inout(
nonce: &Array,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
subkeys: &Array,
) -> Tag {
let mut tag = Tag::default();
let mut checksum = Checksum::default();
let mut tweak = Tweak::default();
+ let buffer_len = buffer.len();
// Associated Data
>::compute_ad_tag(
@@ -112,66 +114,75 @@ where
if !buffer.is_empty() {
tweak[0] = (tweak[0] & 0xf) | TWEAK_M;
- for (index, data) in buffer.chunks_mut(16).enumerate() {
+ let (data_blocks, tail) = buffer.into_chunks();
+ let data_blocks_len = data_blocks.len();
+
+ for (index, data) in data_blocks.into_iter().enumerate() {
// Copy block number
let tmp = tweak[8] & 0xf0;
tweak[8..].copy_from_slice(&(index as u64).to_be_bytes());
tweak[8] = (tweak[8] & 0xf) | tmp;
- if data.len() == 16 {
- for (c, d) in checksum.iter_mut().zip(data.iter()) {
- *c ^= d;
- }
+ for (c, d) in checksum.iter_mut().zip(data.get_in().iter()) {
+ *c ^= d;
+ }
- let data: &mut Block = data.try_into().unwrap();
- B::encrypt_in_place(data, tweak.as_ref(), subkeys);
- } else {
- // Last block checksum
- tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST;
+ B::encrypt_inout(data, &tweak, subkeys);
+ }
- let mut block = Block::default();
- block[0..data.len()].copy_from_slice(data);
+ let mut data = tail;
+ let index = data_blocks_len;
+ if !data.is_empty() {
+ // Last block, incomplete
- block[data.len()] = 0x80;
+ // Copy block number
+ let tmp = tweak[8] & 0xf0;
+ tweak[8..].copy_from_slice(&(index as u64).to_be_bytes());
+ tweak[8] = (tweak[8] & 0xf) | tmp;
- for (c, d) in checksum.iter_mut().zip(block.iter()) {
- *c ^= d;
- }
+ // Last block checksum
+ tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST;
- block.fill(0);
+ let mut block = Block::default();
+ block[0..data.len()].copy_from_slice(data.get_in());
- // Last block encryption
- B::encrypt_in_place(&mut block, tweak.as_ref(), subkeys);
+ block[data.len()] = 0x80;
- for (d, b) in data.iter_mut().zip(block.iter()) {
- *d ^= b;
- }
+ for (c, d) in checksum.iter_mut().zip(block.iter()) {
+ *c ^= d;
+ }
- // Tag computing.
- tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM;
+ block.fill(0);
- let tmp = tweak[8] & 0xf0;
- tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes());
- tweak[8] = (tweak[8] & 0xf) | tmp;
+ // Last block encryption
+ B::encrypt_inout((&mut block).into(), &tweak, subkeys);
- B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys);
+ data.xor_in2out((block[..data.len()]).into());
- for (t, c) in tag.iter_mut().zip(checksum.iter()) {
- *t ^= c;
- }
+ // Tag computing.
+ tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM;
+
+ let tmp = tweak[8] & 0xf0;
+ tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes());
+ tweak[8] = (tweak[8] & 0xf) | tmp;
+
+ B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys);
+
+ for (t, c) in tag.iter_mut().zip(checksum.iter()) {
+ *t ^= c;
}
}
}
- if buffer.len() % 16 == 0 {
+ if buffer_len % 16 == 0 {
// Tag computing without last block
tweak[0] = (tweak[0] & 0xf) | TWEAK_TAG;
let tmp = tweak[8] & 0xf0;
- tweak[8..].copy_from_slice(&((buffer.len() / 16) as u64).to_be_bytes());
+ tweak[8..].copy_from_slice(&((buffer_len / 16) as u64).to_be_bytes());
tweak[8] = (tweak[8] & 0xf) | tmp;
- B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys);
+ B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys);
for (t, c) in tag.iter_mut().zip(checksum.iter()) {
*t ^= c;
@@ -181,16 +192,17 @@ where
tag
}
- fn decrypt_in_place(
+ fn decrypt_inout(
nonce: &Array,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
subkeys: &Array,
) -> Result<(), aead::Error> {
let mut computed_tag = Tag::default();
let mut checksum = Checksum::default();
let mut tweak = Tweak::default();
+ let buffer_len = buffer.len();
// Associated Data
>::compute_ad_tag(
@@ -212,64 +224,71 @@ where
if !buffer.is_empty() {
tweak[0] = (tweak[0] & 0xf) | TWEAK_M;
- for (index, data) in buffer.chunks_mut(16).enumerate() {
+ let (data_blocks, tail) = buffer.into_chunks();
+ let data_blocks_len = data_blocks.len();
+
+ for (index, mut data) in data_blocks.into_iter().enumerate() {
// Copy block number
let tmp = tweak[8] & 0xf0;
tweak[8..].copy_from_slice(&(index as u64).to_be_bytes());
tweak[8] = (tweak[8] & 0xf) | tmp;
- if data.len() == 16 {
- let data: &mut Block = data.try_into().unwrap();
- B::decrypt_in_place(data, tweak.as_ref(), subkeys);
+ B::decrypt_inout(data.reborrow(), tweak.as_ref(), subkeys);
- for (c, d) in checksum.iter_mut().zip(data.iter()) {
- *c ^= d;
- }
- } else {
- // Last block checksum
- tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST;
+ for (c, d) in checksum.iter_mut().zip(data.get_out().iter()) {
+ *c ^= d;
+ }
+ }
- let mut block = Block::default();
- B::encrypt_in_place(&mut block, tweak.as_ref(), subkeys);
+ let mut data = tail;
+ let index = data_blocks_len;
+ if !data.is_empty() {
+ // Copy block number
+ let tmp = tweak[8] & 0xf0;
+ tweak[8..].copy_from_slice(&(index as u64).to_be_bytes());
+ tweak[8] = (tweak[8] & 0xf) | tmp;
- for (d, b) in data.iter_mut().zip(block.iter()) {
- *d ^= b;
- }
+ // Last block checksum
+ tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST;
- block.fill(0);
+ let mut block = Block::default();
+ B::encrypt_inout((&mut block).into(), tweak.as_ref(), subkeys);
- block[0..data.len()].copy_from_slice(data);
- block[data.len()] = 0x80;
+ data.xor_in2out((block[..data.len()]).into());
- for (c, d) in checksum.iter_mut().zip(block.iter()) {
- *c ^= d;
- }
+ block.fill(0);
+
+ block[0..data.len()].copy_from_slice(data.get_out());
+ block[data.len()] = 0x80;
- // Tag computing.
- tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM;
+ for (c, d) in checksum.iter_mut().zip(block.iter()) {
+ *c ^= d;
+ }
- let tmp = tweak[8] & 0xf0;
- tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes());
- tweak[8] = (tweak[8] & 0xf) | tmp;
+ // Tag computing.
+ tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM;
- B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys);
+ let tmp = tweak[8] & 0xf0;
+ tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes());
+ tweak[8] = (tweak[8] & 0xf) | tmp;
- for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) {
- *t ^= c;
- }
+ B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys);
+
+ for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) {
+ *t ^= c;
}
}
}
- if buffer.len() % 16 == 0 {
+ if buffer_len % 16 == 0 {
// Tag computing without last block
tweak[0] = (tweak[0] & 0xf) | TWEAK_TAG;
let tmp = tweak[8] & 0xf0;
- tweak[8..].copy_from_slice(&((buffer.len() / 16) as u64).to_be_bytes());
+ tweak[8..].copy_from_slice(&((buffer_len / 16) as u64).to_be_bytes());
tweak[8] = (tweak[8] & 0xf) | tmp;
- B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys);
+ B::encrypt_inout((&mut checksum).into(), tweak.as_ref(), subkeys);
for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) {
*t ^= c;
@@ -306,7 +325,8 @@ where
tweak[8..].copy_from_slice(&(index as u64).to_be_bytes());
let mut block = *data;
- B::encrypt_in_place(&mut block, tweak, subkeys);
+
+ B::encrypt_inout((&mut block).into(), tweak, subkeys);
for (t, b) in tag.iter_mut().zip(block.iter()) {
*t ^= b;
@@ -330,7 +350,7 @@ where
block[data.len()] = 0x80;
- B::encrypt_in_place(&mut block, tweak, subkeys);
+ B::encrypt_inout((&mut block).into(), tweak, subkeys);
for (t, b) in tag.iter_mut().zip(block.iter()) {
*t ^= b;
@@ -338,39 +358,60 @@ where
}
fn encrypt_decrypt_message(
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tweak: &mut Tweak,
subkeys: &Array,
tag: &Tag,
nonce: &Array,
) {
- if !buffer.is_empty() {
- tweak.copy_from_slice(tag);
- tweak[0] |= 0x80;
+ #[inline]
+ fn encrypt_decrypt_block(
+ index: usize,
+ tweak: &mut Tweak,
+ subkeys: &Array,
+ nonce: &Array,
+ xor: F,
+ ) {
+ let index_array = (index as u64).to_be_bytes();
+
+ // XOR in block numbers
+ for (t, i) in tweak[8..].iter_mut().zip(&index_array) {
+ *t ^= i
+ }
- for (index, data) in buffer.chunks_mut(16).enumerate() {
- let index_array = (index as u64).to_be_bytes();
+ let mut block = Block::default();
+ block[1..].copy_from_slice(nonce);
- // XOR in block numbers
- for (t, i) in tweak[8..].iter_mut().zip(&index_array) {
- *t ^= i
- }
+ B::encrypt_inout((&mut block).into(), tweak, subkeys);
- let mut block = Block::default();
- block[1..].copy_from_slice(nonce);
+ xor(&block);
- B::encrypt_in_place(&mut block, tweak, subkeys);
+ // XOR out block numbers
+ for (t, i) in tweak[8..].iter_mut().zip(&index_array) {
+ *t ^= i
+ }
+ }
- for (t, b) in data.iter_mut().zip(block.iter()) {
- *t ^= b;
- }
+ if buffer.is_empty() {
+ return;
+ }
- // XOR out block numbers
- for (t, i) in tweak[8..].iter_mut().zip(&index_array) {
- *t ^= i
- }
- }
+ tweak.copy_from_slice(tag);
+ tweak[0] |= 0x80;
+
+ let (blocks, tail) = buffer.into_chunks::();
+ let blocks_len = blocks.len();
+ for (index, mut data) in blocks.into_iter().enumerate() {
+ encrypt_decrypt_block::(index, tweak, subkeys, nonce, |block| {
+ data.xor_in2out(block)
+ });
}
+ let mut data = tail;
+ let index = blocks_len;
+
+ encrypt_decrypt_block::(index, tweak, subkeys, nonce, |block| {
+ data.xor_in2out((block[..data.len()]).into())
+ });
}
}
@@ -380,10 +421,10 @@ where
{
type NonceSize = U15;
- fn encrypt_in_place(
+ fn encrypt_inout(
nonce: &Array,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
subkeys: &Array,
) -> Tag {
let mut tag = Tag::default();
@@ -398,11 +439,11 @@ where
);
// Message authentication
- Self::authenticate_message(buffer, &mut tweak, subkeys, &mut tag);
+ Self::authenticate_message(buffer.get_in(), &mut tweak, subkeys, &mut tag);
tweak[0] = TWEAK_TAG;
tweak[1..].copy_from_slice(nonce);
- B::encrypt_in_place(&mut tag, &tweak, subkeys);
+ B::encrypt_inout((&mut tag).into(), &tweak, subkeys);
// Message encryption
Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, &tag, nonce);
@@ -410,10 +451,10 @@ where
tag
}
- fn decrypt_in_place(
+ fn decrypt_inout(
nonce: &Array,
associated_data: &[u8],
- buffer: &mut [u8],
+ mut buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
subkeys: &Array,
) -> Result<(), aead::Error> {
@@ -429,16 +470,16 @@ where
);
// Message decryption
- Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, tag, nonce);
+ Self::encrypt_decrypt_message(buffer.reborrow(), &mut tweak, subkeys, tag, nonce);
tweak.fill(0);
// Message authentication
- Self::authenticate_message(buffer, &mut tweak, subkeys, &mut computed_tag);
+ Self::authenticate_message(buffer.get_out(), &mut tweak, subkeys, &mut computed_tag);
tweak[0] = TWEAK_TAG;
tweak[1..].copy_from_slice(nonce);
- B::encrypt_in_place(&mut computed_tag, &tweak, subkeys);
+ B::encrypt_inout((&mut computed_tag).into(), &tweak, subkeys);
if tag.ct_eq(&computed_tag).into() {
Ok(())
diff --git a/deoxys/tests/mock_buffer.rs b/deoxys/tests/mock_buffer.rs
new file mode 100644
index 00000000..d40220db
--- /dev/null
+++ b/deoxys/tests/mock_buffer.rs
@@ -0,0 +1,82 @@
+//! this module is here to test the inout behavior which is not currently exposed.
+//! it will be once we port over to the API made in RustCrypto/traits#1793.
+//!
+//! This is to drop once https://github.com/RustCrypto/traits/pull/1797 is made available.
+//!
+//! It duplicates test vectors from `tests/deoxys_i_128.rs` and provides a mock buffer backing
+//! for InOut.
+
+use aead::{AeadInOut, array::Array, dev::MockBuffer};
+use hex_literal::hex;
+
+use deoxys::*;
+
+#[test]
+fn test_deoxys_i_128_5() {
+ let plaintext = hex!("5a4c652cb880808707230679224b11799b5883431292973215e9bd03cf3bc32fe4");
+ let mut buffer = MockBuffer::from(&plaintext[..]);
+
+ let aad = Vec::new();
+
+ let key = hex!("101112131415161718191a1b1c1d1e1f");
+ let key = Array(key);
+
+ let nonce = hex!("202122232425262728292a2b2c2d2e2f");
+ let nonce = Array::try_from(&nonce[..8]).unwrap();
+
+ let ciphertext_expected =
+ hex!("cded5a43d3c76e942277c2a1517530ad66037897c985305ede345903ed7585a626");
+
+ let tag_expected: [u8; 16] = hex!("cbf5faa6b8398c47f4278d2019161776");
+
+ let cipher = DeoxysI128::new(&key);
+ let tag: Tag = cipher
+ .encrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf())
+ .expect("encryption failed");
+
+ let ciphertext = buffer.as_ref();
+ assert_eq!(ciphertext, ciphertext_expected);
+ assert_eq!(tag, tag_expected);
+
+ let mut buffer = MockBuffer::from(buffer.as_ref());
+ cipher
+ .decrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf(), &tag)
+ .expect("decryption failed");
+
+ assert_eq!(&plaintext[..], buffer.as_ref());
+}
+
+#[test]
+fn test_deoxys_ii_128_5() {
+ let plaintext = hex!("06ac1756eccece62bd743fa80c299f7baa3872b556130f52265919494bdc136db3");
+ let mut buffer = MockBuffer::from(&plaintext[..]);
+
+ let aad = Vec::new();
+
+ let key = hex!("101112131415161718191a1b1c1d1e1f");
+ let key = Array(key);
+
+ let nonce = hex!("202122232425262728292a2b2c2d2e2f");
+ let nonce = Array::try_from(&nonce[..15]).unwrap();
+
+ let ciphertext_expected =
+ hex!("82bf241958b324ed053555d23315d3cc20935527fc970ff34a9f521a95e302136d");
+
+ let tag_expected: [u8; 16] = hex!("0eadc8612d5208c491e93005195e9769");
+
+ let cipher = DeoxysII128::new(&key);
+ let tag: Tag = cipher
+ .encrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf())
+ .expect("encryption failed");
+
+ let ciphertext = buffer.as_ref();
+ assert_eq!(ciphertext, ciphertext_expected);
+ assert_eq!(tag, tag_expected);
+
+ let mut buffer = MockBuffer::from(buffer.as_ref());
+ cipher
+ .decrypt_inout_detached(&nonce, &aad, buffer.to_in_out_buf(), &tag)
+ .expect("decryption failed");
+
+ assert_eq!(&plaintext[..], buffer.as_ref());
+}
diff --git a/eax/src/lib.rs b/eax/src/lib.rs
index c4d6cf03..1abc7c64 100644
--- a/eax/src/lib.rs
+++ b/eax/src/lib.rs
@@ -38,7 +38,7 @@
//! This crate has an optional `alloc` feature which can be disabled in e.g.
//! microcontroller environments that don't have a heap.
//!
-//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`]
+//! The [`AeadInOut::encrypt_in_place`] and [`AeadInOut::decrypt_in_place`]
//! methods accept any type that impls the [`aead::Buffer`] trait which
//! contains the plaintext for encryption or ciphertext for decryption.
//!
@@ -56,7 +56,7 @@
//! use eax::aead::{
//! array::Array,
//! heapless::Vec,
-//! AeadCore, AeadInPlace, KeyInit, rand_core::OsRng
+//! AeadCore, AeadInOut, KeyInit, rand_core::OsRng
//! };
//!
//! pub type Aes256Eax = Eax;
@@ -97,7 +97,7 @@
//! # {
//! use aes::Aes256;
//! use eax::Eax;
-//! use eax::aead::{AeadInPlaceDetached, KeyInit, array::Array};
+//! use eax::aead::{AeadInOut, KeyInit, array::Array};
//! use eax::aead::heapless::Vec;
//! use eax::aead::consts::{U8, U128};
//!
@@ -110,7 +110,7 @@
//! buffer.extend_from_slice(b"plaintext message");
//!
//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
-//! let tag = cipher.encrypt_in_place_detached(nonce, b"", &mut buffer).expect("encryption failure!");
+//! let tag = cipher.encrypt_inout_detached(nonce, b"", buffer.as_mut_slice().into()).expect("encryption failure!");
//!
//! // The tag has only 8 bytes, compared to the usual 16 bytes
//! assert_eq!(tag.len(), 8);
@@ -119,15 +119,15 @@
//! assert_ne!(&buffer, b"plaintext message");
//!
//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
-//! cipher.decrypt_in_place_detached(nonce, b"", &mut buffer, &tag).expect("decryption failure!");
+//! cipher.decrypt_inout_detached(nonce, b"", buffer.as_mut_slice().into(), &tag).expect("decryption failure!");
//! assert_eq!(&buffer, b"plaintext message");
//! # }
//! ```
-pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser};
+pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser};
pub use cipher;
-use aead::PostfixTagged;
+use aead::{TagPosition, inout::InOutBuf};
use cipher::{
BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, array::Array, consts::U16,
crypto_common::OutputSizeUser, typenum::Unsigned,
@@ -210,25 +210,19 @@ where
{
type NonceSize = Cipher::BlockSize;
type TagSize = M;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
-impl PostfixTagged for Eax
+impl AeadInOut for Eax
where
Cipher: BlockSizeUser + BlockCipherEncrypt + Clone + KeyInit,
M: TagSize,
{
-}
-
-impl AeadInPlaceDetached for Eax
-where
- Cipher: BlockSizeUser + BlockCipherEncrypt + Clone + KeyInit,
- M: TagSize,
-{
- fn encrypt_in_place_detached(
+ fn encrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ mut buffer: InOutBuf<'_, '_, u8>,
) -> Result, Error> {
if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX {
return Err(Error);
@@ -247,10 +241,10 @@ where
// 3. enc ← CTR(M) using n as iv
Ctr128BE::::inner_iv_init(Cipher::new(&self.key), &n)
- .apply_keystream_partial(buffer.into());
+ .apply_keystream_partial(buffer.reborrow());
// 4. c ← OMAC(2 || enc)
- let c = Self::cmac_with_iv(&self.key, 2, buffer);
+ let c = Self::cmac_with_iv(&self.key, 2, buffer.get_out());
// 5. tag ← n ^ h ^ c
// (^ means xor)
@@ -267,11 +261,11 @@ where
Ok(tag)
}
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX {
@@ -285,7 +279,7 @@ where
let h = Self::cmac_with_iv(&self.key, 1, associated_data);
// 4. c ← OMAC(2 || enc)
- let c = Self::cmac_with_iv(&self.key, 2, buffer);
+ let c = Self::cmac_with_iv(&self.key, 2, buffer.get_in());
// 5. tag ← n ^ h ^ c
// (^ means xor)
@@ -305,7 +299,7 @@ where
if expected_tag.ct_eq(tag).into() {
// Decrypt
Ctr128BE::::inner_iv_init(Cipher::new(&self.key), &n)
- .apply_keystream_partial(buffer.into());
+ .apply_keystream_partial(buffer);
Ok(())
} else {
diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs
index a6808ff9..34fa5c4f 100644
--- a/ocb3/src/lib.rs
+++ b/ocb3/src/lib.rs
@@ -5,7 +5,7 @@
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
)]
-#![deny(unsafe_code)]
+//#![deny(unsafe_code)]
#![warn(missing_docs, rust_2018_idioms)]
/// Constants used, reexported for convenience.
@@ -14,17 +14,21 @@ pub mod consts {
}
pub use aead::{
- self, AeadCore, AeadInPlaceDetached, Error, KeyInit, KeySizeUser,
+ self, AeadCore, AeadInOut, Error, KeyInit, KeySizeUser,
array::{Array, AssocArraySize},
};
-use aead::{PostfixTagged, array::ArraySize};
+use aead::{
+ TagPosition,
+ array::ArraySize,
+ inout::{InOut, InOutBuf},
+};
use cipher::{
BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser,
- consts::{U12, U16},
+ consts::{U2, U12, U16},
typenum::Unsigned,
};
-use core::marker::PhantomData;
+use core::{marker::PhantomData, ops::Mul};
use dbl::Dbl;
use subtle::ConstantTimeEq;
@@ -55,7 +59,9 @@ pub type Nonce = Array;
/// OCB3 tag
pub type Tag = Array;
-pub(crate) type Block = Array;
+type BlockSize = U16;
+pub(crate) type Block = Array;
+type DoubleBlock = Array>::Output>;
mod sealed {
use aead::array::{
@@ -168,6 +174,7 @@ where
{
type NonceSize = NonceSize;
type TagSize = TagSize;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
impl From for Ocb3
@@ -190,54 +197,47 @@ where
}
}
-impl PostfixTagged for Ocb3
+impl AeadInOut for Ocb3
where
Cipher: BlockSizeUser + BlockCipherEncrypt + BlockCipherDecrypt,
NonceSize: sealed::NonceSizes,
TagSize: sealed::TagSizes,
{
-}
-
-impl AeadInPlaceDetached for Ocb3
-where
- Cipher: BlockSizeUser + BlockCipherEncrypt + BlockCipherDecrypt,
- NonceSize: sealed::NonceSizes,
- TagSize: sealed::TagSizes,
-{
- fn encrypt_in_place_detached(
+ fn encrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> aead::Result> {
if (buffer.len() > P_MAX) || (associated_data.len() > A_MAX) {
unimplemented!()
}
// First, try to process many blocks at once.
- let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_encrypt(nonce, buffer);
+ let (tail, index, mut offset_i, mut checksum_i) = self.wide_encrypt(nonce, buffer);
- let mut i = (processed_bytes / 16) + 1;
+ let mut i = index;
// Then, process the remaining blocks.
- for p_i in Block::slice_as_chunks_mut(&mut buffer[processed_bytes..]).0 {
+ let (blocks, mut tail): (InOutBuf<'_, '_, Block>, _) = tail.into_chunks();
+
+ for p_i in blocks {
// offset_i = offset_{i-1} xor L_{ntz(i)}
inplace_xor(&mut offset_i, &self.ll[ntz(i)]);
// checksum_i = checksum_{i-1} xor p_i
- inplace_xor(&mut checksum_i, p_i);
+ inplace_xor(&mut checksum_i, p_i.get_in());
// c_i = offset_i xor ENCIPHER(K, p_i xor offset_i)
- let c_i = p_i;
- inplace_xor(c_i, &offset_i);
- self.cipher.encrypt_block(c_i);
- inplace_xor(c_i, &offset_i);
+ let mut c_i = p_i;
+ c_i.xor_in2out(&offset_i);
+ self.cipher.encrypt_block(c_i.get_out());
+ inplace_xor(c_i.get_out(), &offset_i);
i += 1;
}
// Process any partial blocks.
- if (buffer.len() % 16) != 0 {
- let processed_bytes = (i - 1) * 16;
- let remaining_bytes = buffer.len() - processed_bytes;
+ if !tail.is_empty() {
+ let remaining_bytes = tail.len();
// offset_* = offset_m xor L_*
inplace_xor(&mut offset_i, &self.ll_star);
@@ -247,15 +247,13 @@ where
self.cipher.encrypt_block(&mut pad);
// checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*)))
let checksum_rhs = &mut [0u8; 16];
- checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]);
+ checksum_rhs[..remaining_bytes].copy_from_slice(tail.get_in());
checksum_rhs[remaining_bytes] = 0b1000_0000;
inplace_xor(&mut checksum_i, checksum_rhs.as_ref());
// C_* = P_* xor Pad[1..bitlen(P_*)]
- let p_star = &mut buffer[processed_bytes..];
+ let p_star = tail.get_out();
let pad = &mut pad[..p_star.len()];
- for (aa, bb) in p_star.iter_mut().zip(pad) {
- *aa ^= *bb;
- }
+ tail.xor_in2out(pad);
}
let tag = self.compute_tag(associated_data, &mut checksum_i, &offset_i);
@@ -263,14 +261,14 @@ where
Ok(tag)
}
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &aead::Tag,
) -> aead::Result<()> {
- let expected_tag = self.decrypt_in_place_return_tag(nonce, associated_data, buffer);
+ let expected_tag = self.decrypt_inout_return_tag(nonce, associated_data, buffer);
if expected_tag.ct_eq(tag).into() {
Ok(())
} else {
@@ -286,41 +284,40 @@ where
TagSize: sealed::TagSizes,
{
/// Decrypts in place and returns expected tag.
- pub(crate) fn decrypt_in_place_return_tag(
+ pub(crate) fn decrypt_inout_return_tag(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> aead::Tag {
if (buffer.len() > C_MAX) || (associated_data.len() > A_MAX) {
unimplemented!()
}
// First, try to process many blocks at once.
- let (processed_bytes, mut offset_i, mut checksum_i) = self.wide_decrypt(nonce, buffer);
+ let (tail, index, mut offset_i, mut checksum_i) = self.wide_decrypt(nonce, buffer);
- let mut i = (processed_bytes / 16) + 1;
+ let mut i = index;
// Then, process the remaining blocks.
- let (blocks, _remaining) = Block::slice_as_chunks_mut(&mut buffer[processed_bytes..]);
+ let (blocks, mut tail): (InOutBuf<'_, '_, Block>, _) = tail.into_chunks();
for c_i in blocks {
// offset_i = offset_{i-1} xor L_{ntz(i)}
inplace_xor(&mut offset_i, &self.ll[ntz(i)]);
// p_i = offset_i xor DECIPHER(K, c_i xor offset_i)
- let p_i = c_i;
- inplace_xor(p_i, &offset_i);
- self.cipher.decrypt_block(p_i);
- inplace_xor(p_i, &offset_i);
+ let mut p_i = c_i;
+ p_i.xor_in2out(&offset_i);
+ self.cipher.decrypt_block(p_i.get_out());
+ inplace_xor(p_i.get_out(), &offset_i);
// checksum_i = checksum_{i-1} xor p_i
- inplace_xor(&mut checksum_i, p_i);
+ inplace_xor(&mut checksum_i, p_i.get_out());
i += 1;
}
// Process any partial blocks.
- if (buffer.len() % 16) != 0 {
- let processed_bytes = (i - 1) * 16;
- let remaining_bytes = buffer.len() - processed_bytes;
+ if !tail.is_empty() {
+ let remaining_bytes = tail.len();
// offset_* = offset_m xor L_*
inplace_xor(&mut offset_i, &self.ll_star);
@@ -329,14 +326,12 @@ where
inplace_xor(&mut pad, &offset_i);
self.cipher.encrypt_block(&mut pad);
// P_* = C_* xor Pad[1..bitlen(C_*)]
- let c_star = &mut buffer[processed_bytes..];
+ let c_star = tail.get_in();
let pad = &mut pad[..c_star.len()];
- for (aa, bb) in c_star.iter_mut().zip(pad) {
- *aa ^= *bb;
- }
+ tail.xor_in2out(pad);
// checksum_* = checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*)))
let checksum_rhs = &mut [0u8; 16];
- checksum_rhs[..remaining_bytes].copy_from_slice(&buffer[processed_bytes..]);
+ checksum_rhs[..remaining_bytes].copy_from_slice(tail.get_out());
checksum_rhs[remaining_bytes] = 0b1000_0000;
inplace_xor(&mut checksum_i, checksum_rhs.as_ref());
}
@@ -347,81 +342,85 @@ where
/// Encrypts plaintext in groups of two.
///
/// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c
- fn wide_encrypt(&self, nonce: &Nonce, buffer: &mut [u8]) -> (usize, Block, Block) {
+ fn wide_encrypt<'i, 'o>(
+ &self,
+ nonce: &Nonce,
+ buffer: InOutBuf<'i, 'o, u8>,
+ ) -> (InOutBuf<'i, 'o, u8>, usize, Block, Block) {
const WIDTH: usize = 2;
let mut i = 1;
let mut offset_i = [Block::default(); WIDTH];
- offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
+ offset_i[1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
let mut checksum_i = Block::default();
- for wide_blocks in buffer.chunks_exact_mut(::Size::USIZE * WIDTH) {
- let p_i = split_into_two_blocks(wide_blocks);
+ let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks();
+ for wide_block in wide_blocks.into_iter() {
+ let mut p_i = split_into_two_blocks(wide_block);
// checksum_i = checksum_{i-1} xor p_i
for p_ij in &p_i {
- inplace_xor(&mut checksum_i, p_ij);
+ inplace_xor(&mut checksum_i, p_ij.get_in());
}
// offset_i = offset_{i-1} xor L_{ntz(i)}
- offset_i[0] = offset_i[offset_i.len() - 1];
+ offset_i[0] = offset_i[1];
inplace_xor(&mut offset_i[0], &self.ll[ntz(i)]);
- for j in 1..p_i.len() {
- offset_i[j] = offset_i[j - 1];
- inplace_xor(&mut offset_i[j], &self.ll[ntz(i + j)]);
- }
+ offset_i[1] = offset_i[0];
+ inplace_xor(&mut offset_i[1], &self.ll[ntz(i + 1)]);
// c_i = offset_i xor ENCIPHER(K, p_i xor offset_i)
for j in 0..p_i.len() {
- inplace_xor(p_i[j], &offset_i[j]);
- self.cipher.encrypt_block(p_i[j]);
- inplace_xor(p_i[j], &offset_i[j])
+ p_i[j].xor_in2out(&offset_i[j]);
+ self.cipher.encrypt_block(p_i[j].get_out());
+ inplace_xor(p_i[j].get_out(), &offset_i[j]);
}
i += WIDTH;
}
- let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16);
-
- (processed_bytes, offset_i[offset_i.len() - 1], checksum_i)
+ (tail, i, offset_i[offset_i.len() - 1], checksum_i)
}
/// Decrypts plaintext in groups of two.
///
/// Adapted from https://www.cs.ucdavis.edu/~rogaway/ocb/news/code/ocb.c
- fn wide_decrypt(&self, nonce: &Nonce, buffer: &mut [u8]) -> (usize, Block, Block) {
+ fn wide_decrypt<'i, 'o>(
+ &self,
+ nonce: &Nonce,
+ buffer: InOutBuf<'i, 'o, u8>,
+ ) -> (InOutBuf<'i, 'o, u8>, usize, Block, Block) {
const WIDTH: usize = 2;
let mut i = 1;
let mut offset_i = [Block::default(); WIDTH];
- offset_i[offset_i.len() - 1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
+ offset_i[1] = initial_offset(&self.cipher, nonce, TagSize::to_u32());
let mut checksum_i = Block::default();
- for wide_blocks in buffer.chunks_exact_mut(16 * WIDTH) {
- let c_i = split_into_two_blocks(wide_blocks);
+
+ let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks();
+ for wide_block in wide_blocks.into_iter() {
+ let mut c_i = split_into_two_blocks(wide_block);
// offset_i = offset_{i-1} xor L_{ntz(i)}
- offset_i[0] = offset_i[offset_i.len() - 1];
+ offset_i[0] = offset_i[1];
inplace_xor(&mut offset_i[0], &self.ll[ntz(i)]);
- for j in 1..c_i.len() {
- offset_i[j] = offset_i[j - 1];
- inplace_xor(&mut offset_i[j], &self.ll[ntz(i + j)]);
- }
+ offset_i[1] = offset_i[0];
+ inplace_xor(&mut offset_i[1], &self.ll[ntz(i + 1)]);
// p_i = offset_i xor DECIPHER(K, c_i xor offset_i)
// checksum_i = checksum_{i-1} xor p_i
for j in 0..c_i.len() {
- inplace_xor(c_i[j], &offset_i[j]);
- self.cipher.decrypt_block(c_i[j]);
- inplace_xor(c_i[j], &offset_i[j]);
- inplace_xor(&mut checksum_i, c_i[j]);
+ c_i[j].xor_in2out(&offset_i[j]);
+ self.cipher.decrypt_block(c_i[j].get_out());
+ inplace_xor(c_i[j].get_out(), &offset_i[j]);
+ inplace_xor(&mut checksum_i, c_i[j].get_out());
}
i += WIDTH;
}
- let processed_bytes = (buffer.len() / (WIDTH * 16)) * (WIDTH * 16);
- (processed_bytes, offset_i[offset_i.len() - 1], checksum_i)
+ (tail, i, offset_i[offset_i.len() - 1], checksum_i)
}
/// Computes HASH function defined in https://www.rfc-editor.org/rfc/rfc7253.html#section-4.1
@@ -580,11 +579,20 @@ pub(crate) fn ntz(n: usize) -> usize {
}
#[inline]
-pub(crate) fn split_into_two_blocks(two_blocks: &mut [u8]) -> [&mut Block; 2] {
- const BLOCK_SIZE: usize = 16;
- debug_assert_eq!(two_blocks.len(), BLOCK_SIZE * 2);
- let (b0, b1) = two_blocks.split_at_mut(BLOCK_SIZE);
- [b0.try_into().unwrap(), b1.try_into().unwrap()]
+pub(crate) fn split_into_two_blocks<'i, 'o>(
+ two_blocks: InOut<'i, 'o, DoubleBlock>,
+) -> [InOut<'i, 'o, Block>; 2] {
+ let (input, output) = two_blocks.into_raw();
+
+ let (bi0, bi1) = unsafe { input.as_ref() }
+ .unwrap()
+ .split_at(BlockSize::USIZE);
+ let (bi0, bi1): (&Block, &Block) = (bi0.try_into().unwrap(), bi1.try_into().unwrap());
+ let (bo0, bo1) = unsafe { output.as_mut() }
+ .unwrap()
+ .split_at_mut(BlockSize::USIZE);
+ let (bo0, bo1): (&mut Block, &mut Block) = (bo0.try_into().unwrap(), bo1.try_into().unwrap());
+ [InOut::from((bi0, bo0)), InOut::from((bi1, bo1))]
}
#[cfg(test)]
diff --git a/ocb3/tests/kats.rs b/ocb3/tests/kats.rs
index 7181c5c9..1b30c726 100644
--- a/ocb3/tests/kats.rs
+++ b/ocb3/tests/kats.rs
@@ -1,7 +1,7 @@
#![allow(non_snake_case)]
use aead::{
- AeadInPlaceDetached, KeyInit,
+ AeadInOut, KeyInit,
consts::{U8, U12},
};
use aes::{Aes128, Aes192, Aes256};
@@ -38,7 +38,11 @@ macro_rules! rfc7253_wider_variety {
let N = num2str96(3 * i + 1);
let mut buffer = S.clone();
let tag = ocb
- .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &S, &mut buffer)
+ .encrypt_inout_detached(
+ N.as_slice().try_into().unwrap(),
+ &S,
+ buffer.as_mut_slice().into(),
+ )
.unwrap();
ciphertext.append(&mut buffer);
ciphertext.append(&mut tag.as_slice().to_vec());
@@ -48,7 +52,11 @@ macro_rules! rfc7253_wider_variety {
let N = num2str96(3 * i + 2);
let mut buffer = S.clone();
let tag = ocb
- .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &[], &mut buffer)
+ .encrypt_inout_detached(
+ N.as_slice().try_into().unwrap(),
+ &[],
+ buffer.as_mut_slice().into(),
+ )
.unwrap();
ciphertext.append(&mut buffer);
ciphertext.append(&mut tag.as_slice().to_vec());
@@ -57,7 +65,7 @@ macro_rules! rfc7253_wider_variety {
// C = C || OCB-ENCRYPT(K,N,S,)
let N = num2str96(3 * i + 3);
let tag = ocb
- .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &S, &mut [])
+ .encrypt_inout_detached(N.as_slice().try_into().unwrap(), &S, (&mut [][..]).into())
.unwrap();
ciphertext.append(&mut tag.as_slice().to_vec());
}
@@ -75,7 +83,11 @@ macro_rules! rfc7253_wider_variety {
// Output : OCB-ENCRYPT(K,N,C,)
let N = num2str96(385);
let tag = ocb
- .encrypt_in_place_detached(N.as_slice().try_into().unwrap(), &ciphertext, &mut [])
+ .encrypt_inout_detached(
+ N.as_slice().try_into().unwrap(),
+ &ciphertext,
+ (&mut [][..]).into(),
+ )
.unwrap();
assert_eq!(tag.as_slice(), hex!($expected))
diff --git a/xaes-256-gcm/src/lib.rs b/xaes-256-gcm/src/lib.rs
index a89ff81e..d36c8fc3 100644
--- a/xaes-256-gcm/src/lib.rs
+++ b/xaes-256-gcm/src/lib.rs
@@ -56,7 +56,7 @@ pub use aes_gcm;
use core::ops::{Div, Mul};
use aead::{
- AeadCore, AeadInPlaceDetached, Error, KeyInit, KeySizeUser, PostfixTagged, array::Array,
+ AeadCore, AeadInOut, Error, KeyInit, KeySizeUser, TagPosition, array::Array, inout::InOutBuf,
};
use aes::Aes256;
use aes_gcm::Aes256Gcm;
@@ -96,6 +96,7 @@ pub const C_MAX: u64 = (1 << 36) + 16;
impl AeadCore for Xaes256Gcm {
type NonceSize = NonceSize;
type TagSize = TagSize;
+ const TAG_POSITION: TagPosition = TagPosition::Postfix;
}
impl KeySizeUser for Xaes256Gcm {
@@ -126,14 +127,12 @@ impl KeyInit for Xaes256Gcm {
}
}
-impl PostfixTagged for Xaes256Gcm {}
-
-impl AeadInPlaceDetached for Xaes256Gcm {
- fn encrypt_in_place_detached(
+impl AeadInOut for Xaes256Gcm {
+ fn encrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
) -> Result {
if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX {
return Err(Error);
@@ -141,14 +140,14 @@ impl AeadInPlaceDetached for Xaes256Gcm {
let (n1, n) = nonce.split_ref::<>::Output>();
let k = self.derive_key(n1);
- Aes256Gcm::new(&k).encrypt_in_place_detached(n, associated_data, buffer)
+ Aes256Gcm::new(&k).encrypt_inout_detached(n, associated_data, buffer)
}
- fn decrypt_in_place_detached(
+ fn decrypt_inout_detached(
&self,
nonce: &Nonce,
associated_data: &[u8],
- buffer: &mut [u8],
+ buffer: InOutBuf<'_, '_, u8>,
tag: &Tag,
) -> Result<(), Error> {
if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX {
@@ -157,7 +156,7 @@ impl AeadInPlaceDetached for Xaes256Gcm {
let (n1, n) = nonce.split_ref::<>::Output>();
let k = self.derive_key(n1);
- Aes256Gcm::new(&k).decrypt_in_place_detached(n, associated_data, buffer, tag)
+ Aes256Gcm::new(&k).decrypt_inout_detached(n, associated_data, buffer, tag)
}
}
diff --git a/xaes-256-gcm/tests/xaes256gcm.rs b/xaes-256-gcm/tests/xaes256gcm.rs
index 1bb04ce1..62b85d7e 100644
--- a/xaes-256-gcm/tests/xaes256gcm.rs
+++ b/xaes-256-gcm/tests/xaes256gcm.rs
@@ -4,7 +4,7 @@
#[path = "../../aes-gcm/tests/common/mod.rs"]
mod common;
-use aes_gcm::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array};
+use aes_gcm::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array};
use common::TestVector;
use hex_literal::hex;
use xaes_256_gcm::Xaes256Gcm;