mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2025-12-20 11:04:38 +00:00
feat(aes): add subkey blanket
This commit is contained in:
parent
8b80e17f82
commit
88328256b3
@ -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!()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
149
aes/src/key/secret_key.rs
Normal 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
13
aes/src/key/subkey.rs
Normal 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
132
aes/src/key/subkeys.rs
Normal 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],
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user