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;
|
use crate::key::Key;
|
||||||
|
|
||||||
pub struct Aes {}
|
pub struct Aes {}
|
||||||
@ -8,10 +10,17 @@ impl Aes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Aes {
|
impl BlockCipher for Aes {
|
||||||
const BLOCK_SIZE: usize = 16;
|
const BLOCK_SIZE: usize = 16;
|
||||||
|
|
||||||
fn from_key(key: &[u8]) -> Self {
|
fn from_key(key: &[u8]) -> Self {
|
||||||
Self::new(key)
|
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 {
|
pub const fn as_u64(&self) -> u64 {
|
||||||
self.0 as u64
|
self.0 as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
secret_block!(@conversions_as u128);
|
||||||
};
|
};
|
||||||
(@conversions_as u128) => {
|
(@conversions_as u128) => {
|
||||||
/// Return value as u64
|
/// Return value as u129
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -175,7 +177,7 @@ macro_rules! secret_block {
|
|||||||
secret_block!(@conversions_from u32 $int);
|
secret_block!(@conversions_from u32 $int);
|
||||||
};
|
};
|
||||||
(@conversions_from u128 $int:tt) => {
|
(@conversions_from u128 $int:tt) => {
|
||||||
/// Create value from u64
|
/// Create value from u128
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
mod aes_key;
|
mod aes_key;
|
||||||
|
mod secret_key;
|
||||||
|
mod subkey;
|
||||||
|
mod subkeys;
|
||||||
|
|
||||||
|
use crate::secret_key;
|
||||||
pub use aes_key::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