From 74b9e6c629faab4f240d0ee52f778d9f8024ce21 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 15 Mar 2025 20:56:40 -0700 Subject: [PATCH 01/16] make encrypt_decrypt an inout --- Cargo.lock | 1 + deoxys/Cargo.toml | 1 + deoxys/src/modes.rs | 68 ++++++++++++++++++++++++++++++--------------- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e7a691a..069e1fcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -245,6 +245,7 @@ dependencies = [ "aead", "aes", "hex-literal", + "inout", "subtle", "zeroize", ] 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/modes.rs b/deoxys/src/modes.rs index ccb2b117..c98f3e6c 100644 --- a/deoxys/src/modes.rs +++ b/deoxys/src/modes.rs @@ -4,6 +4,7 @@ use aead::{ consts::{U8, U15, U16}, }; use core::marker::PhantomData; +use inout::InOutBuf; use subtle::ConstantTimeEq; const TWEAK_AD: u8 = 0x20; @@ -338,39 +339,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_in_place(&mut block, tweak, subkeys); - let mut block = Block::default(); - block[1..].copy_from_slice(nonce); + xor(&block); + + // XOR out block numbers + for (t, i) in tweak[8..].iter_mut().zip(&index_array) { + *t ^= i + } + } - B::encrypt_in_place(&mut block, tweak, subkeys); + if buffer.is_empty() { + return; + } - for (t, b) in data.iter_mut().zip(block.iter()) { - *t ^= b; - } + tweak.copy_from_slice(tag); + tweak[0] |= 0x80; - // XOR out block numbers - for (t, i) in tweak[8..].iter_mut().zip(&index_array) { - *t ^= i - } - } + 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()) + }); } } @@ -405,7 +427,7 @@ where B::encrypt_in_place(&mut tag, &tweak, subkeys); // Message encryption - Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, &tag, nonce); + Self::encrypt_decrypt_message(buffer.into(), &mut tweak, subkeys, &tag, nonce); tag } @@ -429,7 +451,7 @@ where ); // Message decryption - Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, tag, nonce); + Self::encrypt_decrypt_message(buffer.into(), &mut tweak, subkeys, tag, nonce); tweak.fill(0); From 156c0df5d61340c885535aef4efec5139ee60b02 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 15 Mar 2025 23:33:18 -0700 Subject: [PATCH 02/16] make decrypt/encrypt_inplace use inout --- deoxys/src/lib.rs | 21 +++++++++------------ deoxys/src/modes.rs | 31 ++++++++++++++++--------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs index 63df0f7b..0e347a5f 100644 --- a/deoxys/src/lib.rs +++ b/deoxys/src/lib.rs @@ -118,6 +118,7 @@ use aead::{ consts::U16, }; use core::marker::PhantomData; +use inout::InOut; /// Deoxys-I with 128-bit keys pub type DeoxysI128 = Deoxys, deoxys_bc::DeoxysBc256>; @@ -185,24 +186,22 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal { /// Encrypts a block of data in place. fn encrypt_in_place( - block: &mut Block, + 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, + 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()); } } diff --git a/deoxys/src/modes.rs b/deoxys/src/modes.rs index c98f3e6c..61e88f51 100644 --- a/deoxys/src/modes.rs +++ b/deoxys/src/modes.rs @@ -48,7 +48,7 @@ where let mut block = Block::default(); block.copy_from_slice(ad); - B::encrypt_in_place(&mut block, tweak, subkeys); + B::encrypt_in_place((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -62,7 +62,7 @@ where block[ad.len()] = 0x80; - B::encrypt_in_place(&mut block, tweak, subkeys); + B::encrypt_in_place((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -125,7 +125,7 @@ where } let data: &mut Block = data.try_into().unwrap(); - B::encrypt_in_place(data, tweak.as_ref(), subkeys); + B::encrypt_in_place(data.into(), tweak.as_ref(), subkeys); } else { // Last block checksum tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; @@ -142,7 +142,7 @@ where block.fill(0); // Last block encryption - B::encrypt_in_place(&mut block, tweak.as_ref(), subkeys); + B::encrypt_in_place((&mut block).into(), tweak.as_ref(), subkeys); for (d, b) in data.iter_mut().zip(block.iter()) { *d ^= b; @@ -155,7 +155,7 @@ where tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys); + B::encrypt_in_place((&mut checksum).into(), tweak.as_ref(), subkeys); for (t, c) in tag.iter_mut().zip(checksum.iter()) { *t ^= c; @@ -172,7 +172,7 @@ where 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_in_place((&mut checksum).into(), tweak.as_ref(), subkeys); for (t, c) in tag.iter_mut().zip(checksum.iter()) { *t ^= c; @@ -221,7 +221,7 @@ where if data.len() == 16 { let data: &mut Block = data.try_into().unwrap(); - B::decrypt_in_place(data, tweak.as_ref(), subkeys); + B::decrypt_in_place(data.into(), tweak.as_ref(), subkeys); for (c, d) in checksum.iter_mut().zip(data.iter()) { *c ^= d; @@ -231,7 +231,7 @@ where tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; let mut block = Block::default(); - B::encrypt_in_place(&mut block, tweak.as_ref(), subkeys); + B::encrypt_in_place((&mut block).into(), tweak.as_ref(), subkeys); for (d, b) in data.iter_mut().zip(block.iter()) { *d ^= b; @@ -253,7 +253,7 @@ where tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - B::encrypt_in_place(&mut checksum, tweak.as_ref(), subkeys); + B::encrypt_in_place((&mut checksum).into(), tweak.as_ref(), subkeys); for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { *t ^= c; @@ -270,7 +270,7 @@ where 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_in_place((&mut checksum).into(), tweak.as_ref(), subkeys); for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { *t ^= c; @@ -307,7 +307,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_in_place((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -331,7 +332,7 @@ where block[data.len()] = 0x80; - B::encrypt_in_place(&mut block, tweak, subkeys); + B::encrypt_in_place((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -363,7 +364,7 @@ where let mut block = Block::default(); block[1..].copy_from_slice(nonce); - B::encrypt_in_place(&mut block, tweak, subkeys); + B::encrypt_in_place((&mut block).into(), tweak, subkeys); xor(&block); @@ -424,7 +425,7 @@ where tweak[0] = TWEAK_TAG; tweak[1..].copy_from_slice(nonce); - B::encrypt_in_place(&mut tag, &tweak, subkeys); + B::encrypt_in_place((&mut tag).into(), &tweak, subkeys); // Message encryption Self::encrypt_decrypt_message(buffer.into(), &mut tweak, subkeys, &tag, nonce); @@ -460,7 +461,7 @@ where tweak[0] = TWEAK_TAG; tweak[1..].copy_from_slice(nonce); - B::encrypt_in_place(&mut computed_tag, &tweak, subkeys); + B::encrypt_in_place((&mut computed_tag).into(), &tweak, subkeys); if tag.ct_eq(&computed_tag).into() { Ok(()) From 26f2b732960c1c5fc2032fe44bdd422a538765dc Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 16 Mar 2025 00:11:59 -0700 Subject: [PATCH 03/16] make encrypt_in_place inout aware --- deoxys/src/modes.rs | 77 ++++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/deoxys/src/modes.rs b/deoxys/src/modes.rs index 61e88f51..1b774105 100644 --- a/deoxys/src/modes.rs +++ b/deoxys/src/modes.rs @@ -92,6 +92,8 @@ where let mut tag = Tag::default(); let mut checksum = Checksum::default(); let mut tweak = Tweak::default(); + let buffer: InOutBuf<'_, '_, u8> = buffer.into(); + let buffer_len = buffer.len(); // Associated Data >::compute_ad_tag( @@ -113,63 +115,72 @@ 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.into(), tweak.as_ref(), subkeys); - } else { - // Last block checksum - tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; + B::encrypt_in_place(data, tweak.as_ref(), 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).into(), 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_in_place((&mut block).into(), tweak.as_ref(), subkeys); - B::encrypt_in_place((&mut checksum).into(), 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_in_place((&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).into(), tweak.as_ref(), subkeys); From 26988bd6a6485777f2137274c88fb23473260ff5 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 16 Mar 2025 00:12:40 -0700 Subject: [PATCH 04/16] make decrypt_in_place inout aware --- deoxys/src/modes.rs | 73 +++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/deoxys/src/modes.rs b/deoxys/src/modes.rs index 1b774105..a6330552 100644 --- a/deoxys/src/modes.rs +++ b/deoxys/src/modes.rs @@ -203,6 +203,8 @@ where let mut computed_tag = Tag::default(); let mut checksum = Checksum::default(); let mut tweak = Tweak::default(); + let buffer: InOutBuf<'_, '_, u8> = buffer.into(); + let buffer_len = buffer.len(); // Associated Data >::compute_ad_tag( @@ -224,61 +226,68 @@ 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.into(), tweak.as_ref(), subkeys); + B::decrypt_in_place(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).into(), 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_in_place((&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); - // Tag computing. - tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; + block[0..data.len()].copy_from_slice(data.get_out()); + block[data.len()] = 0x80; - let tmp = tweak[8] & 0xf0; - tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); - tweak[8] = (tweak[8] & 0xf) | tmp; + for (c, d) in checksum.iter_mut().zip(block.iter()) { + *c ^= d; + } - B::encrypt_in_place((&mut checksum).into(), tweak.as_ref(), subkeys); + // Tag computing. + tweak[0] = (tweak[0] & 0xf) | TWEAK_CHKSUM; - for (t, c) in computed_tag.iter_mut().zip(checksum.iter()) { - *t ^= c; - } + 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_in_place((&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).into(), tweak.as_ref(), subkeys); From a573dcbf651e22190981fba0de04d5b6597c1f3e Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 16 Mar 2025 00:19:20 -0700 Subject: [PATCH 05/16] Wire inout in the public traits --- deoxys/src/lib.rs | 20 ++++++++-------- deoxys/src/modes.rs | 56 ++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs index 0e347a5f..910e96f3 100644 --- a/deoxys/src/lib.rs +++ b/deoxys/src/lib.rs @@ -118,7 +118,7 @@ use aead::{ consts::U16, }; use core::marker::PhantomData; -use inout::InOut; +use inout::{InOut, InOutBuf}; /// Deoxys-I with 128-bit keys pub type DeoxysI128 = Deoxys, deoxys_bc::DeoxysBc256>; @@ -157,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>; @@ -185,7 +185,7 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal { fn precompute_subkeys(key: &Array) -> Array; /// Encrypts a block of data in place. - fn encrypt_in_place( + fn encrypt_inout( mut block: InOut<'_, '_, Block>, tweak: &Tweak, subkeys: &Array, @@ -200,7 +200,7 @@ pub trait DeoxysBcType: deoxys_bc::DeoxysBcInternal { } /// Decrypts a block of data in place. - fn decrypt_in_place( + fn decrypt_inout( mut block: InOut<'_, '_, Block>, tweak: &Tweak, subkeys: &Array, @@ -282,10 +282,10 @@ where associated_data: &[u8], buffer: &mut [u8], ) -> Result { - Ok(Tag::from(M::encrypt_in_place( + Ok(Tag::from(M::encrypt_inout( nonce, associated_data, - buffer, + buffer.into(), &self.subkeys, ))) } @@ -297,7 +297,7 @@ where buffer: &mut [u8], tag: &Tag, ) -> Result<(), Error> { - M::decrypt_in_place(nonce, associated_data, buffer, tag, &self.subkeys) + M::decrypt_inout(nonce, associated_data, buffer.into(), tag, &self.subkeys) } } diff --git a/deoxys/src/modes.rs b/deoxys/src/modes.rs index a6330552..0f91ec36 100644 --- a/deoxys/src/modes.rs +++ b/deoxys/src/modes.rs @@ -48,7 +48,7 @@ where let mut block = Block::default(); block.copy_from_slice(ad); - B::encrypt_in_place((&mut block).into(), tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -62,7 +62,7 @@ where block[ad.len()] = 0x80; - B::encrypt_in_place((&mut block).into(), tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -83,16 +83,15 @@ 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: InOutBuf<'_, '_, u8> = buffer.into(); let buffer_len = buffer.len(); // Associated Data @@ -128,7 +127,7 @@ where *c ^= d; } - B::encrypt_in_place(data, tweak.as_ref(), subkeys); + B::encrypt_inout(data, &tweak, subkeys); } let mut data = tail; @@ -156,7 +155,7 @@ where block.fill(0); // Last block encryption - B::encrypt_in_place((&mut block).into(), tweak.as_ref(), subkeys); + B::encrypt_inout((&mut block).into(), &tweak, subkeys); data.xor_in2out((block[..data.len()]).into()); @@ -167,7 +166,7 @@ where tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - B::encrypt_in_place((&mut checksum).into(), 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; @@ -183,7 +182,7 @@ where 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).into(), 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; @@ -193,17 +192,16 @@ 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: InOutBuf<'_, '_, u8> = buffer.into(); let buffer_len = buffer.len(); // Associated Data @@ -235,7 +233,7 @@ where tweak[8..].copy_from_slice(&(index as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - B::decrypt_in_place(data.reborrow(), tweak.as_ref(), subkeys); + B::decrypt_inout(data.reborrow(), tweak.as_ref(), subkeys); for (c, d) in checksum.iter_mut().zip(data.get_out().iter()) { *c ^= d; @@ -254,7 +252,7 @@ where tweak[0] = (tweak[0] & 0xf) | TWEAK_M_LAST; let mut block = Block::default(); - B::encrypt_in_place((&mut block).into(), tweak.as_ref(), subkeys); + B::encrypt_inout((&mut block).into(), tweak.as_ref(), subkeys); data.xor_in2out((block[..data.len()]).into()); @@ -274,7 +272,7 @@ where tweak[8..].copy_from_slice(&((index + 1) as u64).to_be_bytes()); tweak[8] = (tweak[8] & 0xf) | tmp; - B::encrypt_in_place((&mut checksum).into(), 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; @@ -290,7 +288,7 @@ where 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).into(), 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; @@ -328,7 +326,7 @@ where let mut block = *data; - B::encrypt_in_place((&mut block).into(), tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -352,7 +350,7 @@ where block[data.len()] = 0x80; - B::encrypt_in_place((&mut block).into(), tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); for (t, b) in tag.iter_mut().zip(block.iter()) { *t ^= b; @@ -384,7 +382,7 @@ where let mut block = Block::default(); block[1..].copy_from_slice(nonce); - B::encrypt_in_place((&mut block).into(), tweak, subkeys); + B::encrypt_inout((&mut block).into(), tweak, subkeys); xor(&block); @@ -423,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(); @@ -441,22 +439,22 @@ 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).into(), &tweak, subkeys); + B::encrypt_inout((&mut tag).into(), &tweak, subkeys); // Message encryption - Self::encrypt_decrypt_message(buffer.into(), &mut tweak, subkeys, &tag, nonce); + Self::encrypt_decrypt_message(buffer, &mut tweak, subkeys, &tag, nonce); 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> { @@ -472,16 +470,16 @@ where ); // Message decryption - Self::encrypt_decrypt_message(buffer.into(), &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).into(), &tweak, subkeys); + B::encrypt_inout((&mut computed_tag).into(), &tweak, subkeys); if tag.ct_eq(&computed_tag).into() { Ok(()) From 9be4164235f0f0f8d0754a9a1c626abed5471b43 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 16 Mar 2025 11:31:09 -0700 Subject: [PATCH 06/16] Adds a tests against a inoutbuf with two backing buffers --- deoxys/src/lib.rs | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs index 910e96f3..f7c78841 100644 --- a/deoxys/src/lib.rs +++ b/deoxys/src/lib.rs @@ -324,3 +324,114 @@ where B: DeoxysBcType, { } + +#[cfg(test)] +mod tests { + //! 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 hex_literal::hex; + + use super::*; + + struct MockBuffer { + in_buf: [u8; 33], + out_buf: [u8; 33], + } + + impl From<&[u8]> for MockBuffer { + fn from(buf: &[u8]) -> Self { + let mut in_buf = [0u8; 33]; + in_buf.copy_from_slice(buf); + Self { + in_buf, + out_buf: [0u8; 33], + } + } + } + + impl MockBuffer { + /// Get an [`InOutBuf`] from a [`MockBuffer`] + pub fn to_in_out_buf(&mut self) -> InOutBuf<'_, '_, u8> { + InOutBuf::new(self.in_buf.as_slice(), self.out_buf.as_mut_slice()) + .expect("Invariant violation") + } + } + + impl AsRef<[u8]> for MockBuffer { + fn as_ref(&self) -> &[u8] { + &self.out_buf + } + } + + #[test] + fn test_deoxys_i_128_5() { + let plaintext = hex!("5a4c652cb880808707230679224b11799b5883431292973215e9bd03cf3bc32fe4"); + let mut buffer = MockBuffer::from(&plaintext[..]); + + let aad = []; + + 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"); + + type M = modes::DeoxysI; + let cipher = DeoxysI128::new(&key); + let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys); + + let ciphertext = buffer.as_ref(); + assert_eq!(ciphertext, ciphertext_expected); + assert_eq!(tag, tag_expected); + + let mut buffer = MockBuffer::from(buffer.as_ref()); + M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys) + .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 = []; + + 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"); + + type M = modes::DeoxysII; + let cipher = DeoxysII128::new(&key); + let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys); + + let ciphertext = buffer.as_ref(); + assert_eq!(ciphertext, ciphertext_expected); + assert_eq!(tag, tag_expected); + + let mut buffer = MockBuffer::from(buffer.as_ref()); + M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys) + .expect("decryption failed"); + + assert_eq!(&plaintext[..], buffer.as_ref()); + } +} From 6bb51cf8cf86284946e8842ea0cc1f200e8d6d7a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 13 Mar 2025 10:28:09 -0600 Subject: [PATCH 07/16] Migrate to `AeadInOut` Replaces the previous `AeadInPlaceDetached` impls with `AeadInOut`, which was introduced in RustCrypto/traits#1793 --- Cargo.lock | 160 ++----------------------------- Cargo.toml | 16 ++-- aes-gcm-siv/Cargo.toml | 2 +- aes-gcm-siv/src/lib.rs | 36 +++---- aes-gcm/Cargo.toml | 4 +- aes-gcm/src/lib.rs | 22 ++--- aes-gcm/tests/aes128gcm.rs | 2 +- aes-gcm/tests/aes256gcm.rs | 2 +- aes-gcm/tests/common/mod.rs | 2 +- aes-siv/Cargo.toml | 1 + aes-siv/src/lib.rs | 19 ++-- aes-siv/src/siv.rs | 27 +++--- aes-siv/tests/aead.rs | 22 +++-- ccm/src/lib.rs | 17 ++-- ccm/tests/mod.rs | 6 +- chacha20poly1305/src/cipher.rs | 4 +- chacha20poly1305/src/lib.rs | 21 ++-- deoxys/src/lib.rs | 13 +-- eax/src/lib.rs | 20 ++-- ocb3/src/lib.rs | 14 +-- ocb3/tests/kats.rs | 10 +- xaes-256-gcm/src/lib.rs | 16 ++-- xaes-256-gcm/tests/xaes256gcm.rs | 2 +- 23 files changed, 147 insertions(+), 291 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e7a691a..3cf83a5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,13 +6,14 @@ version = 4 [[package]] name = "aead" version = "0.6.0-rc.0" -source = "git+https://github.com/RustCrypto/traits.git#1548d2a7d7ce71a278a783d19d94b59b0103ab15" +source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fbicephalbuffer#a35c5da6b6ea4317c4b8d0a7b49895fc32850021" dependencies = [ "arrayvec", "blobby 0.4.0-pre.0", "bytes", "crypto-common", "heapless", + "inout", ] [[package]] @@ -83,26 +84,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -[[package]] -name = "ascon" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e716048a18530cce4684daf98a7563a499d710e1ed8ef35567fcb43a7c5f1" -dependencies = [ - "zeroize", -] - -[[package]] -name = "ascon-aead" -version = "0.4.2" -dependencies = [ - "aead", - "ascon", - "hex-literal", - "subtle", - "zeroize", -] - [[package]] name = "bitflags" version = "2.9.0" @@ -142,46 +123,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -[[package]] -name = "ccm" -version = "0.5.0" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "hex-literal", - "subtle", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chacha20" -version = "0.10.0-pre.3" -source = "git+https://github.com/RustCrypto/stream-ciphers.git#596cdebf250d7fe8921e18c7288964f50448ae1c" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "zeroize", -] - -[[package]] -name = "chacha20poly1305" -version = "0.11.0-pre.2" -dependencies = [ - "aead", - "chacha20", - "cipher", - "poly1305", - "zeroize", -] - [[package]] name = "cipher" version = "0.5.0-pre.8" @@ -215,7 +162,7 @@ dependencies = [ [[package]] name = "crypto-common" version = "0.2.0-rc.2" -source = "git+https://github.com/RustCrypto/traits.git#1548d2a7d7ce71a278a783d19d94b59b0103ab15" +source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fbicephalbuffer#a35c5da6b6ea4317c4b8d0a7b49895fc32850021" dependencies = [ "hybrid-array", "rand_core", @@ -238,17 +185,6 @@ dependencies = [ "hybrid-array", ] -[[package]] -name = "deoxys" -version = "0.1.0" -dependencies = [ - "aead", - "aes", - "hex-literal", - "subtle", - "zeroize", -] - [[package]] name = "digest" version = "0.11.0-pre.10" @@ -260,18 +196,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "eax" -version = "0.5.0" -dependencies = [ - "aead", - "aes", - "cipher", - "cmac", - "ctr", - "subtle", -] - [[package]] name = "getrandom" version = "0.3.1" @@ -342,21 +266,6 @@ version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" -[[package]] -name = "ocb3" -version = "0.1.0" -dependencies = [ - "aead", - "aead-stream", - "aes", - "cipher", - "ctr", - "dbl", - "hex-literal", - "subtle", - "zeroize", -] - [[package]] name = "opaque-debug" version = "0.3.1" @@ -373,17 +282,6 @@ dependencies = [ "digest", ] -[[package]] -name = "poly1305" -version = "0.9.0-rc.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72844372b6c796d771899186be2c255818fdc21c68d6e2be2c7ffa509ade9df4" -dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", -] - [[package]] name = "polyval" version = "0.7.0-rc.0" @@ -407,24 +305,6 @@ dependencies = [ "universal-hash", ] -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" -dependencies = [ - "proc-macro2", -] - [[package]] name = "rand_core" version = "0.9.3" @@ -446,29 +326,12 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "syn" -version = "2.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - [[package]] name = "universal-hash" version = "0.6.0-rc.0" @@ -578,17 +441,8 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +[[patch.unused]] +name = "chacha20" +version = "0.10.0-pre.3" +source = "git+https://github.com/RustCrypto/stream-ciphers.git#596cdebf250d7fe8921e18c7288964f50448ae1c" diff --git a/Cargo.toml b/Cargo.toml index bfec3ed2..ed2e998f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,12 +4,12 @@ members = [ "aes-gcm", "aes-gcm-siv", "aes-siv", - "ascon-aead", - "ccm", - "chacha20poly1305", - "deoxys", - "eax", - "ocb3", + #"ascon-aead", + #"ccm", + #"chacha20poly1305", + #"deoxys", + #"eax", + #"ocb3", "xaes-256-gcm", ] resolver = "2" @@ -18,8 +18,8 @@ resolver = "2" aead-stream = { path = "./aead-stream" } aes-gcm = { path = "./aes-gcm" } -aead = { git = "https://github.com/RustCrypto/traits.git" } -crypto-common = { git = "https://github.com/RustCrypto/traits.git" } +aead = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/bicephalbuffer" } +crypto-common = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/bicephalbuffer" } chacha20 = { git = "https://github.com/RustCrypto/stream-ciphers.git" } diff --git a/aes-gcm-siv/Cargo.toml b/aes-gcm-siv/Cargo.toml index 33c20ad4..73c48188 100644 --- a/aes-gcm-siv/Cargo.toml +++ b/aes-gcm-siv/Cargo.toml @@ -17,7 +17,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false } +aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } aes = { version = "=0.9.0-pre.3", optional = true } cipher = "=0.5.0-pre.8" ctr = "0.10.0-pre.2" diff --git a/aes-gcm-siv/src/lib.rs b/aes-gcm-siv/src/lib.rs index 7f2ca194..44da07ef 100644 --- a/aes-gcm-siv/src/lib.rs +++ b/aes-gcm-siv/src/lib.rs @@ -78,12 +78,12 @@ //! provide an impl of [`aead::Buffer`] for `bytes::BytesMut` (re-exported from the //! [`aead`] crate as [`aead::bytes::BytesMut`]). -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; #[cfg(feature = "aes")] pub use aes; -use aead::PostfixTagged; +use aead::{PostfixTagged, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, array::Array, @@ -165,28 +165,28 @@ where impl PostfixTagged for AesGcmSiv {} -impl AeadInPlaceDetached for AesGcmSiv +impl AeadInOut for AesGcmSiv where Aes: BlockSizeUser + BlockCipherEncrypt + KeyInit, { - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Nonce, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result { Cipher::::new(&self.key_generating_key, nonce) - .encrypt_in_place_detached(associated_data, buffer) + .encrypt_inout_detached(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> { - Cipher::::new(&self.key_generating_key, nonce).decrypt_in_place_detached( + Cipher::::new(&self.key_generating_key, nonce).decrypt_inout_detached( associated_data, buffer, tag, @@ -268,30 +268,30 @@ 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], + buffer: InOutBuf<'_, '_, u8>, ) -> Result { if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { return Err(Error); } self.polyval.update_padded(associated_data); - self.polyval.update_padded(buffer); + self.polyval.update_padded(buffer.get_in()); let tag = self.finish_tag(associated_data.len(), buffer.len()); - init_ctr(&self.enc_cipher, &tag).apply_keystream_partial(buffer.into()); + init_ctr(&self.enc_cipher, &tag).apply_keystream_partial(buffer); Ok(tag) } /// 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], + mut buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX { @@ -301,8 +301,8 @@ where self.polyval.update_padded(associated_data); // TODO(tarcieri): interleave decryption and authentication - init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.into()); - self.polyval.update_padded(buffer); + init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.reborrow()); + self.polyval.update_padded(buffer.get_out()); let expected_tag = self.finish_tag(associated_data.len(), buffer.len()); @@ -312,7 +312,7 @@ where } else { // On MAC verify failure, re-encrypt the plaintext buffer to // prevent accidental exposure. - init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.into()); + init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer); Err(Error) } } diff --git a/aes-gcm/Cargo.toml b/aes-gcm/Cargo.toml index 0adb5f53..e50a4801 100644 --- a/aes-gcm/Cargo.toml +++ b/aes-gcm/Cargo.toml @@ -17,7 +17,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false } +aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } aes = { version = "=0.9.0-pre.3", optional = true } cipher = "=0.5.0-pre.8" ctr = "0.10.0-pre.2" @@ -26,7 +26,7 @@ subtle = { version = "2", default-features = false } zeroize = { version = "1", optional = true, default-features = false } [dev-dependencies] -aead = { version = "0.6.0-rc.0", features = ["dev"], default-features = false } +aead = { version = "0.6.0-rc.0", features = ["alloc", "dev"], default-features = false } hex-literal = "0.4" [features] diff --git a/aes-gcm/src/lib.rs b/aes-gcm/src/lib.rs index 6b307d68..d7044e75 100644 --- a/aes-gcm/src/lib.rs +++ b/aes-gcm/src/lib.rs @@ -98,12 +98,12 @@ //! provide an impl of [`aead::Buffer`] for `bytes::BytesMut` (re-exported from the //! [`aead`] crate as [`aead::bytes::BytesMut`]). -pub use aead::{self, AeadCore, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; #[cfg(feature = "aes")] pub use aes; -use aead::PostfixTagged; +use aead::{PostfixTagged, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, @@ -260,17 +260,17 @@ impl PostfixTagged for AesGcm { } -impl AeadInPlaceDetached for AesGcm +impl AeadInOut for AesGcm where Aes: BlockSizeUser + BlockCipherEncrypt, NonceSize: ArraySize, TagSize: self::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); @@ -280,17 +280,17 @@ where // TODO(tarcieri): interleave encryption with GHASH // See: - ctr.apply_keystream_partial(buffer.into()); + ctr.apply_keystream_partial(buffer.reborrow()); - let full_tag = self.compute_tag(mask, associated_data, buffer); + let full_tag = self.compute_tag(mask, associated_data, buffer.get_out()); Ok(Tag::try_from(&full_tag[..TagSize::to_usize()]).expect("tag size mismatch")) } - 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 { @@ -301,11 +301,11 @@ where // TODO(tarcieri): interleave encryption with GHASH // See: - let expected_tag = self.compute_tag(mask, associated_data, buffer); + let expected_tag = self.compute_tag(mask, associated_data, buffer.get_in()); use subtle::ConstantTimeEq; if expected_tag[..TagSize::to_usize()].ct_eq(tag).into() { - ctr.apply_keystream_partial(buffer.into()); + ctr.apply_keystream_partial(buffer); Ok(()) } else { Err(Error) diff --git a/aes-gcm/tests/aes128gcm.rs b/aes-gcm/tests/aes128gcm.rs index 1e0f82e0..819a631b 100644 --- a/aes-gcm/tests/aes128gcm.rs +++ b/aes-gcm/tests/aes128gcm.rs @@ -7,7 +7,7 @@ mod common; use self::common::TestVector; use aes_gcm::Aes128Gcm; -use aes_gcm::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; +use aes_gcm::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; use hex_literal::hex; /// NIST CAVS vectors diff --git a/aes-gcm/tests/aes256gcm.rs b/aes-gcm/tests/aes256gcm.rs index e56e5110..7f0ea0b5 100644 --- a/aes-gcm/tests/aes256gcm.rs +++ b/aes-gcm/tests/aes256gcm.rs @@ -7,7 +7,7 @@ mod common; use self::common::TestVector; use aes_gcm::Aes256Gcm; -use aes_gcm::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; +use aes_gcm::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; use hex_literal::hex; /// NIST CAVS vectors diff --git a/aes-gcm/tests/common/mod.rs b/aes-gcm/tests/common/mod.rs index 5833b250..ef1dd674 100644 --- a/aes-gcm/tests/common/mod.rs +++ b/aes-gcm/tests/common/mod.rs @@ -92,7 +92,7 @@ macro_rules! tests { let cipher = <$aead>::new(&key); assert!( cipher - .decrypt_in_place_detached(&nonce, &[], &mut buffer, &tag) + .decrypt_inout_detached(&nonce, &[], buffer.as_mut_slice().into(), &tag) .is_err() ); diff --git a/aes-siv/Cargo.toml b/aes-siv/Cargo.toml index 2f1faac7..d290c7a7 100644 --- a/aes-siv/Cargo.toml +++ b/aes-siv/Cargo.toml @@ -32,6 +32,7 @@ pmac = { version = "0.8.0-pre.2", optional = true } [dev-dependencies] blobby = "0.3" hex-literal = "0.4" +aead = { version = "0.6.0-rc.0", features = ["alloc", "dev"], default-features = false } [features] default = ["alloc", "os_rng"] diff --git a/aes-siv/src/lib.rs b/aes-siv/src/lib.rs index 9fd9e289..592e03ab 100644 --- a/aes-siv/src/lib.rs +++ b/aes-siv/src/lib.rs @@ -83,15 +83,14 @@ extern crate alloc; pub mod siv; -pub use aead::{ - self, AeadCore, AeadInPlace, AeadInPlaceDetached, Error, Key, KeyInit, KeySizeUser, -}; +pub use aead::{self, AeadCore, AeadInOut, AeadInPlace, Error, Key, KeyInit, KeySizeUser}; use crate::siv::Siv; use aead::{ Buffer, array::Array, consts::{U1, U16, U32, U64}, + inout::InOutBuf, }; use aes::{Aes128, Aes256}; use cipher::{BlockCipherEncrypt, BlockSizeUser, array::ArraySize, typenum::IsGreaterOrEqual}; @@ -241,7 +240,7 @@ where } } -impl AeadInPlaceDetached for SivAead +impl AeadInOut for SivAead where Self: KeySizeUser, Siv: KeyInit + KeySizeUser::KeySize>, @@ -250,24 +249,24 @@ where ::KeySize: Add, NonceSize: ArraySize + IsGreaterOrEqual, { - fn encrypt_in_place_detached( + fn encrypt_inout_detached( &self, nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { Siv::::new(&self.key) - .encrypt_in_place_detached([associated_data, nonce.as_slice()], buffer) + .encrypt_inout_detached([associated_data, nonce.as_slice()], buffer) } - fn decrypt_in_place_detached( + fn decrypt_inout_detached( &self, nonce: &Array, associated_data: &[u8], - buffer: &mut [u8], + buffer: InOutBuf<'_, '_, u8>, tag: &Array, ) -> Result<(), Error> { - Siv::::new(&self.key).decrypt_in_place_detached( + Siv::::new(&self.key).decrypt_inout_detached( [associated_data, nonce.as_slice()], buffer, tag, diff --git a/aes-siv/src/siv.rs b/aes-siv/src/siv.rs index 7880ec2e..2f646e42 100644 --- a/aes-siv/src/siv.rs +++ b/aes-siv/src/siv.rs @@ -72,6 +72,7 @@ use crate::Tag; use aead::{ Buffer, Error, array::{Array, ArraySize, typenum::U16}, + inout::InOutBuf, }; use aes::{Aes128, Aes256}; use cipher::{ @@ -209,10 +210,10 @@ where // Make room in the buffer for the SIV tag. It needs to be prepended. buffer.extend_from_slice(Tag::default().as_slice())?; - // TODO(tarcieri): add offset param to `encrypt_in_place_detached` + // TODO(tarcieri): add offset param to `encrypt_inout_detached` buffer.as_mut().copy_within(..pt_len, IV_SIZE); - let tag = self.encrypt_in_place_detached(headers, &mut buffer.as_mut()[IV_SIZE..])?; + let tag = self.encrypt_inout_detached(headers, (&mut buffer.as_mut()[IV_SIZE..]).into())?; buffer.as_mut()[..IV_SIZE].copy_from_slice(tag.as_slice()); Ok(()) } @@ -223,17 +224,17 @@ where /// /// Returns [`Error`] if `plaintext.len()` is less than `M::OutputSize`. /// Returns [`Error`] if `headers.len()` is greater than [`MAX_HEADERS`]. - pub fn encrypt_in_place_detached( + pub fn encrypt_inout_detached( &mut self, headers: I, - plaintext: &mut [u8], + plaintext: InOutBuf<'_, '_, u8>, ) -> Result where I: IntoIterator, T: AsRef<[u8]>, { // Compute the synthetic IV for this plaintext - let siv_tag = s2v(&mut self.mac, headers, plaintext)?; + let siv_tag = s2v(&mut self.mac, headers, plaintext.get_in())?; self.xor_with_keystream(siv_tag, plaintext); Ok(siv_tag) } @@ -270,11 +271,11 @@ where } let siv_tag = Tag::try_from(&buffer.as_ref()[..IV_SIZE]).expect("tag size mismatch"); - self.decrypt_in_place_detached(headers, &mut buffer.as_mut()[IV_SIZE..], &siv_tag)?; + self.decrypt_inout_detached(headers, (&mut buffer.as_mut()[IV_SIZE..]).into(), &siv_tag)?; let pt_len = buffer.len() - IV_SIZE; - // TODO(tarcieri): add offset param to `encrypt_in_place_detached` + // TODO(tarcieri): add offset param to `encrypt_inout_detached` buffer.as_mut().copy_within(IV_SIZE.., 0); buffer.truncate(pt_len); Ok(()) @@ -286,18 +287,18 @@ where /// # Errors /// /// Returns [`Error`] if the ciphertext is not authentic - pub fn decrypt_in_place_detached( + pub fn decrypt_inout_detached( &mut self, headers: I, - ciphertext: &mut [u8], + mut ciphertext: InOutBuf<'_, '_, u8>, siv_tag: &Tag, ) -> Result<(), Error> where I: IntoIterator, T: AsRef<[u8]>, { - self.xor_with_keystream(*siv_tag, ciphertext); - let computed_siv_tag = s2v(&mut self.mac, headers, ciphertext)?; + self.xor_with_keystream(*siv_tag, ciphertext.reborrow()); + let computed_siv_tag = s2v(&mut self.mac, headers, ciphertext.get_out())?; // Note: `CtOutput` provides constant-time equality if CtOutput::::new(computed_siv_tag) == CtOutput::new(*siv_tag) { @@ -310,7 +311,7 @@ where } /// XOR the given buffer with the keystream for the given IV - fn xor_with_keystream(&mut self, mut iv: Tag, msg: &mut [u8]) { + fn xor_with_keystream(&mut self, mut iv: Tag, msg: InOutBuf<'_, '_, u8>) { // "We zero-out the top bit in each of the last two 32-bit words // of the IV before assigning it to Ctr" // — http://web.cs.ucdavis.edu/~rogaway/papers/siv.pdf @@ -318,7 +319,7 @@ where iv[12] &= 0x7f; Ctr128BE::::inner_iv_init(C::new(&self.encryption_key), &iv) - .apply_keystream_partial(msg.into()); + .apply_keystream_partial(msg); } } diff --git a/aes-siv/tests/aead.rs b/aes-siv/tests/aead.rs index ea61a96a..96a66190 100644 --- a/aes-siv/tests/aead.rs +++ b/aes-siv/tests/aead.rs @@ -32,19 +32,20 @@ macro_rules! tests { } #[test] - fn encrypt_in_place_detached() { + fn encrypt_inout_detached() { for vector in $vectors { let key = Array(*vector.key); let nonce = Array(*vector.nonce); - let mut buffer = vector.plaintext.to_vec(); + let buffer = vector.plaintext.to_vec(); + let mut buffer = aead::dev::MockBuffer::from(buffer); let cipher = <$aead>::new(&key); let tag = cipher - .encrypt_in_place_detached(&nonce, vector.aad, &mut buffer) + .encrypt_inout_detached(&nonce, vector.aad, buffer.to_in_out_buf()) .unwrap(); let (expected_tag, expected_ciphertext) = vector.ciphertext.split_at(16); assert_eq!(expected_tag, &tag[..]); - assert_eq!(expected_ciphertext, &buffer[..]); + assert_eq!(expected_ciphertext, buffer.as_ref()); } } @@ -67,18 +68,19 @@ macro_rules! tests { } #[test] - fn decrypt_in_place_detached() { + fn decrypt_inout_detached() { for vector in $vectors { let key = Array(*vector.key); let nonce = Array(*vector.nonce); let tag = Array::try_from(&vector.ciphertext[..16]).unwrap(); - let mut buffer = vector.ciphertext[16..].to_vec(); + let buffer = vector.ciphertext[16..].to_vec(); + let mut buffer = aead::dev::MockBuffer::from(buffer); <$aead>::new(&key) - .decrypt_in_place_detached(&nonce, vector.aad, &mut buffer, &tag) + .decrypt_inout_detached(&nonce, vector.aad, buffer.to_in_out_buf(), &tag) .unwrap(); - assert_eq!(vector.plaintext, buffer.as_slice()); + assert_eq!(vector.plaintext, buffer.as_ref()); } } @@ -108,7 +110,7 @@ macro_rules! tests { mod aes128cmacsivaead { use super::TestVector; use aes_siv::Aes128SivAead; - use aes_siv::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; + use aes_siv::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; /// AES-128-CMAC-SIV test vectors const TEST_VECTORS: &[TestVector<[u8; 32]>] = &[TestVector { @@ -132,7 +134,7 @@ mod aes128cmacsivaead { mod aes128pmacsivaead { use super::TestVector; use aes_siv::Aes128PmacSivAead; - use aes_siv::aead::{Aead, AeadInPlaceDetached, KeyInit, Payload, array::Array}; + use aes_siv::aead::{Aead, AeadInOut, KeyInit, Payload, array::Array}; /// AES-128-PMAC-SIV test vectors const AES_128_PMAC_SIV_TEST_VECTORS: &[TestVector<[u8; 32]>] = &[TestVector { diff --git a/ccm/src/lib.rs b/ccm/src/lib.rs index bd51999b..a9200aa6 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, consts, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; use aead::{ - PostfixTagged, - array::{Array, ArraySize, typenum::Unsigned}, + array::{typenum::Unsigned, Array, ArraySize}, consts::U16, + inout::InOutBuf, + PostfixTagged, }; use cipher::{ Block, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipher, StreamCipherSeek, @@ -221,17 +222,17 @@ where { } -impl AeadInPlaceDetached for Ccm +impl AeadInOut 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)?; @@ -252,11 +253,11 @@ where 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], + buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { let ext_nonce = Self::extend_nonce(nonce); diff --git a/ccm/tests/mod.rs b/ccm/tests/mod.rs index 10ce7276..aa393c7e 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, &[], &mut buf1); 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, &[], &mut buf2); assert!(res.is_err()); } diff --git a/chacha20poly1305/src/cipher.rs b/chacha20poly1305/src/cipher.rs index 76bb4bf8..b04a2058 100644 --- a/chacha20poly1305/src/cipher.rs +++ b/chacha20poly1305/src/cipher.rs @@ -50,7 +50,7 @@ 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], @@ -72,7 +72,7 @@ where /// 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], diff --git a/chacha20poly1305/src/lib.rs b/chacha20poly1305/src/lib.rs index c42e057d..a021df7f 100644 --- a/chacha20poly1305/src/lib.rs +++ b/chacha20poly1305/src/lib.rs @@ -139,7 +139,7 @@ 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}; @@ -147,6 +147,7 @@ use aead::{ PostfixTagged, array::{Array, ArraySize}, consts::{U12, U16, U24, U32}, + inout::InOutBuf, }; use core::marker::PhantomData; @@ -254,32 +255,28 @@ where { } -impl AeadInPlaceDetached for ChaChaPoly1305 +impl AeadInOut 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/src/lib.rs b/deoxys/src/lib.rs index 63df0f7b..a7a20dc4 100644 --- a/deoxys/src/lib.rs +++ b/deoxys/src/lib.rs @@ -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, array::{Array, ArraySize}, consts::U16, + inout::InOutBuf, }; use core::marker::PhantomData; @@ -274,16 +275,16 @@ where { } -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( nonce, @@ -293,11 +294,11 @@ 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) diff --git a/eax/src/lib.rs b/eax/src/lib.rs index c4d6cf03..e619c305 100644 --- a/eax/src/lib.rs +++ b/eax/src/lib.rs @@ -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"", &mut buffer).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"", &mut buffer, &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::{PostfixTagged, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, array::Array, consts::U16, crypto_common::OutputSizeUser, typenum::Unsigned, @@ -219,16 +219,16 @@ where { } -impl AeadInPlaceDetached for Eax +impl AeadInOut 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], + buffer: InOutBuf<'_, '_, u8>, ) -> Result, Error> { if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX { return Err(Error); @@ -267,11 +267,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 { diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index a6808ff9..261a863e 100644 --- a/ocb3/src/lib.rs +++ b/ocb3/src/lib.rs @@ -14,11 +14,11 @@ 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::{PostfixTagged, array::ArraySize, inout::InOutBuf}; use cipher::{ BlockCipherDecrypt, BlockCipherEncrypt, BlockSizeUser, consts::{U12, U16}, @@ -198,17 +198,17 @@ where { } -impl AeadInPlaceDetached for Ocb3 +impl AeadInOut 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!() @@ -263,11 +263,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: &aead::Tag, ) -> aead::Result<()> { let expected_tag = self.decrypt_in_place_return_tag(nonce, associated_data, buffer); diff --git a/ocb3/tests/kats.rs b/ocb3/tests/kats.rs index 7181c5c9..b58069d7 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,7 @@ 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, &mut buffer) .unwrap(); ciphertext.append(&mut buffer); ciphertext.append(&mut tag.as_slice().to_vec()); @@ -48,7 +48,7 @@ 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(), &[], &mut buffer) .unwrap(); ciphertext.append(&mut buffer); ciphertext.append(&mut tag.as_slice().to_vec()); @@ -57,7 +57,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 []) .unwrap(); ciphertext.append(&mut tag.as_slice().to_vec()); } @@ -75,7 +75,7 @@ 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 []) .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..362eb574 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, PostfixTagged, array::Array, inout::InOutBuf, }; use aes::Aes256; use aes_gcm::Aes256Gcm; @@ -128,12 +128,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 +141,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 +157,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; From 3eddf5a2dd884b6a8df45cacedf199c9445327ba Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 16 Mar 2025 14:17:05 -0700 Subject: [PATCH 08/16] ocb3: migrate internals to use inout --- Cargo.lock | 1 + ocb3/Cargo.toml | 1 + ocb3/src/lib.rs | 138 +++++++++++++++++++++++++++--------------------- 3 files changed, 80 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e7a691a..0fcdba4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,6 +353,7 @@ dependencies = [ "ctr", "dbl", "hex-literal", + "inout", "subtle", "zeroize", ] diff --git a/ocb3/Cargo.toml b/ocb3/Cargo.toml index 4e7fd1c2..74991c49 100644 --- a/ocb3/Cargo.toml +++ b/ocb3/Cargo.toml @@ -23,6 +23,7 @@ dbl = "0.4.0-rc.2" subtle = { version = "2", default-features = false } aead-stream = { version = "=0.6.0-pre", optional = true, default-features = false } zeroize = { version = "1", optional = true, default-features = false } +inout = { version = "0.2.0-rc.4", default-features = false } [dev-dependencies] aead = { version = "0.6.0-rc.0", features = ["dev"], default-features = false } diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index a6808ff9..df04d9d7 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. @@ -21,11 +21,12 @@ pub use aead::{ use aead::{PostfixTagged, array::ArraySize}; 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 inout::{InOut, InOutBuf}; use subtle::ConstantTimeEq; /// Number of L values to be precomputed. Precomputing m values, allows @@ -55,7 +56,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::{ @@ -210,34 +213,36 @@ where associated_data: &[u8], buffer: &mut [u8], ) -> aead::Result> { + let buffer = InOutBuf::from(buffer); 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 +252,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); @@ -295,32 +298,32 @@ where if (buffer.len() > C_MAX) || (associated_data.len() > A_MAX) { unimplemented!() } + let buffer = InOutBuf::from(buffer); // 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 +332,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,7 +348,11 @@ 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; @@ -355,12 +360,13 @@ where let mut offset_i = [Block::default(); WIDTH]; offset_i[offset_i.len() - 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)} @@ -373,23 +379,25 @@ where // 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; @@ -397,8 +405,10 @@ where let mut offset_i = [Block::default(); WIDTH]; offset_i[offset_i.len() - 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]; @@ -411,17 +421,16 @@ where // 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 +589,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)] From 0dfdea406003862d78159ce59cbeb54074cc4e14 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 17 Mar 2025 13:37:24 -0700 Subject: [PATCH 09/16] ascon-aead: rewrite internals to use inout --- Cargo.lock | 1 + ascon-aead/Cargo.toml | 1 + ascon-aead/src/asconcore.rs | 62 ++++++++++++++++++++----------------- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e7a691a..c2f67d57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,6 +99,7 @@ dependencies = [ "aead", "ascon", "hex-literal", + "inout", "subtle", "zeroize", ] diff --git a/ascon-aead/Cargo.toml b/ascon-aead/Cargo.toml index a20e14df..5120782d 100644 --- a/ascon-aead/Cargo.toml +++ b/ascon-aead/Cargo.toml @@ -19,6 +19,7 @@ aead = { version = "0.6.0-rc.0", default-features = false } subtle = { version = "2", default-features = false } zeroize = { version = "1.6", optional = true, default-features = false, features = ["derive"] } ascon = "0.4" +inout = { version = "0.2.0-rc.4", default-features = false } [dev-dependencies] hex-literal = "0.4" diff --git a/ascon-aead/src/asconcore.rs b/ascon-aead/src/asconcore.rs index 2cd828bf..142c411a 100644 --- a/ascon-aead/src/asconcore.rs +++ b/ascon-aead/src/asconcore.rs @@ -7,6 +7,7 @@ use aead::{ consts::U16, }; use ascon::State; +use inout::InOutBuf; use subtle::ConstantTimeEq; /// Produce mask for padding. @@ -170,63 +171,68 @@ impl<'a, P: Parameters> AsconCore<'a, P> { self.state[4] ^= 0x8000000000000000; } - fn process_encrypt_inplace(&mut self, message: &mut [u8]) { - let mut blocks = message.chunks_exact_mut(16); - for block in blocks.by_ref() { + fn process_encrypt_inout(&mut self, message: InOutBuf<'_, '_, u8>) { + let (blocks, mut last_block) = message.into_chunks::(); + + for mut block in blocks { // process full block of message - self.state[0] ^= u64_from_bytes(&block[..8]); - block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); - self.state[1] ^= u64_from_bytes(&block[8..16]); - block[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1])); + self.state[0] ^= u64_from_bytes(&block.get_in()[..8]); + block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); + self.state[1] ^= u64_from_bytes(&block.get_in()[8..16]); + block.get_out()[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1])); self.permute_state(); } // process partial block if it exists - let mut last_block = blocks.into_remainder(); let sidx = if last_block.len() >= 8 { - self.state[0] ^= u64_from_bytes(&last_block[..8]); - last_block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); - last_block = &mut last_block[8..]; + self.state[0] ^= u64_from_bytes(&last_block.get_in()[..8]); + last_block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0])); + (_, last_block) = last_block.split_at(8); 1 } else { 0 }; self.state[sidx] ^= pad(last_block.len()); if !last_block.is_empty() { - self.state[sidx] ^= u64_from_bytes_partial(last_block); - last_block.copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block.len()]); + self.state[sidx] ^= u64_from_bytes_partial(last_block.get_in()); + let last_block_len = last_block.len(); + last_block + .get_out() + .copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block_len]); } } - fn process_decrypt_inplace(&mut self, ciphertext: &mut [u8]) { - let mut blocks = ciphertext.chunks_exact_mut(16); - for block in blocks.by_ref() { + fn process_decrypt_inout(&mut self, ciphertext: InOutBuf<'_, '_, u8>) { + let (blocks, mut last_block) = ciphertext.into_chunks::(); + for mut block in blocks { // process full block of ciphertext - let cx = u64_from_bytes(&block[..8]); - block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); + let cx = u64_from_bytes(&block.get_in()[..8]); + block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); self.state[0] = cx; - let cx = u64_from_bytes(&block[8..16]); - block[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1] ^ cx)); + let cx = u64_from_bytes(&block.get_in()[8..16]); + block.get_out()[8..16].copy_from_slice(&u64::to_le_bytes(self.state[1] ^ cx)); self.state[1] = cx; self.permute_state(); } // process partial block if it exists - let mut last_block = blocks.into_remainder(); let sidx = if last_block.len() >= 8 { - let cx = u64_from_bytes(&last_block[..8]); - last_block[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); + let cx = u64_from_bytes(&last_block.get_in()[..8]); + last_block.get_out()[..8].copy_from_slice(&u64::to_le_bytes(self.state[0] ^ cx)); self.state[0] = cx; - last_block = &mut last_block[8..]; + (_, last_block) = last_block.split_at(8); 1 } else { 0 }; self.state[sidx] ^= pad(last_block.len()); if !last_block.is_empty() { - let cx = u64_from_bytes_partial(last_block); + let cx = u64_from_bytes_partial(last_block.get_in()); self.state[sidx] ^= cx; - last_block.copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block.len()]); + let last_block_len = last_block.len(); + last_block + .get_out() + .copy_from_slice(&u64::to_le_bytes(self.state[sidx])[0..last_block_len]); self.state[sidx] = clear(self.state[sidx], last_block.len()) ^ cx; } } @@ -248,7 +254,7 @@ impl<'a, P: Parameters> AsconCore<'a, P> { associated_data: &[u8], ) -> Array { self.process_associated_data(associated_data); - self.process_encrypt_inplace(message); + self.process_encrypt_inout(message.into()); Array::from(self.process_final()) } @@ -259,7 +265,7 @@ impl<'a, P: Parameters> AsconCore<'a, P> { expected_tag: &Array, ) -> Result<(), Error> { self.process_associated_data(associated_data); - self.process_decrypt_inplace(ciphertext); + self.process_decrypt_inout(ciphertext.into()); let tag = self.process_final(); if bool::from(tag.ct_eq(expected_tag)) { From 5342fd04c92b6a8aba94e234dde20ae94cf19c56 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 14 Mar 2025 20:13:38 -0700 Subject: [PATCH 10/16] ccm: migrate to `AeadInOut` --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 2 +- ccm/Cargo.toml | 2 +- ccm/src/lib.rs | 22 +++++++++++----------- ccm/tests/mod.rs | 4 ++-- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ae67b4d..a76724ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,6 +144,18 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "ccm" +version = "0.5.0" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "hex-literal", + "subtle", +] + [[package]] name = "cfg-if" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 8b055667..1697e7fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "aes-gcm-siv", "aes-siv", "ascon-aead", - #"ccm", + "ccm", #"chacha20poly1305", #"deoxys", #"eax", diff --git a/ccm/Cargo.toml b/ccm/Cargo.toml index cc43be2a..54324b8d 100644 --- a/ccm/Cargo.toml +++ b/ccm/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["encryption", "aead"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false } +aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } cipher = { version = "=0.5.0-pre.8", default-features = false } ctr = { version = "0.10.0-pre.2", default-features = false } subtle = { version = "2", default-features = false } diff --git a/ccm/src/lib.rs b/ccm/src/lib.rs index a9200aa6..7284220a 100644 --- a/ccm/src/lib.rs +++ b/ccm/src/lib.rs @@ -42,13 +42,13 @@ //! [aead]: https://docs.rs/aead //! [1]: https://en.wikipedia.org/wiki/Authenticated_encryption -pub use aead::{self, consts, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, consts}; use aead::{ - array::{typenum::Unsigned, Array, ArraySize}, + PostfixTagged, + array::{Array, ArraySize, typenum::Unsigned}, consts::U16, inout::InOutBuf, - PostfixTagged, }; use cipher::{ Block, BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipher, StreamCipherSeek, @@ -234,7 +234,7 @@ where adata: &[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) @@ -243,11 +243,11 @@ 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")) @@ -257,7 +257,7 @@ where &self, nonce: &Nonce, adata: &[u8], - buffer: InOutBuf<'_, '_, u8>, + mut buffer: InOutBuf<'_, '_, u8>, tag: &Tag, ) -> Result<(), Error> { let ext_nonce = Self::extend_nonce(nonce); @@ -267,14 +267,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)); @@ -287,7 +287,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 aa393c7e..f4b20fb8 100644 --- a/ccm/tests/mod.rs +++ b/ccm/tests/mod.rs @@ -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_inout_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_inout_detached(&nonce, &[], &mut buf2); + let res = c.encrypt_inout_detached(&nonce, &[], buf2.as_mut_slice().into()); assert!(res.is_err()); } From 8cd0cd0434d710cad7991572683c7a4aa01b66c5 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 14 Mar 2025 20:38:30 -0700 Subject: [PATCH 11/16] chacha20poly1305: migrate to `AeadInOut` --- Cargo.lock | 38 +++++++++++++++++++++++++++++----- Cargo.toml | 2 +- chacha20poly1305/Cargo.toml | 2 +- chacha20poly1305/src/cipher.rs | 18 ++++++++-------- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a76724ab..688fc244 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,6 +162,28 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chacha20" +version = "0.10.0-pre.3" +source = "git+https://github.com/RustCrypto/stream-ciphers.git#596cdebf250d7fe8921e18c7288964f50448ae1c" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "zeroize", +] + +[[package]] +name = "chacha20poly1305" +version = "0.11.0-pre.2" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "cipher" version = "0.5.0-pre.8" @@ -315,6 +337,17 @@ dependencies = [ "digest", ] +[[package]] +name = "poly1305" +version = "0.9.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72844372b6c796d771899186be2c255818fdc21c68d6e2be2c7ffa509ade9df4" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "polyval" version = "0.7.0-rc.0" @@ -523,8 +556,3 @@ dependencies = [ "quote", "syn", ] - -[[patch.unused]] -name = "chacha20" -version = "0.10.0-pre.3" -source = "git+https://github.com/RustCrypto/stream-ciphers.git#596cdebf250d7fe8921e18c7288964f50448ae1c" diff --git a/Cargo.toml b/Cargo.toml index 1697e7fb..27131867 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ members = [ "aes-siv", "ascon-aead", "ccm", - #"chacha20poly1305", + "chacha20poly1305", #"deoxys", #"eax", #"ocb3", diff --git a/chacha20poly1305/Cargo.toml b/chacha20poly1305/Cargo.toml index 6be0a7ca..51d184dc 100644 --- a/chacha20poly1305/Cargo.toml +++ b/chacha20poly1305/Cargo.toml @@ -20,7 +20,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false } +aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } chacha20 = { version = "=0.10.0-pre.3", default-features = false, features = ["xchacha"] } cipher = "=0.5.0-pre.8" poly1305 = "0.9.0-rc.0" diff --git a/chacha20poly1305/src/cipher.rs b/chacha20poly1305/src/cipher.rs index b04a2058..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}, @@ -53,7 +53,7 @@ where 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,10 +63,10 @@ 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()) } @@ -75,7 +75,7 @@ where 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) From 00db7bcaea622ff14ebccf8e80b12054d9d50c7f Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 14 Mar 2025 21:10:16 -0700 Subject: [PATCH 12/16] eax: migrate to `AeadInOut` --- Cargo.lock | 12 ++++++++++++ Cargo.toml | 2 +- eax/Cargo.toml | 2 +- eax/src/lib.rs | 14 +++++++------- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 688fc244..58503e69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -251,6 +251,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "eax" +version = "0.5.0" +dependencies = [ + "aead", + "aes", + "cipher", + "cmac", + "ctr", + "subtle", +] + [[package]] name = "getrandom" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 27131867..5d6dbed4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ "ccm", "chacha20poly1305", #"deoxys", - #"eax", + "eax", #"ocb3", "xaes-256-gcm", ] diff --git a/eax/Cargo.toml b/eax/Cargo.toml index 9152c064..0da78b09 100644 --- a/eax/Cargo.toml +++ b/eax/Cargo.toml @@ -20,7 +20,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false } +aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } cipher = "=0.5.0-pre.8" cmac = "0.8.0-pre.2" ctr = "0.10.0-pre.2" diff --git a/eax/src/lib.rs b/eax/src/lib.rs index e619c305..bd41170f 100644 --- a/eax/src/lib.rs +++ b/eax/src/lib.rs @@ -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_inout_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,7 +119,7 @@ //! assert_ne!(&buffer, b"plaintext message"); //! //! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext -//! cipher.decrypt_inout_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"); //! # } //! ``` @@ -228,7 +228,7 @@ where &self, nonce: &Nonce, associated_data: &[u8], - buffer: InOutBuf<'_, '_, 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 +247,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) @@ -285,7 +285,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 +305,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 { From a897c0c718c8c266c35b214c775bb558b4ee5be9 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 17 Mar 2025 20:05:02 -0700 Subject: [PATCH 13/16] ocb3: remove useless loops --- ocb3/src/lib.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index df04d9d7..8bb76a86 100644 --- a/ocb3/src/lib.rs +++ b/ocb3/src/lib.rs @@ -358,7 +358,7 @@ where 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(); let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks(); @@ -370,12 +370,10 @@ where } // 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() { @@ -403,7 +401,7 @@ where 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(); let (wide_blocks, tail): (InOutBuf<'_, '_, DoubleBlock>, _) = buffer.into_chunks(); @@ -411,12 +409,10 @@ where 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 From 1116109c13fe50dc8b9f3dbaefe85a2c1b2fb6e6 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 16 Mar 2025 23:00:23 -0700 Subject: [PATCH 14/16] deoxys: migrate inout tests to integration tests --- deoxys/src/lib.rs | 111 ------------------------------------ deoxys/tests/mock_buffer.rs | 82 ++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 111 deletions(-) create mode 100644 deoxys/tests/mock_buffer.rs diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs index f405ba8d..dd95a219 100644 --- a/deoxys/src/lib.rs +++ b/deoxys/src/lib.rs @@ -324,114 +324,3 @@ where B: DeoxysBcType, { } - -#[cfg(test)] -mod tests { - //! 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 hex_literal::hex; - - use super::*; - - struct MockBuffer { - in_buf: [u8; 33], - out_buf: [u8; 33], - } - - impl From<&[u8]> for MockBuffer { - fn from(buf: &[u8]) -> Self { - let mut in_buf = [0u8; 33]; - in_buf.copy_from_slice(buf); - Self { - in_buf, - out_buf: [0u8; 33], - } - } - } - - impl MockBuffer { - /// Get an [`InOutBuf`] from a [`MockBuffer`] - pub fn to_in_out_buf(&mut self) -> InOutBuf<'_, '_, u8> { - InOutBuf::new(self.in_buf.as_slice(), self.out_buf.as_mut_slice()) - .expect("Invariant violation") - } - } - - impl AsRef<[u8]> for MockBuffer { - fn as_ref(&self) -> &[u8] { - &self.out_buf - } - } - - #[test] - fn test_deoxys_i_128_5() { - let plaintext = hex!("5a4c652cb880808707230679224b11799b5883431292973215e9bd03cf3bc32fe4"); - let mut buffer = MockBuffer::from(&plaintext[..]); - - let aad = []; - - 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"); - - type M = modes::DeoxysI; - let cipher = DeoxysI128::new(&key); - let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys); - - let ciphertext = buffer.as_ref(); - assert_eq!(ciphertext, ciphertext_expected); - assert_eq!(tag, tag_expected); - - let mut buffer = MockBuffer::from(buffer.as_ref()); - M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys) - .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 = []; - - 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"); - - type M = modes::DeoxysII; - let cipher = DeoxysII128::new(&key); - let tag: Tag = M::encrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &cipher.subkeys); - - let ciphertext = buffer.as_ref(); - assert_eq!(ciphertext, ciphertext_expected); - assert_eq!(tag, tag_expected); - - let mut buffer = MockBuffer::from(buffer.as_ref()); - M::decrypt_inout(&nonce, &aad, buffer.to_in_out_buf(), &tag, &cipher.subkeys) - .expect("decryption failed"); - - assert_eq!(&plaintext[..], buffer.as_ref()); - } -} 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()); +} From 1bd4230771e2104a3f8360e74850a2d73b817880 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 17 Mar 2025 14:06:48 -0700 Subject: [PATCH 15/16] ascon-aead: implement tests with MockBuffer --- ascon-aead/Cargo.toml | 2 +- ascon-aead/tests/kats_test.rs | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ascon-aead/Cargo.toml b/ascon-aead/Cargo.toml index a1dd3ea9..faff8b93 100644 --- a/ascon-aead/Cargo.toml +++ b/ascon-aead/Cargo.toml @@ -23,7 +23,7 @@ inout = { version = "0.2.0-rc.4", default-features = false } [dev-dependencies] hex-literal = "0.4" -aead = { version = "0.6.0-rc.0", features = ["alloc"] } +aead = { version = "0.6.0-rc.0", features = ["alloc", "dev"] } [features] default = ["alloc", "os_rng"] diff --git a/ascon-aead/tests/kats_test.rs b/ascon-aead/tests/kats_test.rs index a5ae40b7..dedf9341 100644 --- a/ascon-aead/tests/kats_test.rs +++ b/ascon-aead/tests/kats_test.rs @@ -3,7 +3,7 @@ use ascon_aead::{ AsconAead128, - aead::{Aead, AeadInOut, KeyInit, Payload, Tag}, + aead::{Aead, AeadInOut, KeyInit, Payload, Tag, dev::MockBuffer}, }; use hex_literal::hex; @@ -44,6 +44,24 @@ fn run_tv( 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] From e3a251ca6a60c52fc44d86aaebdf745c9f810264 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 18 Mar 2025 11:14:50 -0700 Subject: [PATCH 16/16] Move AeadInPlace into Aead and add a const TAG_POSITION to AeadCore --- Cargo.lock | 4 ++-- Cargo.toml | 4 ++-- aead-stream/src/lib.rs | 26 +++++++++++------------ aes-gcm-siv/Cargo.toml | 2 +- aes-gcm-siv/src/lib.rs | 9 ++++---- aes-gcm/Cargo.toml | 2 +- aes-gcm/src/lib.rs | 12 ++++------- aes-siv/src/lib.rs | 42 +++++-------------------------------- ascon-aead/Cargo.toml | 2 +- ascon-aead/src/lib.rs | 14 +++++-------- ccm/Cargo.toml | 2 +- ccm/src/lib.rs | 11 ++-------- chacha20poly1305/Cargo.toml | 2 +- chacha20poly1305/src/lib.rs | 14 ++++--------- deoxys/Cargo.toml | 2 +- deoxys/src/lib.rs | 14 ++++--------- eax/Cargo.toml | 2 +- eax/src/lib.rs | 14 ++++--------- ocb3/Cargo.toml | 2 +- ocb3/src/lib.rs | 11 ++-------- xaes-256-gcm/src/lib.rs | 5 ++--- 21 files changed, 61 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2db5e7eb..43016a75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,7 +6,7 @@ version = 4 [[package]] name = "aead" version = "0.6.0-rc.0" -source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fbicephalbuffer#a35c5da6b6ea4317c4b8d0a7b49895fc32850021" +source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fmockbuffer-merge#38a7ef2feea0a0bdf8f27d496c945968c272d934" dependencies = [ "arrayvec", "blobby 0.4.0-pre.0", @@ -217,7 +217,7 @@ dependencies = [ [[package]] name = "crypto-common" version = "0.2.0-rc.2" -source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fbicephalbuffer#a35c5da6b6ea4317c4b8d0a7b49895fc32850021" +source = "git+https://github.com/baloo/traits.git?branch=baloo%2Faead%2Fmockbuffer-merge#38a7ef2feea0a0bdf8f27d496c945968c272d934" dependencies = [ "hybrid-array", "rand_core", diff --git a/Cargo.toml b/Cargo.toml index 64b59d61..5d2e127f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,8 @@ resolver = "2" aead-stream = { path = "./aead-stream" } aes-gcm = { path = "./aes-gcm" } -aead = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/bicephalbuffer" } -crypto-common = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/bicephalbuffer" } +aead = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/mockbuffer-merge" } +crypto-common = { git = "https://github.com/baloo/traits.git", branch = "baloo/aead/mockbuffer-merge" } chacha20 = { git = "https://github.com/RustCrypto/stream-ciphers.git" } diff --git a/aead-stream/src/lib.rs b/aead-stream/src/lib.rs index b3332681..4d095902 100644 --- a/aead-stream/src/lib.rs +++ b/aead-stream/src/lib.rs @@ -6,7 +6,7 @@ extern crate alloc; use aead::{ - AeadCore, AeadInPlace, Buffer, Error, Result, + AeadCore, AeadInOut, Buffer, Error, Result, array::{ Array, ArraySize, typenum::{U4, U5, Unsigned}, @@ -32,7 +32,7 @@ pub type NonceSize = /// Create a new STREAM from the provided AEAD. pub trait NewStream: StreamPrimitive where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, NonceSize: ArraySize, { @@ -57,7 +57,7 @@ where /// Deliberately immutable and stateless to permit parallel operation. pub trait StreamPrimitive where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, NonceSize: ArraySize, { @@ -165,7 +165,7 @@ macro_rules! impl_stream_object { #[derive(Debug)] pub struct $name where - A: AeadInPlace, + A: AeadInOut, S: StreamPrimitive, A::NonceSize: Sub<>::NonceOverhead>, NonceSize: ArraySize, @@ -179,7 +179,7 @@ macro_rules! impl_stream_object { impl $name where - A: AeadInPlace, + A: AeadInOut, S: StreamPrimitive, A::NonceSize: Sub<>::NonceOverhead>, NonceSize: ArraySize, @@ -344,7 +344,7 @@ pub type DecryptorLE31 = Decryptor>; #[derive(Debug)] pub struct StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -357,7 +357,7 @@ where impl NewStream for StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -371,7 +371,7 @@ where impl StreamPrimitive for StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -405,7 +405,7 @@ where impl StreamBE32 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -434,7 +434,7 @@ where #[derive(Debug)] pub struct StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -447,7 +447,7 @@ where impl NewStream for StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -461,7 +461,7 @@ where impl StreamPrimitive for StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { @@ -495,7 +495,7 @@ where impl StreamLE31 where - A: AeadInPlace, + A: AeadInOut, A::NonceSize: Sub, <::NonceSize as Sub>::Output: ArraySize, { diff --git a/aes-gcm-siv/Cargo.toml b/aes-gcm-siv/Cargo.toml index 73c48188..33c20ad4 100644 --- a/aes-gcm-siv/Cargo.toml +++ b/aes-gcm-siv/Cargo.toml @@ -17,7 +17,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +aead = { version = "0.6.0-rc.0", default-features = false } aes = { version = "=0.9.0-pre.3", optional = true } cipher = "=0.5.0-pre.8" ctr = "0.10.0-pre.2" diff --git a/aes-gcm-siv/src/lib.rs b/aes-gcm-siv/src/lib.rs index 44da07ef..070f8e5d 100644 --- a/aes-gcm-siv/src/lib.rs +++ b/aes-gcm-siv/src/lib.rs @@ -34,7 +34,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. //! @@ -48,7 +48,7 @@ #![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use aes_gcm_siv::{ -//! aead::{AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}, +//! aead::{AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}, //! Aes256GcmSiv, Nonce, // Or `Aes128GcmSiv` //! }; //! @@ -83,7 +83,7 @@ pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; #[cfg(feature = "aes")] pub use aes; -use aead::{PostfixTagged, inout::InOutBuf}; +use aead::{TagPosition, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, array::Array, @@ -161,10 +161,9 @@ where { type NonceSize = U12; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for AesGcmSiv {} - impl AeadInOut for AesGcmSiv where Aes: BlockSizeUser + BlockCipherEncrypt + KeyInit, diff --git a/aes-gcm/Cargo.toml b/aes-gcm/Cargo.toml index e50a4801..774e9fd5 100644 --- a/aes-gcm/Cargo.toml +++ b/aes-gcm/Cargo.toml @@ -17,7 +17,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +aead = { version = "0.6.0-rc.0", default-features = false } aes = { version = "=0.9.0-pre.3", optional = true } cipher = "=0.5.0-pre.8" ctr = "0.10.0-pre.2" diff --git a/aes-gcm/src/lib.rs b/aes-gcm/src/lib.rs index d7044e75..90d41b64 100644 --- a/aes-gcm/src/lib.rs +++ b/aes-gcm/src/lib.rs @@ -54,7 +54,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. //! @@ -68,7 +68,7 @@ #![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use aes_gcm::{ -//! aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}, +//! aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}, //! Aes256Gcm, Nonce, // Or `Aes128Gcm` //! }; //! @@ -103,7 +103,7 @@ pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; #[cfg(feature = "aes")] pub use aes; -use aead::{PostfixTagged, inout::InOutBuf}; +use aead::{TagPosition, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, @@ -253,11 +253,7 @@ where { type NonceSize = NonceSize; type TagSize = TagSize; -} - -impl PostfixTagged for AesGcm where - TagSize: self::TagSize -{ + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl AeadInOut for AesGcm diff --git a/aes-siv/src/lib.rs b/aes-siv/src/lib.rs index 592e03ab..c0cad4cc 100644 --- a/aes-siv/src/lib.rs +++ b/aes-siv/src/lib.rs @@ -34,7 +34,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. //! @@ -48,7 +48,7 @@ #![cfg_attr(not(all(feature = "os_rng", feature = "heapless")), doc = "```ignore")] //! # fn main() -> Result<(), Box> { //! use aes_siv::{ -//! aead::{AeadCore, AeadInPlace, KeyInit, rand_core::OsRng, heapless::Vec}, +//! aead::{AeadCore, AeadInOut, KeyInit, rand_core::OsRng, heapless::Vec}, //! Aes256SivAead, Nonce, // Or `Aes128SivAead` //! }; //! @@ -83,11 +83,11 @@ extern crate alloc; pub mod siv; -pub use aead::{self, AeadCore, AeadInOut, AeadInPlace, Error, Key, KeyInit, KeySizeUser}; +pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; use crate::siv::Siv; use aead::{ - Buffer, + TagPosition, array::Array, consts::{U1, U16, U32, U64}, inout::InOutBuf, @@ -205,39 +205,7 @@ where // https://tools.ietf.org/html/rfc5297#section-6 type NonceSize = NonceSize; type TagSize = U16; -} - -impl AeadInPlace for SivAead -where - Self: KeySizeUser, - Siv: KeyInit + KeySizeUser::KeySize>, - C: BlockSizeUser + BlockCipherEncrypt + KeyInit + KeySizeUser, - M: Mac + FixedOutputReset + KeyInit, - ::KeySize: Add, - NonceSize: ArraySize + IsGreaterOrEqual, -{ - fn encrypt_in_place( - &self, - nonce: &Array, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<(), Error> { - // "SIV performs nonce-based authenticated encryption when a component of - // the associated data is a nonce. For purposes of interoperability the - // final component -- i.e., the string immediately preceding the - // plaintext in the vector input to S2V -- is used for the nonce." - // https://tools.ietf.org/html/rfc5297#section-3 - Siv::::new(&self.key).encrypt_in_place([associated_data, nonce.as_slice()], buffer) - } - - fn decrypt_in_place( - &self, - nonce: &Array, - associated_data: &[u8], - buffer: &mut dyn Buffer, - ) -> Result<(), Error> { - Siv::::new(&self.key).decrypt_in_place([associated_data, nonce.as_slice()], buffer) - } + const TAG_POSITION: TagPosition = TagPosition::Prefix; } impl AeadInOut for SivAead diff --git a/ascon-aead/Cargo.toml b/ascon-aead/Cargo.toml index faff8b93..556a4456 100644 --- a/ascon-aead/Cargo.toml +++ b/ascon-aead/Cargo.toml @@ -15,7 +15,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +aead = { version = "0.6.0-rc.0", default-features = false } subtle = { version = "2", default-features = false } zeroize = { version = "1.6", optional = true, default-features = false, features = ["derive"] } ascon = "0.4" diff --git a/ascon-aead/src/lib.rs b/ascon-aead/src/lib.rs index b58c77b5..49e1ebef 100644 --- a/ascon-aead/src/lib.rs +++ b/ascon-aead/src/lib.rs @@ -59,7 +59,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. //! @@ -72,7 +72,7 @@ //! ``` //! # #[cfg(feature = "heapless")] { //! use ascon_aead::{AsconAead128, Key, Nonce}; -//! use ascon_aead::aead::{AeadInPlace, KeyInit}; +//! use ascon_aead::aead::{AeadInOut, KeyInit}; //! use ascon_aead::aead::heapless::Vec; //! //! let key = Key::::from_slice(b"very secret key."); @@ -105,9 +105,7 @@ pub use zeroize; pub use aead::{self, Error, Key, Nonce, Tag}; -use aead::{ - AeadCore, AeadInOut, KeyInit, KeySizeUser, PostfixTagged, consts::U16, inout::InOutBuf, -}; +use aead::{AeadCore, AeadInOut, KeyInit, KeySizeUser, TagPosition, consts::U16, inout::InOutBuf}; mod asconcore; @@ -137,10 +135,9 @@ impl KeyInit for Ascon

