refactor: rename cli to crypt

This commit is contained in:
2026-01-12 20:56:47 +02:00
parent 6eb3668147
commit 9c14b01e68
4 changed files with 2 additions and 2 deletions

17
crypt/Cargo.toml Normal file
View File

@@ -0,0 +1,17 @@
[package]
name = "crypt"
version.workspace = true
authors.workspace = true
edition.workspace = true
[dependencies]
aes.workspace = true
cipher-core.workspace = true
cipher-factory = { workspace = true, features = ["clap"] }
clap.workspace = true
color-eyre.workspace = true
des.workspace = true
thiserror.workspace = true
[lints]
workspace = true

54
crypt/src/args.rs Normal file
View File

@@ -0,0 +1,54 @@
use cipher_factory::{Algorithm, CipherContext, OperationMode, OutputFormat};
use clap::Parser;
use std::path::PathBuf;
#[derive(Debug, Clone, Parser)]
#[command(version, about, long_about = None)]
pub struct Args {
/// Operation to perform
#[arg(value_name = "OPERATION")]
pub operation: OperationMode,
/// Encryption algorithm
#[arg(short, long)]
pub algorithm: Algorithm,
/// Key used for encryption/decryption (hex string, e.g., 0x2b7e...)
#[arg(short, long, required = true)]
pub key: String,
/// Initialization vector for CBC mode (hex string, e.g., 0x0001...)
#[arg(long)]
pub iv: Option<String>,
/// The text to encrypt/decrypt (use --input-file for file input)
#[arg(value_name = "TEXT", required_unless_present = "input_file")]
pub text: Option<String>,
/// Input file to encrypt/decrypt
#[arg(short, long, value_name = "FILE")]
pub input_file: Option<PathBuf>,
/// Output file (defaults to stdout)
#[arg(short, long, value_name = "FILE")]
pub output_file: Option<PathBuf>,
/// Output format for decrypted data
#[arg(short = 'f', long)]
pub output_format: Option<OutputFormat>,
}
impl Args {
/// Creates a [`CipherContext`] for text-based operations.
#[must_use]
pub fn into_context(self, input_text: String) -> CipherContext {
CipherContext {
algorithm: self.algorithm,
operation: self.operation,
key: self.key,
iv: self.iv,
input_text,
output_format: self.output_format.unwrap_or_default(),
}
}
}

101
crypt/src/main.rs Normal file
View File

@@ -0,0 +1,101 @@
mod args;
use crate::args::Args;
use aes::{AesCbc, Block128, Iv};
use cipher_factory::{Algorithm, OperationMode};
use clap::Parser;
use color_eyre::eyre::{Result, eyre};
use std::fs::{self, File};
use std::io::{Write, stdout};
use std::str::FromStr;
fn main() -> Result<()> {
color_eyre::install()?;
let args = Args::parse();
// Check if we're doing file-based CBC operation
if args.input_file.is_some() && args.algorithm == Algorithm::AesCbc {
process_cbc_file(&args)?;
} else {
process_text(&args)?;
}
Ok(())
}
fn process_text(args: &Args) -> Result<()> {
let input_text = match (&args.text, &args.input_file) {
(Some(text), None) => text.clone(),
(None, Some(path)) => fs::read_to_string(path)?,
(Some(_), Some(_)) => return Err(eyre!("Cannot specify both TEXT and --input-file")),
(None, None) => return Err(eyre!("Must specify TEXT or --input-file")),
};
let context = args.clone().into_context(input_text);
let output = context.process()?;
write_output(args, output.as_bytes())?;
Ok(())
}
fn process_cbc_file(args: &Args) -> Result<()> {
let input_path = args
.input_file
.as_ref()
.ok_or_else(|| eyre!("No input file"))?;
let iv_str = args
.iv
.as_ref()
.ok_or_else(|| eyre!("CBC mode requires --iv"))?;
let key = Block128::from_str(&args.key).map_err(|e| eyre!("Invalid key: {e}"))?;
let iv = Iv::from_str(iv_str).map_err(|e| eyre!("Invalid IV: {e}"))?;
let cipher = AesCbc::new(key, iv);
match args.operation {
OperationMode::Encrypt => {
let plaintext = fs::read(input_path)?;
let ciphertext = cipher
.encrypt(&plaintext)
.map_err(|e| eyre!("Encryption failed: {e}"))?;
if args.output_file.is_some() {
// Write raw binary to file
write_output(args, &ciphertext)?;
} else {
// Write hex to stdout
let hex = ciphertext.iter().fold(String::new(), |mut acc, b| {
use std::fmt::Write;
let _ = write!(acc, "{b:02X}");
acc
});
println!("{hex}");
}
}
OperationMode::Decrypt => {
let ciphertext = fs::read(input_path)?;
let plaintext = cipher
.decrypt(&ciphertext)
.map_err(|e| eyre!("Decryption failed: {e}"))?;
write_output(args, &plaintext)?;
}
}
Ok(())
}
fn write_output(args: &Args, data: &[u8]) -> Result<()> {
if let Some(path) = &args.output_file {
let mut file = File::create(path)?;
file.write_all(data)?;
} else {
stdout().write_all(data)?;
// Add newline if output doesn't end with one
if !data.ends_with(b"\n") {
println!();
}
}
Ok(())
}