optimize attack
This commit is contained in:
+81
-108
@@ -245,78 +245,51 @@ const TAC: [u64; 24] = [
|
|||||||
0xb38000003c800000,
|
0xb38000003c800000,
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Binary search in a sorted slice of Tab by `output` field
|
/// Full meet-in-the-middle attack (7‑bit u, 10‑bit w)
|
||||||
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
|
|
||||||
fn attack(z: u64) -> u64 {
|
fn attack(z: u64) -> u64 {
|
||||||
const LOG_SIZE_TAC: u32 = 24;
|
const LOG_U: u32 = 7; // size of u space (bits)
|
||||||
const LOG_SIZE_KERB: u32 = 32;
|
const LOG_W: u32 = 10; // size of w space (bits)
|
||||||
let size_l = 1usize << LOG_SIZE_TAC;
|
let l_size = 1 << LOG_U;
|
||||||
|
let truev: u64 = 0; // v = 0
|
||||||
|
|
||||||
// Build table L (u -> stream( S = u XOR truev ) )
|
// --- Build table L (enumerate u) ---
|
||||||
let mut a0 = Lfsr { state: 0, mask: 0 };
|
let mut l: Vec<Tab> = Vec::with_capacity(l_size);
|
||||||
let mut b0 = Lfsr { state: 0, mask: 0 };
|
let mut current_gray: u64 = 0;
|
||||||
let mut c0 = Lfsr { state: 0, mask: 0 };
|
let mut s = truev;
|
||||||
init(0, &mut a0, &mut b0, &mut c0);
|
|
||||||
let stream0 = stream(&mut a0, &mut b0, &mut c0);
|
|
||||||
println!("[*] stream(S=0) = 0x{:016X}", stream0);
|
|
||||||
|
|
||||||
let mut l: Vec<Tab> = 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;
|
// Remaining 2^LOG_U - 1 entries using Gray code + TAC
|
||||||
|
for i in 1u64..l_size as u64 {
|
||||||
println!("[*] building L ({} entries)...", size_l);
|
let new_gray = i ^ (i >> 1);
|
||||||
|
let d = current_gray ^ new_gray;
|
||||||
let mut current_u = 0u64;
|
let pos = d.trailing_zeros() as usize;
|
||||||
// First entry i=0
|
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);
|
|
||||||
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];
|
|
||||||
|
|
||||||
let (mut a, mut b, mut c) = (
|
let (mut a, mut b, mut c) = (
|
||||||
Lfsr { state: 0, mask: 0 },
|
Lfsr { state: 0, mask: 0 },
|
||||||
Lfsr { state: 0, mask: 0 },
|
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 {
|
l.push(Tab {
|
||||||
output: stream(&mut a, &mut b, &mut c),
|
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| {
|
l.sort_by(|a, b| {
|
||||||
let cmp = a.output.cmp(&b.output);
|
let cmp = a.output.cmp(&b.output);
|
||||||
if cmp != Ordering::Equal {
|
if cmp != Ordering::Equal {
|
||||||
@@ -325,60 +298,71 @@ fn attack(z: u64) -> u64 {
|
|||||||
a.input.cmp(&b.input)
|
a.input.cmp(&b.input)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
println!("[*] Sort finished.");
|
|
||||||
|
|
||||||
println!("[*] Search in KerB");
|
// --- Search over w ---
|
||||||
let mut current_w = 0u64;
|
current_gray = 0;
|
||||||
let mut result = 0u64;
|
s = truev;
|
||||||
let mut found = false;
|
|
||||||
|
|
||||||
// First iteration w=0
|
// Base case w = 0
|
||||||
{
|
let (mut a, mut b, mut c) = (
|
||||||
let (mut a, mut b, mut c) = (
|
Lfsr { state: 0, mask: 0 },
|
||||||
Lfsr { state: 0, mask: 0 },
|
Lfsr { state: 0, mask: 0 },
|
||||||
Lfsr { state: 0, mask: 0 },
|
Lfsr { state: 0, mask: 0 },
|
||||||
Lfsr { state: 0, mask: 0 },
|
);
|
||||||
);
|
init(s, &mut a, &mut b, &mut c);
|
||||||
init(current_w ^ truev, &mut a, &mut b, &mut c);
|
let sw = stream(&mut a, &mut b, &mut c);
|
||||||
let sw = stream(&mut a, &mut b, &mut c);
|
let target = z ^ sw;
|
||||||
let target = z ^ sw ^ stream0;
|
|
||||||
if let Some(hit) = binary_search_tab(&l, target) {
|
if let Ok(idx) = l.binary_search_by(|entry| {
|
||||||
result = hit.input ^ current_w ^ truev;
|
if entry.output < target {
|
||||||
found = true;
|
Ordering::Less
|
||||||
println!("[!] Correlation found ! w=0, u=0x{:016X}", hit.input);
|
} 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) {
|
// Iterate over the remaining 1023 values of w
|
||||||
if found {
|
let mut i = 1u64;
|
||||||
break;
|
while i >> LOG_W == 0 {
|
||||||
}
|
let new_gray = i ^ (i >> 1);
|
||||||
current_w ^= KER_B[i.trailing_zeros() as usize];
|
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) = (
|
let (mut a, mut b, mut c) = (
|
||||||
Lfsr { state: 0, mask: 0 },
|
Lfsr { state: 0, mask: 0 },
|
||||||
Lfsr { state: 0, mask: 0 },
|
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 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) {
|
if let Ok(idx) = l.binary_search_by(|entry| {
|
||||||
result = hit.input ^ current_w ^ truev;
|
if entry.output < target {
|
||||||
found = true;
|
Ordering::Less
|
||||||
println!("[!] Correlation found at i={}", i);
|
} else if entry.output > target {
|
||||||
println!(" w = 0x{:016X}", current_w);
|
Ordering::Greater
|
||||||
println!(" u = 0x{:016X}", hit.input);
|
} else {
|
||||||
|
Ordering::Equal
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
let hit = &l[idx];
|
||||||
|
return s ^ hit.input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
// Not found
|
||||||
println!("[-] Secret not found.");
|
0
|
||||||
0
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------- MAIN --------------------------
|
//-------------------------- MAIN --------------------------
|
||||||
@@ -398,7 +382,7 @@ fn main() {
|
|||||||
println!("0x{:08X}", z);
|
println!("0x{:08X}", z);
|
||||||
|
|
||||||
println!("key S = 0x{:016X}\n", s);
|
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 plain: [u8; 8] = [b'H', b'E', b'L', b'L', b'O', b' ', b'W', b'O'];
|
||||||
let message = pack8(&plain);
|
let message = pack8(&plain);
|
||||||
@@ -415,7 +399,7 @@ fn main() {
|
|||||||
std::str::from_utf8(&recovered_text[..8]).unwrap()
|
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!("=== Meet-in-the-Middle attack===");
|
||||||
println!("Target cipher stream : 0x{:016X}\n", z_challenge);
|
println!("Target cipher stream : 0x{:016X}\n", z_challenge);
|
||||||
|
|
||||||
@@ -425,15 +409,4 @@ fn main() {
|
|||||||
|
|
||||||
println!("\nSecret found : S = 0x{:016X}", secret);
|
println!("\nSecret found : S = 0x{:016X}", secret);
|
||||||
println!(" Time : {:.2} s\n", elapsed);
|
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" }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user