{ impl AeadCore for Ascon

{ type NonceSize = U16; type TagSize = U16; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } -impl PostfixTagged for Ascon

{} - impl AeadInOut for Ascon

{ fn encrypt_inout_detached( &self, @@ -200,10 +197,9 @@ 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 AeadInOut for AsconAead128 { #[inline(always)] fn encrypt_inout_detached( diff --git a/ccm/Cargo.toml b/ccm/Cargo.toml index 54324b8d..cc43be2a 100644 --- a/ccm/Cargo.toml +++ b/ccm/Cargo.toml @@ -14,7 +14,7 @@ keywords = ["encryption", "aead"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +aead = { version = "0.6.0-rc.0", default-features = false } cipher = { version = "=0.5.0-pre.8", default-features = false } ctr = { version = "0.10.0-pre.2", default-features = false } subtle = { version = "2", default-features = false } diff --git a/ccm/src/lib.rs b/ccm/src/lib.rs index 7284220a..a75e094f 100644 --- a/ccm/src/lib.rs +++ b/ccm/src/lib.rs @@ -45,7 +45,7 @@ pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, consts}; use aead::{ - PostfixTagged, + TagPosition, array::{Array, ArraySize, typenum::Unsigned}, consts::U16, inout::InOutBuf, @@ -212,14 +212,7 @@ where { type NonceSize = N; type TagSize = M; -} - -impl PostfixTagged for Ccm -where - C: BlockSizeUser + BlockCipherEncrypt, - M: ArraySize + TagSize, - N: ArraySize + NonceSize, -{ + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl AeadInOut for Ccm diff --git a/chacha20poly1305/Cargo.toml b/chacha20poly1305/Cargo.toml index 51d184dc..6be0a7ca 100644 --- a/chacha20poly1305/Cargo.toml +++ b/chacha20poly1305/Cargo.toml @@ -20,7 +20,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +aead = { version = "0.6.0-rc.0", default-features = false } chacha20 = { version = "=0.10.0-pre.3", default-features = false, features = ["xchacha"] } cipher = "=0.5.0-pre.8" poly1305 = "0.9.0-rc.0" diff --git a/chacha20poly1305/src/lib.rs b/chacha20poly1305/src/lib.rs index a021df7f..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, //! }; //! @@ -144,7 +144,7 @@ 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, @@ -246,13 +246,7 @@ where { type NonceSize = N; type TagSize = U16; -} - -impl PostfixTagged for ChaChaPoly1305 -where - C: KeyIvInit + StreamCipher + StreamCipherSeek, - N: ArraySize, -{ + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl AeadInOut for ChaChaPoly1305 diff --git a/deoxys/Cargo.toml b/deoxys/Cargo.toml index bfa0e41c..dbf9bef8 100644 --- a/deoxys/Cargo.toml +++ b/deoxys/Cargo.toml @@ -18,7 +18,7 @@ edition = "2024" rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +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 } diff --git a/deoxys/src/lib.rs b/deoxys/src/lib.rs index dd95a219..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); @@ -113,7 +113,7 @@ mod modes; pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser, consts}; use aead::{ - PostfixTagged, + TagPosition, array::{Array, ArraySize}, consts::U16, inout::{InOut, InOutBuf}, @@ -262,13 +262,7 @@ where { type NonceSize = M::NonceSize; type TagSize = U16; -} - -impl PostfixTagged for Deoxys -where - M: DeoxysMode, - B: DeoxysBcType, -{ + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl AeadInOut for Deoxys diff --git a/eax/Cargo.toml b/eax/Cargo.toml index 0da78b09..9152c064 100644 --- a/eax/Cargo.toml +++ b/eax/Cargo.toml @@ -20,7 +20,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +aead = { version = "0.6.0-rc.0", default-features = false } cipher = "=0.5.0-pre.8" cmac = "0.8.0-pre.2" ctr = "0.10.0-pre.2" diff --git a/eax/src/lib.rs b/eax/src/lib.rs index bd41170f..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; @@ -127,7 +127,7 @@ pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser}; pub use cipher; -use aead::{PostfixTagged, inout::InOutBuf}; +use aead::{TagPosition, inout::InOutBuf}; use cipher::{ BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore, array::Array, consts::U16, crypto_common::OutputSizeUser, typenum::Unsigned, @@ -210,13 +210,7 @@ where { type NonceSize = Cipher::BlockSize; type TagSize = M; -} - -impl PostfixTagged for Eax -where - Cipher: BlockSizeUser + BlockCipherEncrypt + Clone + KeyInit, - M: TagSize, -{ + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl AeadInOut for Eax diff --git a/ocb3/Cargo.toml b/ocb3/Cargo.toml index 9fe5b2e8..4e7fd1c2 100644 --- a/ocb3/Cargo.toml +++ b/ocb3/Cargo.toml @@ -16,7 +16,7 @@ categories = ["cryptography", "no-std"] rust-version = "1.85" [dependencies] -aead = { version = "0.6.0-rc.0", default-features = false, features = ["inout"] } +aead = { version = "0.6.0-rc.0", default-features = false } cipher = "=0.5.0-pre.8" ctr = "0.10.0-pre.2" dbl = "0.4.0-rc.2" diff --git a/ocb3/src/lib.rs b/ocb3/src/lib.rs index fcd09c62..34fa5c4f 100644 --- a/ocb3/src/lib.rs +++ b/ocb3/src/lib.rs @@ -19,7 +19,7 @@ pub use aead::{ }; use aead::{ - PostfixTagged, + TagPosition, array::ArraySize, inout::{InOut, InOutBuf}, }; @@ -174,6 +174,7 @@ where { type NonceSize = NonceSize; type TagSize = TagSize; + const TAG_POSITION: TagPosition = TagPosition::Postfix; } impl From for Ocb3 @@ -196,14 +197,6 @@ where } } -impl PostfixTagged for Ocb3 -where - Cipher: BlockSizeUser + BlockCipherEncrypt + BlockCipherDecrypt, - NonceSize: sealed::NonceSizes, - TagSize: sealed::TagSizes, -{ -} - impl AeadInOut for Ocb3 where Cipher: BlockSizeUser + BlockCipherEncrypt + BlockCipherDecrypt, diff --git a/xaes-256-gcm/src/lib.rs b/xaes-256-gcm/src/lib.rs index 362eb574..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, AeadInOut, Error, KeyInit, KeySizeUser, PostfixTagged, array::Array, inout::InOutBuf, + 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,8 +127,6 @@ impl KeyInit for Xaes256Gcm { } } -impl PostfixTagged for Xaes256Gcm {} - impl AeadInOut for Xaes256Gcm { fn encrypt_inout_detached( &self,