Skip to content

Instantly share code, notes, and snippets.

@luqmana
Created January 15, 2016 07:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luqmana/786124e57999e8d40780 to your computer and use it in GitHub Desktop.
Save luqmana/786124e57999e8d40780 to your computer and use it in GitHub Desktop.
// 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