From 7e5162fb442fc18d880a136c68092af429041d80 Mon Sep 17 00:00:00 2001 From: Kristofers Solo Date: Tue, 11 Nov 2025 09:54:04 +0200 Subject: [PATCH] feat(aes): add round key --- aes/src/aes.rs | 60 +++++++++++++++++++++++++++++++++------ aes/src/block/block128.rs | 24 ++++++++++++++-- aes/src/block/block32.rs | 27 ++++++++++++++++++ aes/src/block/mod.rs | 3 +- aes/src/key/mod.rs | 2 +- aes/src/key/subkey.rs | 12 ++++++++ aes/src/key/subkeys.rs | 5 ++++ 7 files changed, 120 insertions(+), 13 deletions(-) create mode 100644 aes/src/block/block32.rs diff --git a/aes/src/aes.rs b/aes/src/aes.rs index 9f447fc..c76e586 100644 --- a/aes/src/aes.rs +++ b/aes/src/aes.rs @@ -1,12 +1,19 @@ -use cipher_core::BlockCipher; +use crate::{ + Block128, + block::Block32, + key::{Key, Subkey, Subkeys}, +}; +use cipher_core::{BlockCipher, CipherError}; -use crate::key::Key; - -pub struct Aes {} +pub struct Aes { + subkeys: Subkeys, +} impl Aes { - pub fn new(_key: impl Into) -> Self { - todo!() + pub fn new(key: impl Into) -> Self { + Self { + subkeys: Subkeys::from_key(&key.into()), + } } } @@ -18,9 +25,46 @@ impl BlockCipher for Aes { fn transform_impl( &self, - _block: &[u8], - _action: cipher_core::CipherAction, + block: &[u8], + action: cipher_core::CipherAction, ) -> cipher_core::CipherResult { + let block_arr: [u8; Self::BLOCK_SIZE] = block + .try_into() + .map_err(|_| CipherError::invalid_block_size(Self::BLOCK_SIZE, block.len()))?; + + let block128 = Block128::from_be_bytes(block_arr); + + let round_key = add_round_key( + *self.subkeys.first().unwrap(), + *block128.as_block32_array().first().unwrap(), + ); todo!() } } + +fn add_round_key(subkey: Subkey, block: Block32) -> Block32 { + block ^ subkey +} + +#[cfg(test)] +mod tests { + use rstest::rstest; + + use super::*; + + const TEST_MESSAGE: u128 = 0x0123_4567_89AB_CDEF_FEDC_BA98_7654_3210; + + #[rstest] + #[case(0x0123_4567, 0x0F15_71C9, 0x0E36_34AE)] + #[case(0x89AB_CDEF, 0x47D9_E859, 0xCE72_25B6)] + #[case(0xFEDC_BA98, 0x1CB7_ADD6, 0xE26B_174E)] + #[case(0x7654_3210, 0xAF7F_6798, 0xD92B_5588)] + fn round_key(#[case] block: u32, #[case] subkey: u32, #[case] expected: u32) { + let block = Block32::new(block); + let subkey = Subkey::from_u32(subkey); + + let result = add_round_key(subkey, block); + + assert_eq!(result.as_u32(), expected); + } +} diff --git a/aes/src/block/block128.rs b/aes/src/block/block128.rs index 6114917..be6199e 100644 --- a/aes/src/block/block128.rs +++ b/aes/src/block/block128.rs @@ -1,4 +1,4 @@ -use crate::block::secret_block; +use crate::block::{Block32, secret_block}; use cipher_core::{BlockError, InputBlock}; use std::{ slice::{from_raw_parts, from_raw_parts_mut}, @@ -37,6 +37,18 @@ impl Block128 { pub const fn to_le_bytes(self) -> [u8; 16] { self.0.to_le_bytes() } + + #[inline] + #[must_use] + pub const fn as_block32_array(self) -> [Block32; 4] { + let val = self.0; + [ + Block32::from_u32((val >> 96) as u32), + Block32::from_u32((val >> 64) as u32), + Block32::from_u32((val >> 32) as u32), + Block32::from_u32(val as u32), + ] + } } impl FromStr for Block128 { @@ -105,14 +117,20 @@ impl From<[u8; 16]> for Block128 { } } +impl From for [Block32; 4] { + fn from(block: Block128) -> Self { + block.as_block32_array() + } +} + impl From for Vec { fn from(value: Block128) -> Self { - value.0.to_be_bytes().to_vec() + value.to_be_bytes().to_vec() } } impl From<&Block128> for Vec { fn from(value: &Block128) -> Self { - value.0.to_be_bytes().to_vec() + value.to_be_bytes().to_vec() } } diff --git a/aes/src/block/block32.rs b/aes/src/block/block32.rs new file mode 100644 index 0000000..d55162d --- /dev/null +++ b/aes/src/block/block32.rs @@ -0,0 +1,27 @@ +use std::ops::BitXor; + +use crate::{block::secret_block, key::Subkey}; + +secret_block! { + pub struct Block32(u32, 32, 0xFFFF_FFFF); +} +impl Block32 { + #[inline] + #[must_use] + pub const fn to_be_bytes(self) -> [u8; 4] { + self.0.to_be_bytes() + } + + #[inline] + #[must_use] + pub const fn to_le_bytes(self) -> [u8; 4] { + self.0.to_le_bytes() + } +} + +impl BitXor for Block32 { + type Output = Self; + fn bitxor(self, rhs: Subkey) -> Self::Output { + Self(self.0 ^ rhs.as_u32()) + } +} diff --git a/aes/src/block/mod.rs b/aes/src/block/mod.rs index f98778f..ad47237 100644 --- a/aes/src/block/mod.rs +++ b/aes/src/block/mod.rs @@ -1,5 +1,6 @@ mod block128; +mod block32; mod secret_block; use crate::secret_block; -pub use block128::Block128; +pub use {block32::Block32, block128::Block128}; diff --git a/aes/src/key/mod.rs b/aes/src/key/mod.rs index b2d4871..5df3051 100644 --- a/aes/src/key/mod.rs +++ b/aes/src/key/mod.rs @@ -5,4 +5,4 @@ mod subkey; mod subkeys; use crate::secret_key; -pub use aes_key::Key; +pub use {aes_key::Key, subkey::Subkey, subkeys::Subkeys}; diff --git a/aes/src/key/subkey.rs b/aes/src/key/subkey.rs index 53afa05..d4b3f98 100644 --- a/aes/src/key/subkey.rs +++ b/aes/src/key/subkey.rs @@ -27,6 +27,18 @@ impl Subkey { pub const fn rotate_right(self, n: u32) -> Self { Self(self.0.rotate_right(n)) } + + #[inline] + #[must_use] + pub const fn to_be_bytes(self) -> [u8; 4] { + self.0.to_be_bytes() + } + + #[inline] + #[must_use] + pub const fn to_le_bytes(self) -> [u8; 4] { + self.0.to_le_bytes() + } } impl BitXor for Subkey { diff --git a/aes/src/key/subkeys.rs b/aes/src/key/subkeys.rs index 0385776..8a42103 100644 --- a/aes/src/key/subkeys.rs +++ b/aes/src/key/subkeys.rs @@ -51,6 +51,11 @@ impl Subkeys { pub fn iter_mut(&mut self) -> IterMut<'_, Subkey> { self.0.iter_mut() } + + /// Returns the first element of the slice, or `None` if it is empty. + pub fn first(&self) -> Option<&Subkey> { + self.0.first() + } } impl<'a> IntoIterator for &'a Subkeys {