use anyhow::Result;
use openssl::pkcs12::Pkcs12;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
pub struct CrackResult {
pub password: Option<String>,
attempts: AtomicUsize,
}
impl CrackResult {
pub fn new() -> Self {
Self {
password: None,
attempts: AtomicUsize::new(0),
}
}
#[inline(always)]
pub fn increment_attempts(&self) {
self.attempts.fetch_add(1, Ordering::Relaxed);
}
pub fn get_attempts(&self) -> usize {
self.attempts.load(Ordering::Relaxed)
}
}
pub trait PasswordCracker {
fn crack(&self, pkcs12: &Arc<Pkcs12>, result: &Arc<Mutex<CrackResult>>) -> Result<()>;
}
#[cfg(test)]
mod tests {
use std::thread;
use super::*;
#[test]
fn test_crack_result() {
let result = CrackResult::new();
result.increment_attempts();
assert_eq!(result.get_attempts(), 1);
}
#[test]
fn test_crack_result_multi_threaded() {
let result = Arc::new(Mutex::new(CrackResult::new()));
let mut handles = vec![];
for _ in 0..100 {
let result = result.clone();
handles.push(thread::spawn(move || {
result.lock().unwrap().increment_attempts();
}));
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(result.lock().unwrap().get_attempts(), 100);
}
}