ruscrypt/
dispatcher.rs

1//! # Command Dispatcher Module
2//!
3//! This module handles the routing and execution of CLI commands. It takes parsed
4//! command-line arguments and dispatches them to the appropriate cryptographic
5//! functions while providing user interaction and formatted output.
6//!
7//! ## Architecture
8//!
9//! The dispatcher follows a pattern where:
10//! 1. Commands are parsed and displayed to the user
11//! 2. Interactive prompts gather necessary parameters
12//! 3. Appropriate cryptographic functions are called
13//! 4. Results are formatted and displayed
14//!
15//! ## Error Handling
16//!
17//! All functions return `Result<()>` to enable proper error propagation
18//! and user-friendly error messages.
19
20use anyhow::Result;
21use colored::*;
22
23use crate::asym::{dh, rsa};
24use crate::block::{aes, des};
25use crate::classical::{caesar, playfair, rail_fence, vigenere};
26use crate::cli::{
27    Commands, EncryptionAlgorithm, ExchangeProtocol, HashAlgorithm, KeygenAlgorithm,
28    SigningAlgorithm,
29};
30use crate::hash::{md5, sha1, sha256};
31use crate::stream::rc4;
32use crate::{cli, interactive};
33
34/// Dispatch and execute the appropriate command based on parsed CLI arguments
35pub fn dispatch_command(args: cli::Args) -> Result<()> {
36    match args.command {
37        Commands::Encrypt { algorithm } => {
38            let algo_name = cli::get_algorithm_name(&algorithm);
39            println!(
40                "{} {}",
41                "πŸ”’ Encrypting with".green(),
42                algo_name.yellow().bold()
43            );
44            handle_encryption(algorithm)?;
45        }
46        Commands::Decrypt { algorithm } => {
47            let algo_name = cli::get_algorithm_name(&algorithm);
48            println!(
49                "{} {}",
50                "πŸ”“ Decrypting with".blue(),
51                algo_name.yellow().bold()
52            );
53            handle_decryption(algorithm)?;
54        }
55        Commands::Hash { algorithm } => {
56            let algo_name = cli::get_hash_algorithm_name(&algorithm);
57            println!(
58                "{} {}",
59                "πŸ”’ Hashing with".magenta(),
60                algo_name.yellow().bold()
61            );
62            handle_hashing(algorithm)?;
63        }
64        Commands::Exchange { protocol } => {
65            let protocol_name = cli::get_keyexchange_protocol_name(&protocol);
66            println!(
67                "{} {}",
68                "πŸ”‘ Key Exchange with".purple(),
69                protocol_name.yellow().bold()
70            );
71            handle_key_exchange(protocol)?;
72        }
73        Commands::Keygen { algorithm } => {
74            let algo_name = cli::get_keygen_algorithm_name(&algorithm);
75            println!(
76                "{} {}",
77                "πŸ”‘ Generating key for".cyan(),
78                algo_name.yellow().bold()
79            );
80            handle_keygen(algorithm)?;
81        }
82        Commands::Sign { algorithm } => {
83            let algo_name = cli::get_signing_algorithm_name(&algorithm);
84            println!("✍️ Signing with {algo_name} algorithm...");
85
86            if algorithm.rsa {
87                handle_sign(algorithm)?;
88            }
89        }
90        Commands::Verify { algorithm } => {
91            let algo_name = cli::get_signing_algorithm_name(&algorithm);
92            println!("πŸ” Verifying {algo_name} signature...");
93
94            if algorithm.rsa {
95                handle_verify(algorithm)?;
96            }
97        }
98    }
99
100    Ok(())
101}
102
103/// Handle encryption operations for all supported algorithms
104///
105/// This function manages the encryption workflow by:
106/// 1. Prompting for input text
107/// 2. Gathering algorithm-specific parameters (keys, shifts, etc.)
108/// 3. Calling the appropriate encryption function
109/// 4. Displaying the encrypted result
110///
111/// # Arguments
112///
113/// * `algorithm` - The encryption algorithm configuration specifying which algorithm to use
114///
115/// # Returns
116///
117/// Returns `Ok(())` on successful encryption, or an error if the operation fails.
118///
119/// # Interactive Prompts
120///
121/// Depending on the algorithm, this function may prompt for:
122/// - Shift values (Caesar cipher)
123/// - Keywords (Vigenère, Playfair)
124/// - Keys and passwords (RC4, AES, DES, RSA)
125/// - Encoding preferences (base64, hex)
126/// - Algorithm parameters (key sizes, modes)
127///
128/// # Errors
129///
130/// Can return errors from:
131/// - Invalid user input
132/// - Cryptographic operation failures
133/// - I/O errors during prompts
134/// - Algorithm-specific validation failures
135fn handle_encryption(algorithm: EncryptionAlgorithm) -> Result<()> {
136    let input = interactive::prompt_for_input("Enter text to encrypt")?;
137
138    let result = match true {
139        _ if algorithm.caesar => {
140            let shift = interactive::prompt_for_number("Enter shift value (1-25)", 1, 25)?;
141            let encrypted = caesar::encrypt(&input, shift as u8)?;
142            format!("Encrypted text: {encrypted}")
143        }
144        _ if algorithm.vigenere => {
145            let keyword = interactive::prompt_for_input("Enter keyword")?;
146            let encrypted = vigenere::encrypt(&input, &keyword)?;
147            format!("Encrypted text: {encrypted}")
148        }
149        _ if algorithm.playfair => {
150            let keyword = interactive::prompt_for_input("Enter keyword for matrix")?;
151            let encrypted = playfair::encrypt(&input, &keyword)?;
152            format!("Encrypted text: {encrypted}")
153        }
154        _ if algorithm.railfence => {
155            let rails = interactive::prompt_for_number("Enter number of rails (2-10)", 2, 10)?;
156            let encrypted = rail_fence::encrypt(&input, rails as usize)?;
157            format!("Encrypted text: {encrypted}")
158        }
159        _ if algorithm.rc4 => {
160            let key = interactive::prompt_for_password("Enter encryption key")?;
161            let encoding =
162                interactive::prompt_for_choices("Select output encoding", &["base64", "hex"])?;
163            let encrypted = rc4::encrypt(&input, &key, &encoding)?;
164            format!("Encrypted text ({encoding}): {encrypted}")
165        }
166        _ if algorithm.aes => {
167            let password = interactive::prompt_for_password("Enter password")?;
168            let key_size =
169                interactive::prompt_for_choices("Select AES key size", &["128", "192", "256"])?;
170            let mode = interactive::prompt_for_choices("Select encryption mode", &["ECB", "CBC"])?;
171            let encoding =
172                interactive::prompt_for_choices("Select output encoding", &["base64", "hex"])?;
173            let encrypted = aes::encrypt(&input, &password, &key_size, &mode, &encoding)?;
174            format!("Encrypted text (AES-{key_size}, {mode}, {encoding}): {encrypted}")
175        }
176        _ if algorithm.des => {
177            let key = interactive::prompt_for_input("Enter key (exactly 8 characters)")?;
178            if key.len() != 8 {
179                return Err(anyhow::anyhow!("DES key must be exactly 8 characters long"));
180            }
181            let mode = interactive::prompt_for_choices("Select encryption mode", &["ECB", "CBC"])?;
182            let encoding =
183                interactive::prompt_for_choices("Select output encoding", &["base64", "hex"])?;
184            let encrypted = des::encrypt(&input, &key, &mode, &encoding)?;
185            format!("Encrypted text (DES, {mode}, {encoding}): {encrypted}")
186        }
187        _ if algorithm.rsa => {
188            let key_size =
189                interactive::prompt_for_choices("Select RSA key size", &["512", "1024", "2048"])?;
190            let encoding =
191                interactive::prompt_for_choices("Select output encoding", &["base64", "hex"])?;
192            let privkey_format = interactive::prompt_for_choices(
193                "Select private key output format",
194                &["n:d", "PEM"],
195            )?;
196            let (encrypted, private_key) =
197                rsa::encrypt(&input, &key_size, &encoding, &privkey_format)?;
198
199            println!("\nπŸ” RSA Encryption Complete!");
200            println!("πŸ“€ Encrypted data: {encrypted}");
201            println!("πŸ”‘ Private key (SAVE THIS!): {private_key}");
202            println!("⚠️  Keep your private key secure - you'll need it for decryption!");
203
204            format!("RSA-{key_size} encryption successful. Encrypted data and private key provided above.")
205        }
206        _ => return Err(anyhow::anyhow!("Unknown algorithm")),
207    };
208
209    println!("\n{} {}", "Result:".cyan().bold(), result.white());
210    Ok(())
211}
212
213/// Handle decryption operations for all supported algorithms
214///
215/// This function manages the decryption workflow by:
216/// 1. Prompting for encrypted text
217/// 2. Gathering algorithm-specific parameters (keys, shifts, etc.)
218/// 3. Calling the appropriate decryption function
219/// 4. Displaying the decrypted result
220///
221/// # Arguments
222///
223/// * `algorithm` - The encryption algorithm configuration specifying which algorithm to use
224///
225/// # Returns
226///
227/// Returns `Ok(())` on successful decryption, or an error if the operation fails.
228///
229/// # Interactive Prompts
230///
231/// Similar to encryption, but may include additional prompts for:
232/// - Private keys (RSA)
233/// - Initialization vectors (block ciphers)
234/// - Input encoding formats (base64, hex)
235///
236/// # Errors
237///
238/// Can return errors from:
239/// - Invalid encrypted text format
240/// - Incorrect keys or parameters
241/// - Cryptographic operation failures
242/// - Encoding/decoding errors
243fn handle_decryption(algorithm: EncryptionAlgorithm) -> Result<()> {
244    let input = interactive::prompt_for_input("Enter text to decrypt")?;
245
246    let result = match true {
247        _ if algorithm.caesar => {
248            let shift = interactive::prompt_for_number("Enter shift value (1-25)", 1, 25)?;
249            let decrypted = caesar::decrypt(&input, shift as u8)?;
250            format!("Decrypted text: {decrypted}")
251        }
252        _ if algorithm.vigenere => {
253            let keyword = interactive::prompt_for_input("Enter keyword")?;
254            let decrypted = vigenere::decrypt(&input, &keyword)?;
255            format!("Decrypted text: {decrypted}")
256        }
257        _ if algorithm.playfair => {
258            let keyword = interactive::prompt_for_input("Enter keyword for matrix")?;
259            let decrypted = playfair::decrypt(&input, &keyword)?;
260            format!("Decrypted text: {decrypted}")
261        }
262        _ if algorithm.railfence => {
263            let rails = interactive::prompt_for_number("Enter number of rails (2-10)", 2, 10)?;
264            let decrypted = rail_fence::decrypt(&input, rails as usize)?;
265            format!("Decrypted text: {decrypted}")
266        }
267        _ if algorithm.rc4 => {
268            let key = interactive::prompt_for_password("Enter decryption key")?;
269            let encoding =
270                interactive::prompt_for_choices("Select input encoding", &["base64", "hex"])?;
271            let decrypted = rc4::decrypt(&input, &key, &encoding)?;
272            format!("Decrypted text: {decrypted}")
273        }
274        _ if algorithm.aes => {
275            let password = interactive::prompt_for_password("Enter password")?;
276            let key_size =
277                interactive::prompt_for_choices("Select AES key size", &["128", "192", "256"])?;
278            let mode = interactive::prompt_for_choices("Select encryption mode", &["ECB", "CBC"])?;
279            let encoding =
280                interactive::prompt_for_choices("Select input encoding", &["base64", "hex"])?;
281            let decrypted = aes::decrypt(&input, &password, &key_size, &mode, &encoding)?;
282            format!("Decrypted text: {decrypted}")
283        }
284        _ if algorithm.des => {
285            let key = interactive::prompt_for_input("Enter key (exactly 8 characters)")?;
286            if key.len() != 8 {
287                return Err(anyhow::anyhow!("DES key must be exactly 8 characters long"));
288            }
289            let mode = interactive::prompt_for_choices("Select encryption mode", &["ECB", "CBC"])?;
290            let encoding =
291                interactive::prompt_for_choices("Select input encoding", &["base64", "hex"])?;
292            let decrypted = des::decrypt(&input, &key, &mode, &encoding)?;
293            format!("Decrypted text: {decrypted}")
294        }
295        _ if algorithm.rsa => {
296            let private_key = interactive::prompt_for_multiline_input(
297                "Enter private key (format: n:d or PEM block, end with empty line)",
298            )?;
299            let encoding =
300                interactive::prompt_for_choices("Select input encoding", &["base64", "hex"])?;
301            let decrypted = rsa::decrypt(&input, &private_key, &encoding)?;
302            format!("Decrypted text: {decrypted}")
303        }
304        _ => return Err(anyhow::anyhow!("Unknown algorithm")),
305    };
306
307    println!("\n{} {}", "Result:".cyan().bold(), result.white());
308    Ok(())
309}
310
311/// Handle hashing operations for all supported hash functions
312///
313/// This function manages the hashing workflow by:
314/// 1. Prompting for input text
315/// 2. Computing the hash using the selected algorithm
316/// 3. Displaying the hash value in hexadecimal format
317///
318/// # Arguments
319///
320/// * `algorithm` - The hash algorithm configuration specifying which function to use
321///
322/// # Returns
323///
324/// Returns `Ok(())` on successful hashing, or an error if the operation fails.
325///
326/// # Output Format
327///
328/// Hash values are displayed as hexadecimal strings:
329/// - MD5: 32 characters
330/// - SHA-1: 40 characters  
331/// - SHA-256: 64 characters
332///
333/// # Errors
334///
335/// Can return errors from:
336/// - Hash computation failures
337/// - I/O errors during prompts
338/// - Memory allocation issues for large inputs
339fn handle_hashing(algorithm: HashAlgorithm) -> Result<()> {
340    let input = interactive::prompt_for_input("Enter text to hash")?;
341
342    let result = match true {
343        _ if algorithm.md5 => {
344            let hash_value = md5::hash(&input)?;
345            format!("MD5 hash: {hash_value}")
346        }
347        _ if algorithm.sha1 => {
348            let hash_value = sha1::hash(&input)?;
349            format!("SHA-1 hash: {hash_value}")
350        }
351        _ if algorithm.sha256 => {
352            let hash_value = sha256::hash(&input)?;
353            format!("SHA-256 hash: {hash_value}")
354        }
355        _ => return Err(anyhow::anyhow!("Unknown algorithm")),
356    };
357
358    println!("\n{} {}", "Result:".blue().bold(), result.white());
359    Ok(())
360}
361
362/// Handle key exchange protocol operations
363///
364/// This function manages key exchange workflows by:
365/// 1. Presenting protocol-specific options
366/// 2. Managing interactive or manual exchange modes
367/// 3. Facilitating secure key establishment
368/// 4. Displaying shared secrets and educational information
369///
370/// # Arguments
371///
372/// * `protocol` - The key exchange protocol configuration
373///
374/// # Returns
375///
376/// Returns `Ok(())` on successful key exchange, or an error if the operation fails.
377///
378/// # Supported Modes
379///
380/// For Diffie-Hellman:
381/// - **Interactive Simulation**: Demonstrates Alice & Bob exchange
382/// - **Manual Exchange - Start Session**: Real-world usage with other parties
383/// - **Manual Exchange - Complete with Other's Key**: Complete the exchange with a given key
384/// - **Mathematical Demo**: Shows the underlying mathematics
385///
386/// # Security Considerations
387///
388/// The function provides educational warnings about:
389/// - Parameter selection importance
390/// - Man-in-the-middle attack risks
391/// - Proper implementation requirements
392///
393/// # Errors
394///
395/// Can return errors from:
396/// - Invalid protocol selection
397/// - Mathematical computation failures
398/// - User input validation errors
399/// - Network communication issues (future implementations)
400fn handle_key_exchange(protocol: ExchangeProtocol) -> Result<()> {
401    let result = match true {
402        _ if protocol.dh => {
403            let choice = interactive::prompt_for_choices(
404                "Select Diffie-Hellman operation",
405                &[
406                    "Interactive Simulation (Alice & Bob)",
407                    "Manual Exchange - Start Session",
408                    "Manual Exchange - Complete with Other's Key",
409                    "Mathematical Concept Demo",
410                ],
411            )?;
412
413            match choice.as_str() {
414                "Interactive Simulation (Alice & Bob)" => dh::key_exchange("interactive")?,
415                "Manual Exchange - Start Session" => {
416                    println!("\nπŸš€ Starting manual key exchange session...");
417                    dh::key_exchange("manual")?
418                }
419                "Manual Exchange - Complete with Other's Key" => {
420                    let other_public_key =
421                        interactive::prompt_for_input("Enter other party's public key")?
422                            .parse::<u64>()
423                            .map_err(|_| {
424                                anyhow::anyhow!("Invalid public key format. Must be a number.")
425                            })?;
426
427                    let my_private_key = interactive::prompt_for_input("Enter your private key")?
428                        .parse::<u64>()
429                        .map_err(|_| {
430                            anyhow::anyhow!("Invalid private key format. Must be a number.")
431                        })?;
432
433                    dh::complete_manual_key_exchange(other_public_key, my_private_key)?
434                }
435                "Mathematical Concept Demo" => dh::key_exchange("demo")?,
436                _ => return Err(anyhow::anyhow!("Invalid choice")),
437            }
438        }
439        _ if protocol.ecdh => "ECDH key exchange is not yet implemented. Coming soon!".to_string(),
440        _ => return Err(anyhow::anyhow!("Unknown key exchange protocol")),
441    };
442
443    println!("\n{} {}", "Result:".cyan().bold(), result.white());
444    Ok(())
445}
446
447/// Handle key generation operations for supported algorithms
448///
449/// This function manages the key generation workflow by:
450/// 1. Prompting for key size and output format
451/// 2. Calling the appropriate key generation function
452/// 3. Displaying the generated keys in the selected format
453///
454/// # Arguments
455///
456/// * `algorithm` - The key generation algorithm configuration
457///
458/// # Returns
459///
460/// Returns `Ok(())` on successful key generation, or an error if the operation fails.
461///
462/// # Interactive Prompts
463///
464/// - Key size (e.g., 512, 1024, 2048 for RSA)
465/// - Output format (e.g., "n:e" or "PEM")
466///
467/// # Errors
468///
469/// Can return errors from:
470/// - Invalid user input
471/// - Key generation failures
472/// - I/O errors during prompts
473fn handle_keygen(algorithm: KeygenAlgorithm) -> Result<()> {
474    if algorithm.rsa {
475        let key_size: String =
476            interactive::prompt_for_choices("Select RSA key size", &["512", "1024", "2048"])?;
477        let format = interactive::prompt_for_key_output_format()?;
478        let key_size_num = key_size
479            .parse::<u32>()
480            .map_err(|_| anyhow::anyhow!("Invalid key size"))?;
481        let (public_key, private_key) = rsa::keygen_and_export(key_size_num, &format)?;
482        println!("\n{} {}", "Public Key:".green().bold(), public_key.white());
483        println!("{} {}", "Private Key:".yellow().bold(), private_key.white());
484        println!("⚠️  Keep your private key secure!");
485        Ok(())
486    } else {
487        Err(anyhow::anyhow!("Unknown key generation algorithm"))
488    }
489}
490
491/// Handle RSA signing operations
492pub fn handle_sign(algorithm: SigningAlgorithm) -> Result<()> {
493    if algorithm.rsa {
494        println!("πŸ“ RSA Digital Signature");
495        println!("========================");
496
497        let data = interactive::prompt_for_input("Enter message to sign")?;
498        let private_key =
499            interactive::prompt_for_multiline_input("Enter private key (n:d format or PEM)")?;
500        let encoding = interactive::prompt_for_encoding("Select output encoding")?;
501
502        match rsa::sign(&data, &private_key, &encoding) {
503            Ok(signature) => {
504                println!("\nβœ… Digital signature created successfully!");
505                println!("πŸ“ Original message: {data}");
506                println!(
507                    "πŸ” Digital signature ({}): {}",
508                    encoding.to_uppercase(),
509                    signature
510                );
511                println!("\nπŸ’‘ Save this signature to verify the message authenticity later.");
512            }
513            Err(e) => {
514                eprintln!("❌ Signing failed: {e}");
515                return Err(e);
516            }
517        }
518
519        Ok(())
520    } else {
521        Err(anyhow::anyhow!("Unknown signing algorithm"))
522    }
523}
524
525/// Handle RSA signature verification operations
526pub fn handle_verify(algorithm: SigningAlgorithm) -> Result<()> {
527    if algorithm.rsa {
528        println!("πŸ” RSA Signature Verification");
529        println!("=============================");
530
531        let data = interactive::prompt_for_input("Enter original message")?;
532        let signature = interactive::prompt_for_input("Enter signature to verify")?;
533        let public_key =
534            interactive::prompt_for_multiline_input("Enter public key (n:e format or PEM)")?;
535        let encoding = interactive::prompt_for_encoding("Select signature encoding")?;
536
537        match rsa::verify(&data, &signature, &public_key, &encoding) {
538            Ok(is_valid) => {
539                println!("\nπŸ” Signature verification result:");
540                println!("πŸ“ Original message: {data}");
541                println!("πŸ” Signature: {}...", &signature[..signature.len().min(20)]);
542
543                if is_valid {
544                    println!("βœ… VALID: The signature is authentic!");
545                    println!("πŸ”’ The message integrity is verified and the signature is genuine.");
546                } else {
547                    println!("❌ INVALID: The signature verification failed!");
548                    println!(
549                        "⚠️  The message may have been tampered with or the signature is forged."
550                    );
551                }
552            }
553            Err(e) => {
554                eprintln!("❌ Verification failed: {e}");
555                return Err(e);
556            }
557        }
558
559        Ok(())
560    } else {
561        Err(anyhow::anyhow!("Unknown verification algorithm"))
562    }
563}