diff --git a/src/lib/crypt.rs b/src/lib/crypt.rs index 129da04..39605ec 100644 --- a/src/lib/crypt.rs +++ b/src/lib/crypt.rs @@ -5,7 +5,6 @@ use des::Des; use rand::Rng; use rayon::prelude::*; use std::sync::Mutex; -use std::time::Instant; type DesCfb = Cfb; @@ -38,7 +37,6 @@ pub fn decrypt_with_dictionary( checksum: &[u8], ) -> Option> { let decrypted = Mutex::>>::new(None); - let start = Instant::now(); let pass = dict.par_iter().find_first(|(_pw, key)| { let decrypted_data = decrypt_data(&data, key); let decr_check = sha_checksum(&decrypted_data); @@ -51,11 +49,7 @@ pub fn decrypt_with_dictionary( }; }); if let Some((pw, _key)) = pass { - println!( - "\nPassword found in {:.2}s: {}", - start.elapsed().as_secs_f32(), - pw - ); + println!("\nPassword found: {}", pw); let decry = decrypted.lock().unwrap(); if let Some(decrypted_data) = (*decry).clone() { return Some(decrypted_data); diff --git a/src/main.rs b/src/main.rs index ffd4a42..f5024dd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ use rpassword::read_password_from_tty; use spinners::{Spinner, Spinners}; use std::fs; use std::fs::File; -use std::io::{BufWriter, Write}; +use std::io::{BufRead, BufReader, BufWriter, Write}; use std::sync::mpsc::sync_channel; use std::thread; use std::time::Duration; @@ -128,29 +128,10 @@ fn decrypt(_opts: &Opts, args: &Decrypt) { let data_checksum = base64::decode(bin_content.as_slice()).unwrap(); if let Some(dict) = dictionary { - let sp = spinner("Reading dictionary..."); - let pw_table: Vec; - { - let dictionary = fs::read_to_string(dict).expect("Failed to read dictionary file!"); - let lines = dictionary.par_lines(); - pw_table = lines - .map(|line| { - let parts: Vec<&str> = line.split("\t").collect::>(); - let pw = parts[0].to_string(); - let key_str: String = parts[1].to_string(); - let key = base64::decode(&key_str).unwrap(); - - (pw, key) - }) - .collect(); - } - sp.message("Dictionary decrypting file multithreaded".into()); - if let Some(dec_data) = decrypt_with_dictionary(&data, pw_table, &data_checksum) { - sp.stop(); + if let Some(dec_data) = decrypt_with_dictionary_file(dict, &data, &data_checksum) { fs::write(output, &dec_data).expect("Failed to write output file!"); println!("\nFinished!"); } else { - sp.stop(); println!("\nNo password found!"); } } else { @@ -218,3 +199,61 @@ fn create_dictionary(_opts: &Opts, args: &CreateDictionary) { fn spinner(text: &str) -> Spinner { Spinner::new(Spinners::Dots2, text.into()) } + +const LINES_PER_CHUNK: usize = 10000000; + +fn decrypt_with_dictionary_file( + filename: String, + data: &Vec, + data_checksum: &Vec, +) -> Option> { + let sp = spinner("Reading dictionary..."); + let f = File::open(&filename).expect("Failed to open dictionary file."); + let reader = BufReader::new(f); + let mut pb = + ProgressBar::new((get_line_count(&filename) as f64 / LINES_PER_CHUNK as f64).ceil() as u64); + let (rx, tx) = sync_channel::>(10); + let _handle = thread::spawn(move || { + let mut line_vec: Vec = vec![]; + reader.lines().for_each(|line_result| { + if line_vec.len() > LINES_PER_CHUNK { + if let Err(_) = rx.send(line_vec.clone()) {} + line_vec.clear(); + } + match line_result { + Ok(line) => line_vec.push(line), + Err(err) => eprintln!("Failed with err {}", err), + } + }); + if let Err(_) = rx.send(line_vec.clone()) {} + line_vec.clear(); + }); + sp.stop(); + let mut result_data: Option> = None; + for lines in tx { + let pw_table: Vec = lines + .par_iter() + .map(|line| { + let parts: Vec<&str> = line.split("\t").collect::>(); + let pw = parts[0].parse().unwrap(); + let key_str: String = parts[1].parse().unwrap(); + let key = base64::decode(&key_str).unwrap(); + + (pw, key) + }) + .collect(); + pb.inc(); + if let Some(dec_data) = decrypt_with_dictionary(&data, pw_table, &data_checksum) { + result_data = Some(dec_data); + break; + } + } + pb.finish(); + result_data +} + +fn get_line_count(fname: &str) -> usize { + let f = File::open(fname).expect("Failed to open file to get the line count."); + let reader = BufReader::new(f); + return reader.lines().count(); +}