From 74b9e6c629faab4f240d0ee52f778d9f8024ce21 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 15 Mar 2025 20:56:40 -0700 Subject: [PATCH 1/6] 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 2/6] 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 3/6] 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 4/6] 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 5/6] 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 6/6] 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()); + } +}