mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2026-02-04 06:42:11 +00:00
refactor(des): use InputBlock trait
This commit is contained in:
@@ -1,9 +1,24 @@
|
||||
use crate::block::{lr::LR, secret_block};
|
||||
use cipher_core::{BlockError, InputBlock};
|
||||
use std::{
|
||||
slice::{from_raw_parts, from_raw_parts_mut},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
secret_block! {
|
||||
pub struct Block64(u64, 64, 0xFFFF_FFFF_FFFF_FFFF);
|
||||
}
|
||||
|
||||
impl InputBlock for Block64 {
|
||||
const BLOCK_SIZE: usize = 64;
|
||||
fn as_bytes(&self) -> &[u8] {
|
||||
unsafe { from_raw_parts((&raw const self.0).cast::<u64>().cast::<u8>(), 8) }
|
||||
}
|
||||
fn as_bytes_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { from_raw_parts_mut((&raw mut self.0).cast::<u64>().cast::<u8>(), 8) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Block64 {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
@@ -30,6 +45,68 @@ impl Block64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Block64 {
|
||||
type Err = BlockError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(parse_string_to_u64(s)?))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_string_to_u64(s: &str) -> Result<u64, BlockError> {
|
||||
let trimmed = s.trim();
|
||||
|
||||
if trimmed.is_empty() {
|
||||
return Err(BlockError::EmptyBlock);
|
||||
}
|
||||
|
||||
// Hexadecimal with 0x/0X prefix
|
||||
if let Some(hex_str) = trimmed
|
||||
.strip_prefix("0x")
|
||||
.or_else(|| trimmed.strip_prefix("0X"))
|
||||
{
|
||||
return parse_radix(hex_str, 16);
|
||||
}
|
||||
// Binary with 0b/0B prefix
|
||||
if let Some(bin_str) = trimmed
|
||||
.strip_prefix("0b")
|
||||
.or_else(|| trimmed.strip_prefix("0B"))
|
||||
{
|
||||
return parse_radix(bin_str, 2);
|
||||
}
|
||||
|
||||
// 8-character ASCII string conversion to u64
|
||||
if trimmed.len() > 8 {
|
||||
return Err(BlockError::InvalidByteStringLength(trimmed.len()));
|
||||
}
|
||||
|
||||
ascii_string_to_u64(trimmed)
|
||||
}
|
||||
|
||||
fn parse_radix(s: &str, radix: u32) -> Result<u64, BlockError> {
|
||||
let trimmed = s.trim_start_matches('0');
|
||||
if trimmed.is_empty() {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
u64::from_str_radix(trimmed, radix).map_err(BlockError::from)
|
||||
}
|
||||
|
||||
fn ascii_string_to_u64(s: &str) -> Result<u64, BlockError> {
|
||||
if !s.is_ascii() {
|
||||
return Err(BlockError::conversion_error(
|
||||
"u64",
|
||||
"String contains non-ASCII characters",
|
||||
));
|
||||
}
|
||||
|
||||
let mut bytes = [0; 8];
|
||||
for (idx, byte) in s.bytes().enumerate() {
|
||||
bytes[idx] = byte;
|
||||
}
|
||||
|
||||
Ok(u64::from_be_bytes(bytes))
|
||||
}
|
||||
|
||||
impl From<[u8; 8]> for Block64 {
|
||||
fn from(bytes: [u8; 8]) -> Self {
|
||||
Self::from_be_bytes(bytes)
|
||||
|
||||
@@ -45,7 +45,7 @@ impl BlockCipher for Des {
|
||||
&self,
|
||||
block: &[u8],
|
||||
action: cipher_core::CipherAction,
|
||||
) -> cipher_core::CipherResult<cipher_core::CipherOutput> {
|
||||
) -> cipher_core::CipherResult<cipher_core::Output> {
|
||||
let block_arr: [u8; Self::BLOCK_SIZE] = block
|
||||
.try_into()
|
||||
.map_err(|_| CipherError::invalid_block_size(Self::BLOCK_SIZE, block.len()))?;
|
||||
|
||||
@@ -4,4 +4,4 @@ mod des;
|
||||
mod key;
|
||||
pub(crate) mod utils;
|
||||
|
||||
pub use des::Des;
|
||||
pub use {block::Block64, des::Des};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use cipher_core::{BlockCipher, CipherOutput};
|
||||
use cipher_core::{BlockCipher, Output};
|
||||
use claims::assert_ok;
|
||||
use des::Des;
|
||||
use rstest::rstest;
|
||||
@@ -192,7 +192,7 @@ fn different_inputs() {
|
||||
);
|
||||
}
|
||||
|
||||
fn cipher_block_to_u64(block: CipherOutput) -> u64 {
|
||||
fn cipher_block_to_u64(block: Output) -> u64 {
|
||||
let bytes = block.as_slice().try_into().expect("8 bytes");
|
||||
u64::from_be_bytes(bytes)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user