use super::*; use std::{ path::{ PathBuf, }, }; /// The type of key to generate #[derive(Debug,Eq,PartialEq)] pub enum GenerateKey { Rsa, Aes, } /// The key serialise format #[derive(Debug,Eq,PartialEq)] pub enum KeyOutputFormat { Binary, Text, /// PEM format only valid for RSA keys PEM, } impl FromStr for KeyOutputFormat { type Err = Error; fn from_str(value: &str) -> Result { Ok(match value.to_uppercase().as_str() { "TEXT" => KeyOutputFormat::Text, "BIN" => KeyOutputFormat::Binary, "PEM" => KeyOutputFormat::PEM, d => return Err(format!("Unknown key output format `{}`. Expected `TEXT`, `BIN` or `PEM`.", d))?, }) } } impl KeyOutputFormat { pub fn is_aes_okay(&self) -> bool { if let KeyOutputFormat::PEM = self { false } else { true } } } /// Operation mode for `Operation::Normal` #[derive(Debug,Eq,PartialEq)] pub enum OperationMode { Autodetect, Encrypt, Decrypt, Verify, } /// The operation for this run #[derive(Debug,Eq,PartialEq)] pub enum Operation { /// Crypto Normal{ mode: OperationMode, rsa: Vec, sign: Vec, auto_sign: bool, aes: Vec, translate: Vec<(PathBuf, Option)>, in_place: bool, verbose: bool, #[cfg(feature="threads")] sync: bool, }, /// Generate key KeyGen{ key_type: GenerateKey, format: KeyOutputFormat, cycle: Option, use_password: bool, password: Option, output: Option, private_only: bool, public_only: bool, output_public: Option, verbose: bool, }, /// Print help Help, } impl Operation { /// Is verbose logging enabled pub fn verbose(&self) -> bool { match self { Self::Normal { verbose, .. } | Self::KeyGen { verbose, .. } => *verbose, _ => false, } } } macro_rules! transcribe { ($cond:expr => $if:expr; $else:expr) => { if $cond {$if} else {$else} }; } use std::fmt; impl fmt::Display for Operation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self { Self::Help => writeln!(f, "Display help"), Self::Normal{ mode, rsa, sign, auto_sign, aes, in_place, verbose, #[cfg(feature="threads")] sync, .. } => { write!(f, "Mode: ")?; match mode { OperationMode::Encrypt => writeln!(f, "Encrypt")?, OperationMode::Decrypt => writeln!(f, "Decrypt")?, OperationMode::Verify => writeln!(f, "Verify")?, _ => writeln!(f, "Autodetected")?, } if rsa.len() > 0 { writeln!(f, "RSA encryption enabled for {} keys.", rsa.len())?; } if sign.len() > 0 || *auto_sign { writeln!(f, "Signing with {} keys.", sign.len() + transcribe!(*auto_sign => rsa.len(); 0))?; } writeln!(f, "AES encrypting with {} keys.", aes.len())?; writeln!(f, " (will generate {} session keys.)", transcribe!(aes.len() > 0 => aes.len() * transcribe!(rsa.len()>0 => rsa.len(); 1); rsa.len()))?; if *in_place { writeln!(f, "In-place")?; } #[cfg(feature="threads")] if *sync { writeln!(f, "Single-threaded mode")?; } #[cfg(not(feature="threads"))] writeln!(f, "Single-threaded mode")?; if *verbose { writeln!(f, "Verbose mode")?; } Ok(()) }, Self::KeyGen { key_type: GenerateKey::Rsa, format, cycle, password, use_password, output, verbose, private_only, output_public, public_only, } => { writeln!(f, "Generate key: RSA")?; writeln!(f, "Output format: {}", format)?; if let Some(cycle) = cycle { if output.is_some() || output_public.is_some() { writeln!(f, "Input: {:?}", cycle)?; } else { writeln!(f, "In-place: {:?}", cycle)?; } } if password.is_some() || *use_password { writeln!(f, "Using password.")?; } if let Some(output) = output { writeln!(f, "Outputting to: {:?}", output)?; } if let Some(output_public) = output_public { if *public_only { writeln!(f, "Outputting public only to {:?}", output_public)?; } else { writeln!(f, "Outputting public to {:?}", output_public)?; } } if *private_only { writeln!(f, "No public output")?; } if *verbose { writeln!(f, "Verbose logging")?; } Ok(()) }, Self::KeyGen { key_type: GenerateKey::Aes, format, cycle, password, use_password, output, verbose, .. } => { writeln!(f, "Generate key: AES")?; writeln!(f, "Output format: {}", format)?; if let Some(cycle) = cycle { if output.is_some() { writeln!(f, "Input: {:?}", cycle)?; } else { writeln!(f, "In-place: {:?}", cycle)?; } } if password.is_some() || *use_password { writeln!(f, "Using password.")?; } if let Some(output) = output { writeln!(f, "Outputting to: {:?}", output)?; } if *verbose { writeln!(f, "Verbose logging.")?; } Ok(()) }, } } } impl fmt::Display for KeyOutputFormat { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", match self { Self::PEM => "PEM", Self::Text => "TEXT", Self::Binary => "BIN", }) } }