use crate::types::{CrackResult, PasswordCracker};
use anyhow::{Context, Result};
use memmap2::Mmap;
use openssl::pkcs12::Pkcs12;
use rayon::prelude::*;
use std::fs::File;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
pub struct DictionaryCracker {
dictionary_path: PathBuf,
delimiter: String,
}
impl DictionaryCracker {
pub fn new(dictionary_path: PathBuf, delimiter: String) -> Self {
Self {
dictionary_path,
delimiter,
}
}
#[inline(always)]
fn process_chunk(
chunk: &[u8],
delimiter: char,
pkcs12: &Pkcs12,
result: &Arc<Mutex<CrackResult>>,
) -> bool {
if let Ok(text) = std::str::from_utf8(chunk) {
for line in text.split(delimiter) {
{
let result_guard = result.lock().unwrap();
if result_guard.password.is_some() {
return true;
}
result_guard.increment_attempts();
}
let password = line.trim().to_string();
if super::check_password(pkcs12, &password, result) {
return true;
}
}
}
false
}
}
impl PasswordCracker for DictionaryCracker {
fn crack(&self, pkcs12: &Arc<Pkcs12>, result: &Arc<Mutex<CrackResult>>) -> Result<()> {
println!(
"Starting dictionary attack with {} threads",
rayon::current_num_threads()
);
let dict_file =
File::open(&self.dictionary_path).context("Failed to open dictionary file")?;
let mmap = unsafe { Mmap::map(&dict_file)? };
let delimiter = self.delimiter.as_bytes()[0] as char;
mmap.par_chunks(super::CHUNK_SIZE)
.find_any(|chunk| Self::process_chunk(chunk, delimiter, pkcs12, result));
Ok(())
}
}