Created
January 15, 2016 07:03
-
-
Save luqmana/786124e57999e8d40780 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This code can be compiled in 3 modes: | |
// rustc --cfg find | |
// rustc --cfg interactive | |
// rustc --cfg oracle | |
// | |
// The interactive mode is based on the | |
// crib dragging technique described by | |
// Dan Crowley at: | |
// https://www.trustwave.com/Resources/SpiderLabs-Blog/The-Way-of-the-Cryptologist/ | |
fn code(msg: &str, key: &str, encode: bool) -> String { | |
use std::ascii::AsciiExt; | |
assert!(msg.is_ascii()); | |
assert!(key.is_ascii()); | |
let len = std::cmp::min(msg.len(), key.len()); | |
let mut result = String::with_capacity(len); | |
// Convery lowercase -> uppercase and everything else to space | |
// Then encode 'A'..'Z' => '1'..'26' and ' ' => 0 | |
let normalize = |x| match x { | |
b'a'...b'z' => (x - 32) as i8 - b'A' as i8 + 1, | |
b'A'...b'Z' => x as i8 - b'A' as i8 + 1, | |
_ => 0 | |
}; | |
// % does not have the semantics we want for negative values | |
let modulus = |a, b| ((a % b) + b) % b; | |
for (k, m) in key.bytes().zip(msg.bytes()) { | |
let (k, m) = (normalize(k), normalize(m)); | |
// Either encode or decode | |
let c = if encode { m + k } else { m - k }; | |
// Gotta make sure we keep to A-Z | |
let c = modulus(c, 27); | |
// And back to ASCII | |
let c = if c == 0 { b' ' } else { c as u8 + b'A' - 1 }; | |
result.push(c as char); | |
} | |
result | |
} | |
#[cfg(interactive)] | |
#[allow(unused_must_use)] | |
fn main() { | |
use std::io::{self, Write}; | |
use std::iter; | |
let c1 = include_str!("enc1.txt").trim_right_matches('\n'); | |
let c2 = include_str!("enc2.txt").trim_right_matches('\n'); | |
let diff = code(c1, c2, false); | |
println!("c1 - c2 = m1 - m2:\n{}\n", diff); | |
if let Some(pos) = diff.find("LIKELY") { | |
println!("LIKELY Position: {}", pos); | |
println!(" c1 \t {}", &c1[pos-1..pos+7]); | |
println!(" c2 \t {}", &c2[pos-1..pos+7]); | |
println!("c1-c2 \t {}", &diff[pos-1..pos+7]); | |
} | |
let stdout = io::stdout(); | |
let mut out = stdout.lock(); | |
let mut m1: String = iter::repeat('_').take(diff.len()).collect(); | |
let mut m2: String = iter::repeat('_').take(diff.len()).collect(); | |
let mut key: String = iter::repeat('_').take(diff.len()).collect(); | |
let mut crib = String::new(); | |
let mut res = String::new(); | |
'repl: loop { | |
crib.clear(); | |
res.clear(); | |
write!(out, "Msg 1:\t{}\n\nMsg 2:\t{}\n\nKey:\t{}\n\n", m1, m2, key); | |
write!(out, "Crib: "); | |
out.flush(); | |
if let Err(e) = io::stdin().read_line(&mut crib) { | |
panic!("Error reading crib: {}", e); | |
} | |
crib = crib.trim_right_matches('\n').to_string(); | |
let run = diff.len() - crib.len() + 1; | |
for i in 0..run { | |
write!(out, "[{}]: >{}< >{}<\n", i, code(&diff[i..], &crib, true), code(&crib, &diff[i..], false)); | |
} | |
'resp: loop { | |
write!(out, "\nSelect [i], 'none' or 'quit'? "); | |
out.flush(); | |
if let Err(e) = io::stdin().read_line(&mut res) { | |
panic!("Error reading response: {}", e); | |
} | |
if res.trim() == "quit" || res.trim() == "q" { | |
break 'repl; | |
} else if res.trim() == "none" || res.trim() == "n" { | |
break 'resp; | |
} else { | |
match res.trim().parse::<usize>() { | |
Ok(i) if i < diff.len() => { | |
let mut which = String::new(); | |
write!(out, "Crib part of message [1] or [2]? "); | |
out.flush(); | |
if let Err(e) = io::stdin().read_line(&mut which) { | |
panic!("Error reading message selection: {}", e); | |
} | |
let loc1 = (&mut m1[i..i + crib.len()]).as_ptr() as *mut _; | |
let loc2 = (&mut m2[i..i + crib.len()]).as_ptr() as *mut _; | |
let k = if which.trim() == "1" { | |
let m2 = code(&crib, &diff[i..], false); | |
unsafe { | |
std::intrinsics::copy(crib.as_ptr(), loc1, m2.len()); | |
std::intrinsics::copy(m2.as_ptr(), loc2, m2.len()); | |
} | |
code(&c2[i..], &m2, false) | |
} else if which.trim() == "2" { | |
let m1 = code(&diff[i..], &crib, true); | |
unsafe { | |
std::intrinsics::copy(m1.as_ptr(), loc1, m1.len()); | |
std::intrinsics::copy(crib.as_ptr(), loc2, m1.len()); | |
} | |
code(&c1[i..], &m1, false) | |
} else { | |
break 'resp; | |
}; | |
unsafe { | |
let loc = (&mut key[i..i + crib.len()]).as_ptr() as *mut _; | |
std::intrinsics::copy(k.as_ptr(), loc, k.len()); | |
} | |
break 'resp; | |
} | |
_ => { | |
write!(out, "Invalid entry.\n"); | |
} | |
} | |
} | |
} | |
} | |
} | |
#[cfg(find)] | |
fn main() { | |
let words = include_str!("1000.dicin"); | |
let c1 = include_str!("enc1.txt").trim_right_matches('\n'); | |
let c2 = include_str!("enc2.txt").trim_right_matches('\n'); | |
let diff = code(c1, c2, false); | |
for w in words.lines() { | |
let mut word = "LIKELY ".to_string(); | |
word.push_str(w.trim_right_matches('\n')); | |
// m1 - (c1 - c2) | |
// = m1 - ((m1 + k) - (m2 + k)) | |
// = m1 - (m1 + k - m2 - k) | |
// = m1 - (m1 - m2) | |
// = m1 - m1 + m2 | |
// = m2 | |
let c = code(&word, &diff[2641..2641+word.len()], false); | |
println!("{} - {}", word, c.trim()); | |
} | |
} | |
#[cfg(oracle)] | |
fn main() { | |
use std::io::{self, Write}; | |
let stdout = io::stdout(); | |
let mut handle = stdout.lock(); | |
write!(handle, "Key: ").unwrap(); | |
handle.flush().unwrap(); | |
let mut key = String::new(); | |
if let Err(e) = io::stdin().read_line(&mut key) { | |
panic!("Error reading key: {}", e); | |
} | |
write!(handle, "Msg: ").unwrap(); | |
handle.flush().unwrap(); | |
let mut msg = String::new(); | |
if let Err(e) = io::stdin().read_line(&mut msg) { | |
panic!("Error reading msg: {}", e); | |
} | |
write!(handle, "[D]ecode or [E]ncode? ").unwrap(); | |
handle.flush().unwrap(); | |
let mut action = String::new(); | |
if let Err(e) = io::stdin().read_line(&mut action) { | |
panic!("Error reading action: {}", e); | |
} | |
if !action.starts_with("D") && | |
!action.starts_with("E") { | |
panic!("Plz."); | |
} | |
let c = code(msg.trim_right_matches('\n'), | |
key.trim_right_matches('\n'), | |
action.starts_with("E")); | |
println!("Result:\n{}", c); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment