use clap::{Parser, Subcommand};
use rasypt_lite_lib::Algorithm;
const MIN_RECOMMENDED_PASSWORD_LEN: usize = 8;
#[derive(Parser)]
#[command(
name = "rasypt-lite",
about = "Password-based encryption with PBEWithHMACSHA512AndAES_256 and SM-compliant algorithms"
)]
struct Cli {
#[arg(short, long, default_value_t = false, global = true)]
quiet: bool,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Encrypt {
#[arg(short, long)]
input: String,
#[arg(short, long)]
password: String,
#[arg(long, default_value_t = false)]
wrap: bool,
#[arg(
short = 'a',
long = "algorithm",
alias = "alg",
default_value = "PBEWithHMACSHA512AndAES_256",
value_parser = clap::value_parser!(Algorithm)
)]
algorithm: Algorithm,
#[arg(long = "iterations")]
iterations: Option<u32>,
},
Decrypt {
#[arg(short, long)]
input: String,
#[arg(short, long)]
password: String,
#[arg(
short = 'a',
long = "algorithm",
alias = "alg",
default_value = "PBEWithHMACSHA512AndAES_256",
value_parser = clap::value_parser!(Algorithm)
)]
algorithm: Algorithm,
#[arg(long = "iterations")]
iterations: Option<u32>,
},
}
fn main() {
let cli = Cli::parse();
match cli.command {
Commands::Encrypt {
input,
password,
wrap,
algorithm,
iterations,
} => {
warn_if_password_too_short(&password, cli.quiet);
let encrypted = match iterations {
Some(it) => {
rasypt_lite_lib::encrypt_with_iterations(algorithm, &password, &input, it)
}
None => rasypt_lite_lib::encrypt_with(algorithm, &password, &input),
};
if wrap && algorithm == Algorithm::PBEWithHMACSHA512AndAES_256 {
println!("ENC({})", encrypted);
} else if wrap {
eprintln!("Warning: --wrap is only supported with the default algorithm; output not wrapped.");
println!("{}", encrypted);
} else {
println!("{}", encrypted);
}
}
Commands::Decrypt {
input,
password,
algorithm,
iterations,
} => {
warn_if_password_too_short(&password, cli.quiet);
let result = if algorithm == Algorithm::PBEWithHMACSHA512AndAES_256
&& rasypt_lite_lib::is_enc_value(&input)
{
rasypt_lite_lib::decrypt_enc(&input, &password)
} else {
match iterations {
Some(it) => rasypt_lite_lib::decrypt_with_iterations(
algorithm, &password, &input, it,
),
None => rasypt_lite_lib::decrypt_with(algorithm, &password, &input),
}
};
match result {
Ok(plaintext) => println!("{}", plaintext),
Err(e) => {
eprintln!("Decryption failed: {}", e);
std::process::exit(1);
}
}
}
}
}
fn warn_if_password_too_short(password: &str, quiet: bool) {
if quiet || password.chars().count() >= MIN_RECOMMENDED_PASSWORD_LEN {
return;
}
eprintln!(
"Warning: password length is below the recommended {} characters; continuing anyway. Use --quiet to suppress this warning.",
MIN_RECOMMENDED_PASSWORD_LEN
);
}