feat(aes): add subkey blanket

This commit is contained in:
Kristofers Solo 2025-11-10 10:19:51 +02:00
parent 8b80e17f82
commit 88328256b3
Signed by: kristoferssolo
GPG Key ID: 74FF8144483D82C8
6 changed files with 313 additions and 4 deletions

View File

@ -1,3 +1,5 @@
use cipher_core::BlockCipher;
use crate::key::Key;
pub struct Aes {}
@ -8,10 +10,17 @@ impl Aes {
}
}
impl Aes {
impl BlockCipher for Aes {
const BLOCK_SIZE: usize = 16;
fn from_key(key: &[u8]) -> Self {
Self::new(key)
}
fn transform_impl(
&self,
block: &[u8],
action: cipher_core::CipherAction,
) -> cipher_core::CipherResult<cipher_core::Output> {
todo!()
}
}

View File

@ -121,9 +121,11 @@ macro_rules! secret_block {
pub const fn as_u64(&self) -> u64 {
self.0 as u64
}
secret_block!(@conversions_as u128);
};
(@conversions_as u128) => {
/// Return value as u64
/// Return value as u129
#[allow(dead_code)]
#[inline]
#[must_use]
@ -175,7 +177,7 @@ macro_rules! secret_block {
secret_block!(@conversions_from u32 $int);
};
(@conversions_from u128 $int:tt) => {
/// Create value from u64
/// Create value from u128
#[allow(dead_code)]
#[inline]
#[must_use]

View File

@ -1,3 +1,7 @@
mod aes_key;
mod secret_key;
mod subkey;
mod subkeys;
use crate::secret_key;
pub use aes_key::Key;

149
aes/src/key/secret_key.rs Normal file
View File

@ -0,0 +1,149 @@
/// Macro to generate a masked, zeroizable integer wrapper type.
///
/// Usage:
/// ```
/// use des::secret_key;
/// secret_key! {
/// /// docs...
/// pub struct Subkey(u64, 48, 0x0000_FFFF_FFFF_FFFFu64);
/// }
/// ```
#[macro_export]
macro_rules! secret_key {
(
$(#[$meta:meta])*
$vis:vis struct $name:ident ( $int:tt, $bits:expr, $mask:expr );
) => {
$(#[$meta])*
#[derive(::zeroize::ZeroizeOnDrop, Default)]
$vis struct $name($int);
impl $name {
/// Mask to restrict the underlying integer to valid bits.
pub const MASK: $int = $mask;
secret_key!(@conversions_as $int);
secret_key!(@conversions_from $int $int);
}
impl ::std::fmt::Debug for $name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
f.write_str(concat!(stringify!($name), "[REDACTED]"))
}
}
impl From<$int> for $name {
fn from(v: $int) -> Self {
Self(v & Self::MASK)
}
}
};
// Helper: generate conversions_as based on type
(@conversions_as u8) => {
/// Return value as u8
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn as_u8(&self) -> u8 {
self.0 as u8
}
secret_key!(@conversions_as u16);
};
(@conversions_as u16) => {
/// Return value as u16
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn as_u16(&self) -> u16 {
self.0 as u16
}
secret_key!(@conversions_as u32);
};
(@conversions_as u32) => {
/// Return value as u32
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn as_u32(&self) -> u32 {
self.0 as u32
}
secret_key!(@conversions_as u64);
};
(@conversions_as u64) => {
/// Return value as u64
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn as_u64(&self) -> u64 {
self.0 as u64
}
secret_key!(@conversions_as u128);
};
(@conversions_as u128) => {
/// Return value as u128
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn as_u128(&self) -> u128 {
self.0 as u128
}
};
// Helper: generate conversions_from based on type
(@conversions_from u8 $int:tt) => {
/// Create value from u8
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn from_u8(key: u8) -> Self {
Self(key as $int & Self::MASK)
}
};
(@conversions_from u16 $int:tt) => {
/// Create value from u16
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn from_u16(key: u16) -> Self {
Self(key as $int & Self::MASK)
}
secret_key!(@conversions_from u8 $int);
};
(@conversions_from u32 $int:tt) => {
/// Create value from u32
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn from_u32(key: u32) -> Self {
Self(key as $int & Self::MASK)
}
secret_key!(@conversions_from u16 $int);
};
(@conversions_from u64 $int:tt) => {
/// Create value from u64
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn from_u64(key: u64) -> Self {
Self(key as $int & Self::MASK)
}
secret_key!(@conversions_from u32 $int);
};
(@conversions_from u128 $int:tt) => {
/// Create value from u128
#[allow(dead_code)]
#[inline]
#[must_use]
pub const fn from_u128(key: u128) -> Self {
Self(key & Self::MASK)
}
secret_key!(@conversions_from u64 $int);
}
}

13
aes/src/key/subkey.rs Normal file
View File

@ -0,0 +1,13 @@
use crate::key::secret_key;
secret_key! {
/// A single AES round subkey
pub struct Subkey(u32, 32, 0xFFFF_FFFF);
}
impl Subkey {
/// Zero value.
pub const fn zero() -> Self {
Self(0)
}
}

132
aes/src/key/subkeys.rs Normal file
View File

@ -0,0 +1,132 @@
use crate::key::{Key, subkey::Subkey};
use std::{
fmt::Debug,
iter::Rev,
ops::Index,
slice::{Iter, IterMut},
};
// #[derive(Default)]
pub struct Subkeys([Subkey; 44]);
impl Subkeys {
/// Generates 44 round subkeys from the given key.
#[must_use]
pub fn from_key(key: &Key) -> Self {
todo!()
}
/// Returns an iterator over the subkeys.
pub fn iter(&self) -> Iter<'_, Subkey> {
self.0.iter()
}
/// Returns a reverse iterator over the subkeys.
pub fn iter_rev(&self) -> Rev<Iter<'_, Subkey>> {
self.0.iter().rev()
}
/// Returns a mutable iterator over the subkeys.
pub fn iter_mut(&mut self) -> IterMut<'_, Subkey> {
self.0.iter_mut()
}
}
impl<'a> IntoIterator for &'a Subkeys {
type Item = &'a Subkey;
type IntoIter = Iter<'a, Subkey>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut Subkeys {
type Item = &'a mut Subkey;
type IntoIter = IterMut<'a, Subkey>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl Index<usize> for Subkeys {
type Output = Subkey;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl Debug for Subkeys {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Subkeys[REDACTED]")
}
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_KEY: u128 = 0x0F1571C947D9E8591CB7ADD6AF7F6798;
impl PartialEq<[[u8; 4]; 44]> for Subkeys {
fn eq(&self, other: &[[u8; 4]; 44]) -> bool {
self.iter()
.zip(other)
.all(|(a, &b)| a.as_u32() == u32::from_be_bytes(b))
}
}
#[test]
fn from_key() {
let key = Key::from(TEST_KEY);
let subkeys = Subkeys::from_key(&key);
assert_eq!(
subkeys,
[
[0x0F, 0x15, 0x71, 0xC9],
[0x47, 0xD9, 0xE8, 0x59],
[0x1C, 0xB7, 0xAD, 0xD6],
[0xAF, 0x7F, 0x67, 0x98],
[0xDC, 0x90, 0x37, 0xB0],
[0x9B, 0x49, 0xDF, 0xE9],
[0x87, 0xFE, 0x72, 0x3F],
[0x28, 0x81, 0x15, 0xA7],
[0xD2, 0xC9, 0x6B, 0x84],
[0x49, 0x80, 0xB4, 0x6D],
[0xCE, 0x7E, 0xC6, 0x52],
[0xE6, 0xFF, 0xD3, 0xF5],
[0xC0, 0xAF, 0x8D, 0x0A],
[0x89, 0x2F, 0x39, 0x67],
[0x47, 0x51, 0xFF, 0x35],
[0xA1, 0xAE, 0x2C, 0xC0],
[0x2C, 0xDE, 0x37, 0x38],
[0xA5, 0xF1, 0x0E, 0x5F],
[0xE2, 0xA0, 0xF1, 0x6A],
[0x43, 0x0E, 0xDD, 0xAA],
[0x97, 0x1F, 0x9B, 0x22],
[0x32, 0xEE, 0x95, 0x7D],
[0xD0, 0x4E, 0x64, 0x17],
[0x93, 0x40, 0xB9, 0xBD],
[0xBE, 0x49, 0xE1, 0xFE],
[0x8C, 0xA7, 0x74, 0x83],
[0x5C, 0xE9, 0x10, 0x94],
[0xCF, 0xA9, 0xA9, 0x29],
[0x2D, 0x9A, 0x44, 0x74],
[0xA1, 0x3D, 0x30, 0xF7],
[0xFD, 0xD4, 0x20, 0x63],
[0x32, 0x7D, 0x89, 0x4A],
[0x52, 0x3D, 0x92, 0x57],
[0xF3, 0x00, 0xA2, 0xA0],
[0x0E, 0xD4, 0x82, 0xC3],
[0x3C, 0xA9, 0x0B, 0x89],
[0x9A, 0x16, 0x35, 0xBC],
[0x69, 0x16, 0x97, 0x1C],
[0x67, 0xC2, 0x15, 0xDF],
[0x5B, 0x6B, 0x1E, 0x56],
[0xD3, 0x64, 0x84, 0x85],
[0xBA, 0x72, 0x13, 0x99],
[0xDD, 0xB0, 0x06, 0x46],
[0x86, 0xDB, 0x18, 0x10],
]
)
}
}