Change to validation via HMAC-SHA256 and Remove brute-brute force

master
trivernis 5 years ago
parent 2816a1f138
commit 8cd1330730

33
Cargo.lock generated

@ -53,7 +53,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bdflib"
version = "0.4.1"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -219,6 +219,15 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "des"
version = "0.3.0"
@ -234,10 +243,11 @@ name = "destools"
version = "0.1.0"
dependencies = [
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bdflib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"bdflib 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (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)",
"hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pbr 1.0.2 (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)",
@ -320,6 +330,15 @@ dependencies = [
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "hmac"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -667,6 +686,11 @@ dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.11.11"
@ -827,7 +851,7 @@ dependencies = [
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
"checksum bdflib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e883dd02966e46e8d8ea6c286d04070343139bfdcb15bbec10af8d50a750e1a2"
"checksum bdflib 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3e0c502c6831015e424f0d57e85c50f8010dfec10b3bf29b9a9c930e29d7b0cb"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
@ -847,6 +871,7 @@ dependencies = [
"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
"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 dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
@ -857,6 +882,7 @@ dependencies = [
"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.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
"checksum lzma-sys 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "53e48818fd597d46155132bbbb9505d6d1b3d360b4ee25cfa91c406f8a90fe91"
@ -900,6 +926,7 @@ dependencies = [
"checksum structopt-derive 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c6e79c80e0f4efd86ca960218d4e056249be189ff1c42824dcd9a7f51a56f0bd"
"checksum strum 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca6e4730f517e041e547ffe23d29daab8de6b73af4b6ae2a002108169f5e7da"
"checksum strum_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3384590878eb0cab3b128e844412e2d010821e7e091211b9d87324173ada7db8"
"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"

@ -20,3 +20,4 @@ spinners = "1.2.0"
regex = "1.3.4"
byteorder = "1.3.4"
bdflib = "0.4.0"
hmac = "0.7.1"

@ -1,4 +1,4 @@
use crate::lib::hash::sha_checksum;
use crate::lib::hash::create_hmac;
use cfb_mode::stream_cipher::{NewStreamCipher, StreamCipher};
use cfb_mode::Cfb;
use des::Des;
@ -31,16 +31,14 @@ pub fn decrypt_data(data: &[u8], key: &[u8]) -> Vec<u8> {
}
/// Decrypts data using a dictionary
pub fn decrypt_with_dictionary(
data: &[u8],
dict: Vec<(&String, Vec<u8>)>,
checksum: &[u8],
) -> Option<Vec<u8>> {
pub fn decrypt_with_dictionary(data: &[u8], dict: Vec<(&String, &Vec<u8>)>) -> Option<Vec<u8>> {
let decrypted = Mutex::<Option<Vec<u8>>>::new(None);
let hmac = &data[data.len() - 32..];
let encrypted_data = &data[..data.len() - 32];
let pass = dict.par_iter().find_first(|(_pw, key)| {
let decrypted_data = decrypt_data(&data, key);
let decr_check = sha_checksum(&decrypted_data);
return if decr_check == checksum {
let decrypted_data = decrypt_data(encrypted_data, &key[0..8]);
let decr_hmac = create_hmac(&key, &decrypted_data).expect("failed to create hmac");
return if decr_hmac == hmac {
let mut decry = decrypted.lock().unwrap();
*decry = Some(decrypted_data);
true
@ -57,23 +55,3 @@ pub fn decrypt_with_dictionary(
}
None
}
/// Decrypts data by generating all possible keys
pub fn decrypt_brute_brute_force(data: &[u8], checksum: &[u8]) -> Option<Vec<u8>> {
let encryption_key = (0u64..std::u64::MAX)
.into_par_iter()
.find_first(|num: &u64| {
let key: &[u8] = &num.to_le_bytes();
let decrypted_data = decrypt_data(&data, key);
let decr_check = sha_checksum(&decrypted_data);
decr_check == checksum
});
if let Some(num) = encryption_key {
let key: &[u8] = &num.to_le_bytes();
println!("Key found: {:?}", key);
return Some(decrypt_data(data, key));
}
None
}

@ -1,6 +1,9 @@
use sha2::{Digest, Sha256, Sha512};
use hmac::crypto_mac::InvalidKeyLength;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
pub type PassKey = (String, Vec<u8>);
type HmacSha256 = Hmac<Sha256>;
/// Hashes a text to a 32 bytes long key.
pub fn create_key(pw: &str) -> Vec<u8> {
@ -21,15 +24,6 @@ pub fn sha256(pw: &str) -> Vec<u8> {
result.to_vec()
}
/// Hashes a text to sha512
pub fn sha512(pw: &str) -> Vec<u8> {
let mut hasher = Sha512::default();
hasher.input(pw);
let result = hasher.result();
result.to_vec()
}
/// Creates a sha256 hashsum from the input data
pub fn sha_checksum(data: &Vec<u8>) -> Vec<u8> {
let mut hasher = Sha256::default();
@ -38,3 +32,11 @@ pub fn sha_checksum(data: &Vec<u8>) -> Vec<u8> {
result.to_vec()
}
/// Creates a hmac hash to be appended after the encrypted message
pub fn create_hmac(key: &Vec<u8>, data: &Vec<u8>) -> Result<Vec<u8>, InvalidKeyLength> {
let mut mac = HmacSha256::new_varkey(key)?;
mac.input(data);
Ok(mac.result().code().to_vec())
}

@ -1,9 +1,7 @@
pub mod lib;
use crate::lib::crypt::{
decrypt_brute_brute_force, decrypt_data, decrypt_with_dictionary, encrypt_data,
};
use crate::lib::hash::{create_key, sha256, sha_checksum};
use crate::lib::crypt::{decrypt_with_dictionary, encrypt_data};
use crate::lib::hash::{create_hmac, sha256};
use crate::lib::timing::TimeTaker;
use bdf::chunks::{DataEntry, HashEntry, HashLookupTable};
use bdf::io::{BDFReader, BDFWriter};
@ -53,10 +51,6 @@ struct Encrypt {
/// The output file
#[structopt(short = "o", long = "output", default_value = "output.des")]
output: String,
/// The file for the checksum.
#[structopt(long = "checksum-file")]
output_checksum: Option<String>,
}
#[derive(StructOpt, Clone)]
@ -69,10 +63,6 @@ struct Decrypt {
#[structopt(short = "o", long = "output", default_value = "output.txt")]
output: String,
/// The file for the checksum.
#[structopt(long = "checksum-file")]
input_checksum: Option<String>,
/// A dictionary file containing a list of passwords
/// The file needs to be in a csv format with calculated password hashes.
/// The hashes can be calculated with the create-dictionary subcommand from a txt file.
@ -115,15 +105,12 @@ fn encrypt(_opts: &Opts, args: &Encrypt) {
let output: String = (*args.output).parse().unwrap();
let data: Vec<u8> = fs::read(input).expect("Failed to read input file!");
if let Some(output_checksum) = (args.clone()).output_checksum {
let checksum = sha_checksum(&data);
let checksum_b64 = base64::encode(checksum.as_slice());
fs::write(output_checksum, checksum_b64.as_bytes())
.expect("Failed to write checksum file!");
}
let pass = read_password_from_tty(Some("Password: ")).unwrap();
let key = create_key(&pass);
let enc_data = encrypt_data(data.as_slice(), key.as_slice());
let sha256_key = sha256(&pass);
let key = &sha256_key[0..8];
let mut data_hmac = create_hmac(&sha256_key, &data).expect("failed to create hmac");
let mut enc_data = encrypt_data(data.as_slice(), &key);
enc_data.append(&mut data_hmac);
fs::write(output, enc_data.as_slice()).expect("Failed to write output file!");
}
@ -137,39 +124,21 @@ fn decrypt(_opts: &Opts, args: &Decrypt) {
let dictionary = args.dictionary.clone();
let data = fs::read(input).expect("Failed to read input file!");
if let Some(input_checksum) = (args.clone()).input_checksum {
let bin_content = fs::read(input_checksum).expect("Failed to read checksum file!");
let data_checksum = base64::decode(bin_content.as_slice()).unwrap();
if let Some(dict) = dictionary {
tt.take("decryption-start");
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!(
"Decryption took {:.2}s",
tt.since("decryption-start").unwrap().as_secs_f32()
);
println!("Finished {:.2}s!", tt.since("start").unwrap().as_secs_f32());
} else {
println!("\nNo password found!");
println!("Finished {:.2}s!", tt.since("start").unwrap().as_secs_f32());
}
if let Some(dict) = dictionary {
tt.take("decryption-start");
if let Some(dec_data) = decrypt_with_dictionary_file(dict, &data) {
fs::write(output, &dec_data).expect("Failed to write output file!");
println!(
"Decryption took {:.2}s",
tt.since("decryption-start").unwrap().as_secs_f32()
);
println!("Finished {:.2}s!", tt.since("start").unwrap().as_secs_f32());
} else {
let sp = spinner("Brute force decrypting file");
if let Some(dec_data) = decrypt_brute_brute_force(&data, &data_checksum) {
sp.stop();
fs::write(output, &dec_data).expect("Failed to write output file!");
println!("Finished {:.2}s!", tt.since("start").unwrap().as_secs_f32());
} else {
sp.stop();
println!("\nNo fitting key found. (This should have been impossible)")
}
println!("\nNo password found!");
println!("Finished {:.2}s!", tt.since("start").unwrap().as_secs_f32());
}
} else {
let pass = read_password_from_tty(Some("Password: ")).unwrap();
let key = create_key(&pass);
let result = decrypt_data(&data, key.as_slice());
fs::write(output, &result).expect("Failed to write output file!");
println!("No checksum file given!");
}
}
@ -249,11 +218,7 @@ fn spinner(text: &str) -> Spinner {
/// Decrypts the file using a bdf dictionary
/// The files content is read chunk by chunk to reduce the memory impact since dictionary
/// files tend to be several gigabytes in size
fn decrypt_with_dictionary_file(
filename: String,
data: &Vec<u8>,
data_checksum: &Vec<u8>,
) -> Option<Vec<u8>> {
fn decrypt_with_dictionary_file(filename: String, data: &Vec<u8>) -> Option<Vec<u8>> {
let sp = spinner("Reading dictionary...");
let f = File::open(&filename).expect("Failed to open dictionary file.");
let mut bdf_file = BDFReader::new(f);
@ -280,17 +245,17 @@ fn decrypt_with_dictionary_file(
sp.stop();
let mut result_data: Option<Vec<u8>> = None;
for entries in tx {
let pw_table: Vec<(&String, Vec<u8>)> = entries
let pw_table: Vec<(&String, &Vec<u8>)> = entries
.par_iter()
.map(|entry: &DataEntry| {
let pw = &entry.plain;
let key: &Vec<u8> = entry.get_hash_value(SHA256.to_string()).unwrap();
(pw, key[0..8].to_vec())
(pw, key)
})
.collect();
pb.inc();
if let Some(dec_data) = decrypt_with_dictionary(&data, pw_table, &data_checksum) {
if let Some(dec_data) = decrypt_with_dictionary(&data, pw_table) {
result_data = Some(dec_data);
break;
}

Loading…
Cancel
Save