Fix multithreading and update README

master
Trivernis 5 years ago
parent 5ca4be142d
commit e9cac5a16a

5
.gitignore vendored

@ -6,5 +6,6 @@ data.des
data.sha256
dataenc.txt
pass.txt
dictionary.csv
.idea
testdata/dictionary.csv
.idea
testdata

41
Cargo.lock generated

@ -195,9 +195,11 @@ dependencies = [
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfb-mode 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"may 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"sha 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -212,6 +214,11 @@ dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "either"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fake-simd"
version = "0.1.2"
@ -263,6 +270,14 @@ dependencies = [
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itertools"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -434,6 +449,28 @@ dependencies = [
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon-core"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.56"
@ -661,12 +698,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
"checksum des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74ba5f1b5aee9772379c2670ba81306e65a93c0ee3caade7a1d22b188d88a3af"
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
"checksum generator 0.6.20 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa160efb38ce00acbe4450d41a103fb3d2acdb17ff09a7cf38f3ac26af0738"
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
"checksum hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c55f143919fbc0bc77e427fe2d74cf23786d7c1875666f2fde3ac3c659bb67"
"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
@ -686,6 +725,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
"checksum rpassword 4.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "99371657d3c8e4d816fb6221db98fa408242b0b53bac08f8676a41f8554fe99f"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"

@ -16,4 +16,6 @@ sha2 = "0.8.1"
rpassword = "4.0.5"
base64 = "0.11.0"
num_cpus = "1.12.0"
may = "0.3.17"
may = "0.3.17"
rayon = "1.3.0"
itertools = "0.8.2"

@ -17,4 +17,20 @@ SUBCOMMANDS:
decrypt Decrypt a DES encoded file
encrypt Encrypt a file with des
help Prints this message or the help of the given subcommand(s)
```
## Example
```shell script
# Encrypt test.txt to test.des
destools encrypt -i test.txt -o test.des --checksum-file test.sha256
# Create a rainbow table from passwords.txt
destools create-dictionary -i passwords.txt -o dictionary.csv
# Decrypt test.des
destools decrypt -i test.des -o decrypted.txt
# Try to brute force dercrypt test.des
destools decrypt -i test.des -o decrypted.txt -d dictionary.csv --checksum-file test.sha256
```

@ -1,4 +1,5 @@
use sha2::{Sha256, Digest};
use rayon::prelude::*;
pub type PassKey = (String, Vec<u8>);
@ -12,13 +13,11 @@ pub fn create_key(pw: String) -> Vec<u8> {
}
/// Maps a list of passwords to keys and returns a vector of pairs
pub fn map_to_keys(passwords: Vec<String>) -> Vec<PassKey> {
let mut result: Vec<PassKey> = vec![];
for pw in passwords.iter() {
let pw_str = pw.clone();
result.push((pw_str.clone(), create_key(pw_str)));
}
return result;
pub fn map_to_keys(passwords: Vec<&String>) -> Vec<PassKey> {
return passwords.par_iter().map(|pw| {
let pw_str = (*pw).clone();
(pw_str.clone(), create_key(pw_str))
}).collect();
}
/// Creates a sha256 hashsum from the input data

@ -7,11 +7,13 @@ use std::thread::JoinHandle;
type ChannelControls<T> = (Sender<ThreadControlMessage<T>>, Receiver<ThreadControlMessage<T>>);
type DecryptData = (Option<Vec<u8>>, Option<PassKey>);
#[derive(Debug)]
pub struct ThreadControlMessage<T> {
message_type: MessageType,
data: Option<T>,
}
#[derive(Debug)]
pub enum MessageType {
Data,
Stop,
@ -56,12 +58,17 @@ pub fn cpu_count() -> u8 {
/// Decrypts data multithreaded
pub fn decrypt_data_threaded(data: Vec<u8>, pw_table: &Vec<PassKey>, data_checksum: Vec<u8>) -> Option<Vec<u8>> {
let chan = create_channel::<DecryptData>();
let (rx, tx) = chan;
let (rx, tx1) = chan;
let chan2 = create_channel::<DecryptData>();
let (rx2, tx) = chan2;
let mut entry_index = 0;
let mut threads: Vec<JoinHandle<()>> = vec![];
for _ in 0u8..cpu_count() {
let rx1 = rx.clone();
let tx1 = tx.clone();
let num_threads = cpu_count();
println!("Creating {} threads...", num_threads);
for i in 0u8..num_threads {
print!("Starting Thread {}\r", i);
let rx1 = rx2.clone();
let tx1 = tx1.clone();
let data_checksum = data_checksum.clone();
let data = data.clone();
let child = thread::spawn(move || {
@ -73,8 +80,11 @@ pub fn decrypt_data_threaded(data: Vec<u8>, pw_table: &Vec<PassKey>, data_checks
entry_index += 1;
}
}
println!("Starting main loop...");
loop {
print!("{} out of {} Passwords tested\r", entry_index, pw_table.len());
if entry_index % 100 == 0 {
print!("{} out of {} Passwords tested\r", entry_index, pw_table.len());
}
let message = tx.recv().unwrap();
if let Ok(next_entry) = next_password(pw_table, entry_index) {
let msg_data: DecryptData = (None, Some(next_entry));
@ -83,9 +93,18 @@ pub fn decrypt_data_threaded(data: Vec<u8>, pw_table: &Vec<PassKey>, data_checks
rx.send(ThreadControlMessage::<DecryptData>::new_data(msg_data)).unwrap();
},
MessageType::Data => {
if let Some((result_data, _)) = message.data {
rx.send(ThreadControlMessage::new_stop()).unwrap();
return result_data;
if let Some((result_data, pass_key)) = message.data {
if let Some(decrypted_data) = result_data {
rx.send(ThreadControlMessage::new_stop()).unwrap();
println!();
println!("Received data.");
if let Some((pw, _key)) = pass_key {
println!("Password is: {}", pw);
}
return Some(decrypted_data);
} else {
rx.send(ThreadControlMessage::<DecryptData>::new_data(msg_data)).unwrap();
}
} else {
rx.send(ThreadControlMessage::<DecryptData>::new_data(msg_data)).unwrap();
}
@ -95,6 +114,8 @@ pub fn decrypt_data_threaded(data: Vec<u8>, pw_table: &Vec<PassKey>, data_checks
entry_index += 1;
} else {
rx.send(ThreadControlMessage::new_stop()).unwrap();
println!();
println!("No remaining passwords!");
return None;
}
}
@ -113,26 +134,32 @@ fn next_password(pw_table: &Vec<PassKey>, index: usize) -> Result<PassKey, &str>
fn decrypt_data_coro(controls: &ChannelControls<DecryptData>, data: Vec<u8>, check: Vec<u8>) {
loop {
let (tx, rx) = controls;
let message = rx.recv().unwrap();
match message.message_type {
MessageType::Data => {
if let Some((_, pass_key)) = message.data {
if let Some((pw, key)) = pass_key {
let decrypted_data = decrypt_data(&data, key.as_slice());
let decr_check = sha_checksum(&data);
if decr_check == check {
println!("Password is: {}", pw);
tx.send(ThreadControlMessage::new_data((Some(decrypted_data), None))).unwrap();
} else {
tx.send(ThreadControlMessage::new_request()).unwrap();
if let Ok(message) = rx.recv() {
match message.message_type {
MessageType::Data => {
if let Some((_, pass_key)) = message.data {
if let Some((_pw, key)) = pass_key.clone() {
let decrypted_data = decrypt_data(&data, key.as_slice());
let decr_check = sha_checksum(&decrypted_data);
if decr_check == check {
tx.send(ThreadControlMessage::new_data((Some(decrypted_data), pass_key))).unwrap();
} else {
if let Err(_e) = tx.send(ThreadControlMessage::new_request()) {
break;
}
}
}
}
},
MessageType::Stop => {
break;
},
_ => {
tx.send(ThreadControlMessage::new_request()).unwrap();
}
},
MessageType::Stop => {
break;
},
_ => {}
}
} else {
break;
}
}
}

@ -7,6 +7,8 @@ use rpassword;
use rpassword::{read_password_from_tty};
use crate::lib::hash::{create_key, map_to_keys, PassKey, sha_checksum};
use crate::lib::threading::{decrypt_data_threaded};
use rayon::prelude::*;
use itertools::Itertools;
#[derive(StructOpt, Clone)]
#[structopt(name = "destools", version = "1.0", author = "Julius R.")]
@ -38,7 +40,7 @@ struct Encrypt {
input: String,
/// The output file
#[structopt(short = "o", long = "output", default_value = "output.txt")]
#[structopt(short = "o", long = "output", default_value = "output.des")]
output: String,
/// The file for the checksum.
@ -49,7 +51,7 @@ struct Encrypt {
#[derive(StructOpt, Clone)]
struct Decrypt {
/// The input file
#[structopt(short = "i", long = "input", default_value = "input.txt")]
#[structopt(short = "i", long = "input", default_value = "input.des")]
input: String,
/// The output file
@ -122,7 +124,7 @@ fn decrypt(_opts: &Opts, args: &Decrypt) {
for (i, line) in lines.enumerate() {
print!("Parsing Dictionary: {} lines\r", i);
let parts: Vec<&str> = line.split(",").collect::<Vec<&str>>();
let pw = parts.first().unwrap().parse().unwrap();
let pw = parts[0].parse().unwrap();
let key_str: String = parts[1].parse().unwrap();
let key = base64::decode(&key_str).unwrap();
pw_table.push((pw, key));
@ -131,17 +133,6 @@ fn decrypt(_opts: &Opts, args: &Decrypt) {
if let Some(decrypted_data) = decrypt_data_threaded(data.clone(), &pw_table, data_checksum) {
write_file(output, &decrypted_data);
}
/*
for (i, (pw, key)) in pw_table.iter().enumerate() {
let result = decrypt_data(&data, key);
let result_checksum = sha_checksum(&result);
print!("{} out of {} Passwords tested\r", i+1, pw_table.len());
if result_checksum == data_checksum {
println!();
println!("Password found: {}", pw);
break;
}
}*/
}
} else {
let pass = read_password_from_tty(Some("Password: ")).unwrap();
@ -156,21 +147,26 @@ fn create_dictionary(_opts: &Opts, args: &CreateDictionary) {
let input = (*args.input).parse().unwrap();
let contents = read_file(input);
let lines = contents.lines().collect::<Vec<&str>>();
let passwords = lines.iter().map(| s | -> String {
println!("Parsing {} passwords...", lines.len());
let pws: Vec<String> = lines.par_iter().map(| s | -> String {
s.parse().unwrap()
}).collect();
println!("Removing duplicates...");
let passwords = pws.iter().unique().collect_vec();
println!("Mapping passwords to keys...");
let dictionary = map_to_keys(passwords);
println!("Writing passwords to file...");
let mut fout = File::create(args.output.clone()).unwrap();
for entry in dictionary.iter() {
let key = base64::encode((*entry).1.as_slice());
let line = format!("{},{}\n", (*entry).0, key);
fout.write(&line.into_bytes()).unwrap();
}
println!("Finished!");
}
/// Reads a file to the end and returns the content as byte array
fn read_file_binary(filename: String) -> Vec<u8> {
println!("{}", filename);
let mut fin = File::open(filename).unwrap();
let mut data: Vec<u8> = vec![];
fin.read_to_end(&mut data).unwrap();
@ -179,7 +175,6 @@ fn read_file_binary(filename: String) -> Vec<u8> {
/// Reads a file to the end and returns the contents as a string
fn read_file(filename: String) -> String {
println!("{}", filename);
let mut fin = File::open(filename).unwrap();
let mut contents= String::new();
fin.read_to_string(&mut contents).unwrap();
@ -188,7 +183,6 @@ fn read_file(filename: String) -> String {
/// writes binary data to a file
fn write_file(filename: String, data: &[u8]) {
println!("{}", filename);
let mut fout = File::create(filename).unwrap();
fout.write(data).unwrap();
}
Loading…
Cancel
Save