mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2026-02-04 06:42:11 +00:00
refactor(key): improve secret_int! macro
This commit is contained in:
@@ -3,97 +3,26 @@ use thiserror::Error;
|
||||
#[derive(Debug, Error, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum CipherError {
|
||||
/// Invalid key size for the cipher
|
||||
#[error("invalid key size: expected {expected} bytes, got {actual}")]
|
||||
#[error("Invalid key size: expected {expected} bytes, got {actual}")]
|
||||
InvalidKeySize { expected: usize, actual: usize },
|
||||
|
||||
/// Input data doesn't match the cipher's block size
|
||||
#[error("invalid block size: expected {expected} bytes, got {actual}")]
|
||||
#[error("Invalid block size: expected {expected} bytes, got {actual}")]
|
||||
InvalidBlockSize { expected: usize, actual: usize },
|
||||
|
||||
/// Decryption detected invalid padding
|
||||
#[error("invalid padding detected during decryption")]
|
||||
InvalidPadding,
|
||||
|
||||
/// Input length not valid for unpadded operation
|
||||
#[error("invalid plaintext length: {actual} bytes (must be multiple of block size)")]
|
||||
InvalidPlaintextLength { actual: usize },
|
||||
|
||||
/// General size validation failure
|
||||
#[error("size mismatch: expected {expected} bytes, got {actual}")]
|
||||
InvalidSize { expected: usize, actual: usize },
|
||||
}
|
||||
|
||||
impl CipherError {
|
||||
/// Creates a key size error
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn invalid_key_size(expected: usize, actual: usize) -> Self {
|
||||
Self::InvalidKeySize { expected, actual }
|
||||
}
|
||||
|
||||
/// Creates a block size error
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn invalid_block_size(expected: usize, actual: usize) -> Self {
|
||||
Self::InvalidBlockSize { expected, actual }
|
||||
}
|
||||
|
||||
/// Creates an invalid padding error
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn invalid_padding() -> Self {
|
||||
Self::InvalidPadding
|
||||
}
|
||||
|
||||
/// Creates a plaintext length error
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn invalid_plaintext_length(actual: usize) -> Self {
|
||||
Self::InvalidPlaintextLength { actual }
|
||||
}
|
||||
|
||||
/// Returns true if this is a key size error
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn is_key_error(&self) -> bool {
|
||||
matches!(self, Self::InvalidKeySize { .. })
|
||||
}
|
||||
|
||||
/// Returns true if this is a block size error
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn is_block_error(&self) -> bool {
|
||||
matches!(self, Self::InvalidBlockSize { .. })
|
||||
}
|
||||
|
||||
/// Returns true if this is a size-related error
|
||||
#[must_use]
|
||||
pub const fn is_size_error(&self) -> bool {
|
||||
self.is_key_error() || self.is_block_error() || matches!(self, Self::InvalidSize { .. })
|
||||
}
|
||||
|
||||
/// Returns the expected size for size-related errors
|
||||
#[must_use]
|
||||
pub const fn expected_size(&self) -> Option<usize> {
|
||||
match self {
|
||||
Self::InvalidKeySize { expected, .. }
|
||||
| Self::InvalidBlockSize { expected, .. }
|
||||
| Self::InvalidSize { expected, .. } => Some(*expected),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the actual size for size-related errors
|
||||
#[must_use]
|
||||
pub const fn actual_size(&self) -> Option<usize> {
|
||||
match self {
|
||||
Self::InvalidKeySize { actual, .. }
|
||||
| Self::InvalidBlockSize { actual, .. }
|
||||
| Self::InvalidSize { actual, .. }
|
||||
| Self::InvalidPlaintextLength { actual } => Some(*actual),
|
||||
Self::InvalidPadding => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias for clean Result types
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
use crate::{CipherAction, CipherError, CipherResult};
|
||||
|
||||
/// Generic block cipher trait.
|
||||
///
|
||||
/// Implements the standard encrypt/decrypt interface for block ciphers.
|
||||
/// Implementers define `transform_impl` to handle the core algorithm,
|
||||
/// while `transform` provides validation and convenience wrappers.
|
||||
pub trait BlockCipher: Sized {
|
||||
const BLOCK_SIZE: usize;
|
||||
|
||||
/// Core cipher transformation (must be implemented by concrete types).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `CipherError` if the transformation fails.
|
||||
fn transform_impl(&self, block: &[u8], action: CipherAction) -> CipherResult<Vec<u8>>;
|
||||
|
||||
/// Transforms a block with validation.
|
||||
///
|
||||
/// Validates that the block size matches `BLOCK_SIZE` before delegating
|
||||
/// to `transform_impl`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `CipherError::InvalidBlockSize` if `block.len() != BLOCK_SIZE`.
|
||||
fn transform(&self, block: &[u8], action: CipherAction) -> CipherResult<Vec<u8>> {
|
||||
if block.len() != Self::BLOCK_SIZE {
|
||||
return Err(CipherError::invalid_block_size(
|
||||
@@ -15,9 +33,20 @@ pub trait BlockCipher: Sized {
|
||||
self.transform_impl(block, action)
|
||||
}
|
||||
|
||||
/// Encrypts a single block.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `CipherError::InvalidBlockSize` if the plaintext is not exactly `BLOCK_SIZE` bytes.
|
||||
fn encrypt(&self, plaintext: &[u8]) -> CipherResult<Vec<u8>> {
|
||||
self.transform(plaintext, CipherAction::Encrypt)
|
||||
}
|
||||
|
||||
/// Decrypts a single block.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns `CipherError::InvalidBlockSize` if the plaintext is not exactly `BLOCK_SIZE` bytes.
|
||||
fn decrypt(&self, ciphertext: &[u8]) -> CipherResult<Vec<u8>> {
|
||||
self.transform(ciphertext, CipherAction::Decrypt)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user