|
|
|
@ -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<PassKey>;
|
|
|
|
|
{
|
|
|
|
|
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::<Vec<&str>>();
|
|
|
|
|
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<u8>,
|
|
|
|
|
data_checksum: &Vec<u8>,
|
|
|
|
|
) -> Option<Vec<u8>> {
|
|
|
|
|
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::<Vec<String>>(10);
|
|
|
|
|
let _handle = thread::spawn(move || {
|
|
|
|
|
let mut line_vec: Vec<String> = 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<Vec<u8>> = None;
|
|
|
|
|
for lines in tx {
|
|
|
|
|
let pw_table: Vec<PassKey> = lines
|
|
|
|
|
.par_iter()
|
|
|
|
|
.map(|line| {
|
|
|
|
|
let parts: Vec<&str> = line.split("\t").collect::<Vec<&str>>();
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|