From ff3a28db10dd851102a8f272c1f67adb2c841f10 Mon Sep 17 00:00:00 2001 From: Sam Hadow Date: Thu, 23 Apr 2026 15:59:20 +0200 Subject: [PATCH] optimize attack --- src/main.rs | 189 ++++++++++++++++++++++------------------------------ 1 file changed, 81 insertions(+), 108 deletions(-) diff --git a/src/main.rs b/src/main.rs index f93836f..51619fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -245,78 +245,51 @@ const TAC: [u64; 24] = [ 0xb38000003c800000, ]; -/// Binary search in a sorted slice of Tab by `output` field -fn binary_search_tab(table: &[Tab], target: u64) -> Option<&Tab> { - table - .binary_search_by(|entry| { - if entry.output < target { - Ordering::Less - } else if entry.output > target { - Ordering::Greater - } else { - Ordering::Equal - } - }) - .ok() - .map(|idx| &table[idx]) -} - -/// Full meet-in-the-middle attack +/// Full meet-in-the-middle attack (7‑bit u, 10‑bit w) fn attack(z: u64) -> u64 { - const LOG_SIZE_TAC: u32 = 24; - const LOG_SIZE_KERB: u32 = 32; - let size_l = 1usize << LOG_SIZE_TAC; + const LOG_U: u32 = 7; // size of u space (bits) + const LOG_W: u32 = 10; // size of w space (bits) + let l_size = 1 << LOG_U; + let truev: u64 = 0; // v = 0 - // Build table L (u -> stream( S = u XOR truev ) ) - let mut a0 = Lfsr { state: 0, mask: 0 }; - let mut b0 = Lfsr { state: 0, mask: 0 }; - let mut c0 = Lfsr { state: 0, mask: 0 }; - init(0, &mut a0, &mut b0, &mut c0); - let stream0 = stream(&mut a0, &mut b0, &mut c0); - println!("[*] stream(S=0) = 0x{:016X}", stream0); + // --- Build table L (enumerate u) --- + let mut l: Vec = Vec::with_capacity(l_size); + let mut current_gray: u64 = 0; + let mut s = truev; - let mut l: Vec = Vec::with_capacity(size_l); + // First entry u = 0 + let (mut a, mut b, mut c) = ( + Lfsr { state: 0, mask: 0 }, + Lfsr { state: 0, mask: 0 }, + Lfsr { state: 0, mask: 0 }, + ); + init(s, &mut a, &mut b, &mut c); + l.push(Tab { + output: stream(&mut a, &mut b, &mut c), + input: 0, + }); - let truev: u64 = 0; - - println!("[*] building L ({} entries)...", size_l); - - let mut current_u = 0u64; - // First entry i=0 - { - let (mut a, mut b, mut c) = ( - Lfsr { state: 0, mask: 0 }, - Lfsr { state: 0, mask: 0 }, - Lfsr { state: 0, mask: 0 }, - ); - init(current_u ^ truev, &mut a, &mut b, &mut c); - l.push(Tab { - output: stream(&mut a, &mut b, &mut c), - input: current_u, - }); - } - - for i in 1u64..size_l as u64 { - // Jump to next u using Gray-code XOR - current_u ^= TAC[i.trailing_zeros() as usize]; + // Remaining 2^LOG_U - 1 entries using Gray code + TAC + for i in 1u64..l_size as u64 { + let new_gray = i ^ (i >> 1); + let d = current_gray ^ new_gray; + let pos = d.trailing_zeros() as usize; + s ^= TAC[pos]; // update S = truev ^ u + current_gray = new_gray; let (mut a, mut b, mut c) = ( Lfsr { state: 0, mask: 0 }, Lfsr { state: 0, mask: 0 }, Lfsr { state: 0, mask: 0 }, ); - init(current_u ^ truev, &mut a, &mut b, &mut c); + init(s, &mut a, &mut b, &mut c); l.push(Tab { output: stream(&mut a, &mut b, &mut c), - input: current_u, + input: s, // store the full S }); - - if i & 0xFFFFF == 0 { - println!(" {} / {}", i, size_l); - } } - println!("[*] Sorting L"); + // Sort L by output for binary search l.sort_by(|a, b| { let cmp = a.output.cmp(&b.output); if cmp != Ordering::Equal { @@ -325,60 +298,71 @@ fn attack(z: u64) -> u64 { a.input.cmp(&b.input) } }); - println!("[*] Sort finished."); - println!("[*] Search in KerB"); - let mut current_w = 0u64; - let mut result = 0u64; - let mut found = false; + // --- Search over w --- + current_gray = 0; + s = truev; - // First iteration w=0 - { - let (mut a, mut b, mut c) = ( - Lfsr { state: 0, mask: 0 }, - Lfsr { state: 0, mask: 0 }, - Lfsr { state: 0, mask: 0 }, - ); - init(current_w ^ truev, &mut a, &mut b, &mut c); - let sw = stream(&mut a, &mut b, &mut c); - let target = z ^ sw ^ stream0; - if let Some(hit) = binary_search_tab(&l, target) { - result = hit.input ^ current_w ^ truev; - found = true; - println!("[!] Correlation found ! w=0, u=0x{:016X}", hit.input); + // Base case w = 0 + let (mut a, mut b, mut c) = ( + Lfsr { state: 0, mask: 0 }, + Lfsr { state: 0, mask: 0 }, + Lfsr { state: 0, mask: 0 }, + ); + init(s, &mut a, &mut b, &mut c); + let sw = stream(&mut a, &mut b, &mut c); + let target = z ^ sw; + + if let Ok(idx) = l.binary_search_by(|entry| { + if entry.output < target { + Ordering::Less + } else if entry.output > target { + Ordering::Greater + } else { + Ordering::Equal } + }) { + let hit = &l[idx]; + // Secret = truev ^ w ^ stored_input + return s ^ hit.input; } - for i in 1u64..(1u64 << LOG_SIZE_KERB) { - if found { - break; - } - current_w ^= KER_B[i.trailing_zeros() as usize]; + // Iterate over the remaining 1023 values of w + let mut i = 1u64; + while i >> LOG_W == 0 { + let new_gray = i ^ (i >> 1); + let d = current_gray ^ new_gray; + let pos = d.trailing_zeros() as usize; + s ^= KER_B[pos]; // update S = truev ^ w + current_gray = new_gray; let (mut a, mut b, mut c) = ( Lfsr { state: 0, mask: 0 }, Lfsr { state: 0, mask: 0 }, Lfsr { state: 0, mask: 0 }, ); - init(current_w ^ truev, &mut a, &mut b, &mut c); + init(s, &mut a, &mut b, &mut c); let sw = stream(&mut a, &mut b, &mut c); - let target = z ^ sw ^ stream0; + let target = z ^ sw; - if let Some(hit) = binary_search_tab(&l, target) { - result = hit.input ^ current_w ^ truev; - found = true; - println!("[!] Correlation found at i={}", i); - println!(" w = 0x{:016X}", current_w); - println!(" u = 0x{:016X}", hit.input); + if let Ok(idx) = l.binary_search_by(|entry| { + if entry.output < target { + Ordering::Less + } else if entry.output > target { + Ordering::Greater + } else { + Ordering::Equal + } + }) { + let hit = &l[idx]; + return s ^ hit.input; } + + i += 1; } - if !found { - println!("[-] Secret not found."); - 0 - } else { - result - } + // Not found + 0 } //-------------------------- MAIN -------------------------- @@ -398,7 +382,7 @@ fn main() { println!("0x{:08X}", z); println!("key S = 0x{:016X}\n", s); - print_representation(); + // print_representation(); let plain: [u8; 8] = [b'H', b'E', b'L', b'L', b'O', b' ', b'W', b'O']; let message = pack8(&plain); @@ -415,7 +399,7 @@ fn main() { std::str::from_utf8(&recovered_text[..8]).unwrap() ); - let z_challenge: u64 = 0x2D0E339CFD588D1B; + let z_challenge: u64 = 0x9AC76518F2322DA4; println!("=== Meet-in-the-Middle attack==="); println!("Target cipher stream : 0x{:016X}\n", z_challenge); @@ -425,15 +409,4 @@ fn main() { println!("\nSecret found : S = 0x{:016X}", secret); println!(" Time : {:.2} s\n", elapsed); - - // Verification - init(secret, &mut a, &mut b, &mut c); - let z_check = stream(&mut a, &mut b, &mut c); - println!("=== Check ==="); - println!("stream(S_found) = 0x{:016X}", z_check); - println!("z_challenge = 0x{:016X}", z_challenge); - println!( - "Correlation : {}", - if z_check == z_challenge { "YES" } else { "NO" } - ); }