mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2025-12-31 13:52:29 +00:00
feat(cipher-factory): add AesCbc algorithm variant
Add AES-CBC support to Algorithm enum:
- Add AesCbc variant with clap name "aes-cbc"
- Add requires_iv() method to check if algorithm needs IV
- Add new_cbc_cipher() for creating AesCbc instances
- Add encrypt_cbc() and decrypt_cbc() helper methods
- Update parse_text() and Display for AesCbc
This commit is contained in:
parent
454d1d6011
commit
6c5cd9b78a
@ -1,7 +1,7 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use aes::{Aes, Block128};
|
use aes::{Aes, AesCbc, Block128, Iv};
|
||||||
use cipher_core::{BlockCipher, BlockError, CipherError};
|
use cipher_core::{BlockCipher, BlockError, CipherError, CipherResult};
|
||||||
use des::{Block64, Des};
|
use des::{Block64, Des};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
@ -10,24 +10,27 @@ use std::str::FromStr;
|
|||||||
pub enum Algorithm {
|
pub enum Algorithm {
|
||||||
Des,
|
Des,
|
||||||
Aes,
|
Aes,
|
||||||
|
#[cfg_attr(feature = "clap", clap(name = "aes-cbc"))]
|
||||||
|
AesCbc,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Algorithm {
|
impl Algorithm {
|
||||||
/// Creates a new cipher instance for the specified algorithm.
|
/// Returns whether this algorithm requires an IV (Initialization Vector).
|
||||||
|
#[must_use]
|
||||||
|
pub const fn requires_iv(&self) -> bool {
|
||||||
|
matches!(self, Self::AesCbc)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new ECB-mode cipher instance for the specified algorithm.
|
||||||
///
|
///
|
||||||
/// Parses the key string and instantiates either DES or AES based on the algorithm choice.
|
/// Parses the key string and instantiates either DES or AES based on the algorithm choice.
|
||||||
/// The key format depends on the algorithm:
|
/// The key format depends on the algorithm:
|
||||||
/// - DES: 64-bit key (hex string, e.g., "0x1334577999bcdff1")
|
/// - DES: 64-bit key (hex string, e.g., "0x1334577999bcdff1")
|
||||||
/// - AES: 128-bit key (hex string, e.g., "0x2b7e151628aed2a6abf7158809cf4f3c")
|
/// - AES: 128-bit key (hex string, e.g., "0x2b7e151628aed2a6abf7158809cf4f3c")
|
||||||
///
|
///
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// A boxed cipher instance implementing `BlockCipher`, or a `CipherError` if parsing fails.
|
|
||||||
///
|
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns `CipherError` if the key cannot be parsed (invalid format, wrong length, etc.).
|
/// Returns `CipherError` if the key cannot be parsed or if called with a CBC algorithm.
|
||||||
///
|
|
||||||
pub fn new_cipher(&self, key: &str) -> Result<Box<dyn BlockCipher>, CipherError> {
|
pub fn new_cipher(&self, key: &str) -> Result<Box<dyn BlockCipher>, CipherError> {
|
||||||
match self {
|
match self {
|
||||||
Self::Des => {
|
Self::Des => {
|
||||||
@ -40,9 +43,50 @@ impl Algorithm {
|
|||||||
let cipher = Aes::from_key(key);
|
let cipher = Aes::from_key(key);
|
||||||
Ok(Box::new(cipher))
|
Ok(Box::new(cipher))
|
||||||
}
|
}
|
||||||
|
Self::AesCbc => Err(CipherError::InvalidPadding(
|
||||||
|
"AES-CBC requires an IV; use new_cbc_cipher instead".into(),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new AES-CBC cipher instance with the given key and IV.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns `CipherError` if the key or IV cannot be parsed.
|
||||||
|
pub fn new_cbc_cipher(&self, key: &str, iv: &str) -> Result<AesCbc, CipherError> {
|
||||||
|
match self {
|
||||||
|
Self::AesCbc => {
|
||||||
|
let key = Block128::from_str(key)?;
|
||||||
|
let iv = Iv::from_str(iv)?;
|
||||||
|
Ok(AesCbc::new(key, iv))
|
||||||
|
}
|
||||||
|
_ => Err(CipherError::InvalidPadding(format!(
|
||||||
|
"{self} does not support CBC mode"
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encrypts data using CBC mode with PKCS#7 padding.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns `CipherError` if encryption fails.
|
||||||
|
pub fn encrypt_cbc(&self, key: &str, iv: &str, plaintext: &[u8]) -> CipherResult<Vec<u8>> {
|
||||||
|
let cipher = self.new_cbc_cipher(key, iv)?;
|
||||||
|
cipher.encrypt(plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypts data using CBC mode and removes PKCS#7 padding.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns `CipherError` if decryption fails or padding is invalid.
|
||||||
|
pub fn decrypt_cbc(&self, key: &str, iv: &str, ciphertext: &[u8]) -> CipherResult<Vec<u8>> {
|
||||||
|
let cipher = self.new_cbc_cipher(key, iv)?;
|
||||||
|
cipher.decrypt(ciphertext)
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses plaintext or ciphertext according to the specified algorithm's block size.
|
/// Parses plaintext or ciphertext according to the specified algorithm's block size.
|
||||||
///
|
///
|
||||||
/// Converts a text string into a byte vector using the appropriate block size:
|
/// Converts a text string into a byte vector using the appropriate block size:
|
||||||
@ -63,10 +107,13 @@ impl Algorithm {
|
|||||||
/// - The text length doesn't match the block size
|
/// - The text length doesn't match the block size
|
||||||
/// - The text contains invalid characters for the given format
|
/// - The text contains invalid characters for the given format
|
||||||
///
|
///
|
||||||
|
/// Parses text for ECB-mode algorithms (single block).
|
||||||
|
///
|
||||||
|
/// For CBC mode, use raw bytes directly instead of this method.
|
||||||
pub fn parse_text(&self, text: &str) -> Result<Vec<u8>, BlockError> {
|
pub fn parse_text(&self, text: &str) -> Result<Vec<u8>, BlockError> {
|
||||||
match self {
|
match self {
|
||||||
Self::Des => Ok(Block64::from_str(text)?.to_be_bytes().to_vec()),
|
Self::Des => Ok(Block64::from_str(text)?.to_be_bytes().to_vec()),
|
||||||
Self::Aes => Ok(Block128::from_str(text)?.to_be_bytes().to_vec()),
|
Self::Aes | Self::AesCbc => Ok(Block128::from_str(text)?.to_be_bytes().to_vec()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,6 +123,7 @@ impl Display for Algorithm {
|
|||||||
let s = match self {
|
let s = match self {
|
||||||
Self::Des => "DES",
|
Self::Des => "DES",
|
||||||
Self::Aes => "AES",
|
Self::Aes => "AES",
|
||||||
|
Self::AesCbc => "AES-CBC",
|
||||||
};
|
};
|
||||||
f.write_str(s)
|
f.write_str(s)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user