use crate::types::*;
use crate::crc::{Crc32Computer, crc32_fast, inv_crc32_fast};
use crate::crypto::get_key_manager;
use crate::error::{PkCrackError, Result};
use crate::{msb, CONST, INVCONST};
pub struct Stage2Processor {
crc_computer: Crc32Computer,
solutions: Vec<Stage2Result>,
found_solutions: bool,
}
impl Stage2Processor {
pub fn new() -> Result<Self> {
Ok(Self {
crc_computer: Crc32Computer::new(),
solutions: Vec::new(),
found_solutions: false,
})
}
pub fn execute(&mut self, key2_candidates: &[u32], plaintext: &[u8], ciphertext: &[u8],
offset: usize, abort_on_success: bool) -> Result<Vec<Stage2Result>> {
self.solutions.clear();
self.found_solutions = false;
let text_length = plaintext.len();
println!("Starting Stage 2 with {} key2 candidates", key2_candidates.len());
for (i, &key2_13) in key2_candidates.iter().enumerate() {
if abort_on_success && self.found_solutions {
println!("Aborting Stage 2 after finding solution");
break;
}
if i % 100 == 0 || key2_candidates.len() <= 100 {
println!("Searching... {:.1}%", 100.0 * i as f64 / key2_candidates.len() as f64);
}
if let Some(solution) = self.build_key_sequence(key2_13, plaintext, ciphertext, offset, text_length)? {
self.solutions.push(solution);
self.found_solutions = true;
if abort_on_success {
break;
}
}
}
println!("Stage 2 completed. Found {} solutions", self.solutions.len());
Ok(self.solutions.clone())
}
fn build_key_sequence(&self, key2_13: u32, plaintext: &[u8], ciphertext: &[u8],
offset: usize, text_length: usize) -> Result<Option<Stage2Result>> {
if let Some((key0_7, key1_12, key2_13)) = self.recursion2(key2_13, plaintext, ciphertext, offset, 13, text_length)? {
if self.validate_key_sequence(key0_7, key1_12, key2_13, plaintext, ciphertext, offset, text_length) {
return Ok(Some(Stage2Result {
key0: key0_7,
key1: key1_12,
key2: key2_13,
offset,
}));
}
}
Ok(None)
}
fn recursion2(&self, key2_i: u32, plaintext: &[u8], ciphertext: &[u8],
offset: usize, i: usize, text_length: usize) -> Result<Option<(u32, u32, u32)>> {
if i < offset + 13 {
return self.build_key0_key1(key2_i, plaintext, ciphertext, offset, text_length);
}
let key3_i = plaintext[i] ^ ciphertext[i];
let key2_im1_candidates = self.find_key2_im1_candidates(key2_i, key3_i)?;
for &key2_im1 in &key2_im1_candidates {
if let Some((key0_7, key1_12, key2_13)) = self.recursion2(key2_im1, plaintext, ciphertext, offset, i - 1, text_length)? {
if self.validate_key2_transition(key2_im1, key2_i, key3_i) {
return Ok(Some((key0_7, key1_12, key2_13)));
}
}
}
Ok(None)
}
fn find_key2_im1_candidates(&self, key2_i: u32, key3_i: u8) -> Result<Vec<u32>> {
let mut candidates = Vec::new();
let key2_im1_base = inv_crc32_fast(key2_i, 0);
for temp_lo in 0..=0xFFFFu32 {
let temp = temp_lo | 3;
let calculated_key3 = ((temp as u64 * (temp as u64 ^ 1)) >> 8) & 0xFF;
if calculated_key3 == key3_i as u64 {
let temp_hi = ((temp as u64 * (temp as u64 ^ 1)) >> 32) as u32;
let candidate = (key2_im1_base & 0xFF000000) | (temp_hi << 16) | temp_lo;
if (candidate & 0xFC000000) == (key2_im1_base & 0xFC000000) {
candidates.push(candidate);
}
}
}
candidates.truncate(1000);
Ok(candidates)
}
fn build_key0_key1(&self, key2_13: u32, plaintext: &[u8], ciphertext: &[u8],
offset: usize, text_length: usize) -> Result<Option<(u32, u32, u32)>> {
let key1_12_candidates = self.find_key1_12_candidates(key2_13, plaintext, ciphertext, offset)?;
for &key1_12 in &key1_12_candidates {
if let Some(key0_7) = self.find_key0_7_candidate(key1_12, plaintext, ciphertext, offset)? {
if self.validate_key_sequence(key0_7, key1_12, key2_13, plaintext, ciphertext, offset, text_length) {
return Ok(Some((key0_7, key1_12, key2_13)));
}
}
}
Ok(None)
}
fn find_key1_12_candidates(&self, key2_13: u32, plaintext: &[u8], ciphertext: &[u8],
offset: usize) -> Result<Vec<u32>> {
let mut candidates = Vec::new();
let key3_12 = plaintext[offset + 12] ^ ciphertext[offset + 12];
for key1_12 in 0u32..=0xFFFFFFFFu32 {
let temp = (key2_13 & 0xFFFF) | 3;
let calculated_key3 = ((temp as u64 * (temp as u64 ^ 1)) >> 8) & 0xFF;
if calculated_key3 == key3_12 as u64 {
let key1_msb = msb(key1_12);
let key2_candidate = crc32_fast(key2_13, key1_msb);
if (key2_candidate & 0xFF000000) == (key2_13 & 0xFF000000) {
candidates.push(key1_12);
if candidates.len() >= 100 {
break;
}
}
}
}
Ok(candidates)
}
fn find_key0_7_candidate(&self, key1_12: u32, plaintext: &[u8], ciphertext: &[u8],
offset: usize) -> Result<Option<u32>> {
let key3_7 = plaintext[offset + 7] ^ ciphertext[offset + 7];
let mut temp = key1_12.wrapping_sub(1);
temp = ((temp as u64).wrapping_mul(INVCONST as u64) & 0xFFFFFFFF) as u32;
let key1_7 = temp.wrapping_sub(key1_12 & 0xFF);
for key0_7 in 0u32..=0xFFFFFFFFu32 {
let mut test_key0 = key0_7;
let mut test_key1 = key1_7;
for i in offset + 7..offset + 12 {
test_key1 = (test_key1 + (test_key0 & 0xFF)).wrapping_mul(CONST).wrapping_add(1);
test_key0 = crc32_fast(test_key0, plaintext[i]);
let temp = (test_key1 >> 24) as u8;
let calculated_key3 = plaintext[i] ^ ciphertext[i];
let test_key2_temp = (temp as u32 & 0xFFFF) | 3;
let test_calculated_key3 = ((test_key2_temp as u64 * (test_key2_temp as u64 ^ 1)) >> 8) & 0xFF;
if test_calculated_key3 != calculated_key3 as u64 {
break;
}
}
if test_key1 == key1_12 {
return Ok(Some(key0_7));
}
}
Ok(None)
}
fn validate_key2_transition(&self, key2_i: u32, key2_ip1: u32, key3_i: u8) -> bool {
let temp = (key2_ip1 & 0xFFFF) | 3;
let calculated_key3 = ((temp as u64 * (temp as u64 ^ 1)) >> 8) & 0xFF;
calculated_key3 == key3_i as u64
}
fn validate_key_sequence(&self, key0_7: u32, key1_12: u32, key2_13: u32,
plaintext: &[u8], ciphertext: &[u8], offset: usize, text_length: usize) -> bool {
let key_manager = match get_key_manager() {
Ok(km) => km,
Err(_) => return false,
};
let mut state = match self.reconstruct_full_state(key0_7, key1_12, key2_13, plaintext, offset) {
Ok(s) => s,
Err(_) => return false,
};
key_manager.validate_keys(state, plaintext, ciphertext)
}
fn reconstruct_full_state(&self, key0_7: u32, key1_12: u32, key2_13: u32,
plaintext: &[u8], offset: usize) -> Result<KeyState> {
let mut key0 = key0_7;
let mut key1 = key1_12;
let mut key2 = key2_13;
for i in offset + 13..plaintext.len() {
let key3 = plaintext[i] ^ plaintext[i];
key0 = crc32_fast(key0, plaintext[i]);
key1 = (key1 + (key0 & 0xFF)).wrapping_mul(CONST).wrapping_add(1);
key2 = crc32_fast(key2, msb(key1));
}
Ok(KeyState::new(key0, key1, key2))
}
pub fn get_solutions(&self) -> &[Stage2Result] {
&self.solutions
}
pub fn get_num_solutions(&self) -> usize {
self.solutions.len()
}
pub fn has_solutions(&self) -> bool {
self.found_solutions
}
pub fn reset(&mut self) {
self.solutions.clear();
self.found_solutions = false;
}
}
impl Default for Stage2Processor {
fn default() -> Self {
Self::new().expect("Failed to create Stage2Processor")
}
}
pub fn execute_stage2(key2_candidates: &[u32], plaintext: &[u8], ciphertext: &[u8],
offset: usize, abort_on_success: bool) -> Result<Vec<Stage2Result>> {
let mut processor = Stage2Processor::new()?;
processor.execute(key2_candidates, plaintext, ciphertext, offset, abort_on_success)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_stage2_processor_creation() {
let processor = Stage2Processor::new();
assert!(processor.is_ok());
}
#[test]
fn test_find_key2_im1_candidates() {
let processor = Stage2Processor::new().unwrap();
let key2_i = 0x12345678;
let key3_i = 0xAB;
let result = processor.find_key2_im1_candidates(key2_i, key3_i);
assert!(result.is_ok());
}
#[test]
fn test_validate_key2_transition() {
let processor = Stage2Processor::new().unwrap();
let key2_i = 0x12345678;
let key2_ip1 = 0x87654321;
let key3_i = 0xAB;
let _result = processor.validate_key2_transition(key2_i, key2_ip1, key3_i);
}
#[test]
fn test_execute_stage2_empty_candidates() {
let candidates = vec![];
let plaintext = b"Test plaintext data";
let ciphertext = b"Encrypted test data";
let result = execute_stage2(&candidates, plaintext, ciphertext, 12, false);
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
}
}