solve Challenge 6 of Set 1
This commit is contained in:
parent
3f4de3d0d2
commit
311f274645
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -17,9 +17,22 @@ version = "2.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
|
||||
|
||||
[[package]]
|
||||
name = "break_repeating_xor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"common",
|
||||
"env_logger",
|
||||
"log",
|
||||
"rustc-serialize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "detect_xor"
|
||||
|
|
|
@ -7,5 +7,6 @@ members = [
|
|||
"set1/challenge3_xor_cipher",
|
||||
"set1/challenge4_detect_xor",
|
||||
"set1/challenge5_repeating_xor",
|
||||
"set1/challenge6_break_repeating_xor",
|
||||
]
|
||||
resolver = "2"
|
||||
|
|
|
@ -5,3 +5,4 @@ edition = "2021"
|
|||
authors = ["Thomas Lindner <tom@dl6tom.de>"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
use log::{debug, trace};
|
||||
use std::ascii::escape_default;
|
||||
use std::iter::repeat;
|
||||
|
||||
pub fn score(plaintext: &Vec<u8>) -> u32 {
|
||||
pub fn escape(text: &[u8]) -> String {
|
||||
String::from_utf8(text.iter().map(|ch| escape_default(ch.clone())).flatten().collect()).unwrap()
|
||||
}
|
||||
|
||||
pub fn score(plaintext: &[u8]) -> u32 {
|
||||
let ranking = [24, 7, 15, 17, 26, 11, 10, 19, 22, 4, 5, 16, 13,
|
||||
21, 23, 8, 2, 18, 20, 25, 14, 6, 12, 3, 9, 1];
|
||||
let mut score = 0;
|
||||
|
@ -8,7 +14,9 @@ pub fn score(plaintext: &Vec<u8>) -> u32 {
|
|||
for ch in plaintext.iter() {
|
||||
if ch >= &0x20 && ch <= &0x7e {
|
||||
score += 1;
|
||||
if ch >= &('a' as u8) && ch <= &('z' as u8) {
|
||||
if ch == &(' ' as u8) {
|
||||
score += 27;
|
||||
} else if ch >= &('a' as u8) && ch <= &('z' as u8) {
|
||||
score += ranking[(ch - 'a' as u8) as usize];
|
||||
} else if ch >= &('A' as u8) && ch <= &('Z' as u8) {
|
||||
score += ranking[(ch - 'A' as u8) as usize];
|
||||
|
@ -18,6 +26,26 @@ pub fn score(plaintext: &Vec<u8>) -> u32 {
|
|||
score
|
||||
}
|
||||
|
||||
pub fn hamming(v1: &[u8], v2: &[u8]) -> u32 {
|
||||
v1.iter().zip(v2.iter()).map(|(a, b)| a ^ b)
|
||||
.map(|x| ((x & 0xaa) >> 1) + (x & 0x55))
|
||||
.map(|x| ((x & 0xcc) >> 2) + (x & 0x33))
|
||||
.map(|x| ((x & 0xf0) >> 4) + (x & 0x0f))
|
||||
.map(|x| x as u32).sum()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn challenge6_hamming() {
|
||||
let v1 = "this is a test";
|
||||
let v2 = "wokka wokka!!!";
|
||||
assert_eq!(hamming(v1.as_bytes(), v2.as_bytes()), 37);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generic_xor_cipher(text: &[u8], keyiter: &mut dyn Iterator<Item = &u8>) -> Vec<u8> {
|
||||
text.iter().zip(keyiter).map(|(c, k)| c ^ k).collect()
|
||||
}
|
||||
|
@ -35,16 +63,58 @@ pub fn break_xor_cipher(ciphertext: &[u8]) -> (Vec<u8>, u32) {
|
|||
let mut decrypted: Vec<u8> = vec![];
|
||||
|
||||
for key in 0..0xff {
|
||||
let plaintext: Vec<u8> = xor_cipher(&ciphertext, key);
|
||||
let s = score(&plaintext);
|
||||
let plaintext = xor_cipher(ciphertext, key);
|
||||
let s = score(plaintext.as_slice());
|
||||
trace!("score:{} \"{}\"", s, escape(plaintext.as_slice()));
|
||||
if s > maxscore {
|
||||
maxscore = s;
|
||||
decrypted = plaintext;
|
||||
}
|
||||
}
|
||||
debug!("score:{} \"{}\"", maxscore, escape(decrypted.as_slice()));
|
||||
(decrypted, maxscore)
|
||||
}
|
||||
|
||||
pub fn repeating_xor_cipher(text: &[u8], key: &[u8]) -> Vec<u8> {
|
||||
generic_xor_cipher(text, &mut key.iter().cycle())
|
||||
}
|
||||
|
||||
pub fn break_repeating_xor_cipher(ciphertext: &[u8]) -> Vec<u8> {
|
||||
let mut mindistance = u32::MAX;
|
||||
let mut keylength = 0;
|
||||
for length in 1..40 {
|
||||
let mut distance = 0;
|
||||
let maxoffset = ciphertext.len() / length - 1;
|
||||
for offset in 0..maxoffset {
|
||||
distance += hamming(&ciphertext[offset * length .. (offset + 1) * length],
|
||||
&ciphertext[(offset + 1) * length .. (offset + 2) * length]);
|
||||
}
|
||||
// scale and normalize
|
||||
distance *= 1024;
|
||||
distance /= (maxoffset * length) as u32;
|
||||
trace!("distance:{} keylength:{}", distance, length);
|
||||
if distance < mindistance {
|
||||
mindistance = distance;
|
||||
keylength = length;
|
||||
}
|
||||
}
|
||||
debug!("estimated keylength: {}", keylength);
|
||||
|
||||
let mut decryptedcolumns: Vec<Vec<u8>> = vec![];
|
||||
for offset in 0..keylength {
|
||||
let ciphercolumn: Vec<u8> = ciphertext[offset..].iter().step_by(keylength).cloned().collect();
|
||||
let (decrypted, _) = break_xor_cipher(ciphercolumn.as_slice());
|
||||
decryptedcolumns.push(decrypted);
|
||||
}
|
||||
|
||||
let mut decrypted: Vec<u8> = vec![];
|
||||
for i in 0..decryptedcolumns[0].len() {
|
||||
for column in decryptedcolumns.iter() {
|
||||
if column.len() <= i {
|
||||
break;
|
||||
}
|
||||
decrypted.push(column[i]);
|
||||
}
|
||||
}
|
||||
decrypted
|
||||
}
|
||||
|
|
64
set1/challenge6_break_repeating_xor/6.txt
Normal file
64
set1/challenge6_break_repeating_xor/6.txt
Normal file
|
@ -0,0 +1,64 @@
|
|||
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
|
79
set1/challenge6_break_repeating_xor/6_plaintext.txt
Normal file
79
set1/challenge6_break_repeating_xor/6_plaintext.txt
Normal file
|
@ -0,0 +1,79 @@
|
|||
I'm back and I'm ringin' the bell
|
||||
A rockin' on the mike while the fly girls yell
|
||||
In ecstasy in the back of me
|
||||
Well that's my DJ Deshay cuttin' all them Z's
|
||||
Hittin' hard and the girlies goin' crazy
|
||||
Vanilla's on the mike, man I'm not lazy.
|
||||
|
||||
I'm lettin' my drug kick in
|
||||
It controls my mouth and I begin
|
||||
To just let it flow, let my concepts go
|
||||
My posse's to the side yellin', Go Vanilla Go!
|
||||
|
||||
Smooth 'cause that's the way I will be
|
||||
And if you don't give a damn, then
|
||||
Why you starin' at me
|
||||
So get off 'cause I control the stage
|
||||
There's no dissin' allowed
|
||||
I'm in my own phase
|
||||
The girlies sa y they love me and that is ok
|
||||
And I can dance better than any kid n' play
|
||||
|
||||
Stage 2 -- Yea the one ya' wanna listen to
|
||||
It's off my head so let the beat play through
|
||||
So I can funk it up and make it sound good
|
||||
1-2-3 Yo -- Knock on some wood
|
||||
For good luck, I like my rhymes atrocious
|
||||
Supercalafragilisticexpialidocious
|
||||
I'm an effect and that you can bet
|
||||
I can take a fly girl and make her wet.
|
||||
|
||||
I'm like Samson -- Samson to Delilah
|
||||
There's no denyin', You can try to hang
|
||||
But you'll keep tryin' to get my style
|
||||
Over and over, practice makes perfect
|
||||
But not if you're a loafer.
|
||||
|
||||
You'll get nowhere, no place, no time, no girls
|
||||
Soon -- Oh my God, homebody, you probably eat
|
||||
Spaghetti with a spoon! Come on and say it!
|
||||
|
||||
VIP. Vanilla Ice yep, yep, I'm comin' hard like a rhino
|
||||
Intoxicating so you stagger like a wino
|
||||
So punks stop trying and girl stop cryin'
|
||||
Vanilla Ice is sellin' and you people are buyin'
|
||||
'Cause why the freaks are jockin' like Crazy Glue
|
||||
Movin' and groovin' trying to sing along
|
||||
All through the ghetto groovin' this here song
|
||||
Now you're amazed by the VIP posse.
|
||||
|
||||
Steppin' so hard like a German Nazi
|
||||
Startled by the bases hittin' ground
|
||||
There's no trippin' on mine, I'm just gettin' down
|
||||
Sparkamatic, I'm hangin' tight like a fanatic
|
||||
You trapped me once and I thought that
|
||||
You might have it
|
||||
So step down and lend me your ear
|
||||
'89 in my time! You, '90 is my year.
|
||||
|
||||
You're weakenin' fast, YO! and I can tell it
|
||||
Your body's gettin' hot, so, so I can smell it
|
||||
So don't be mad and don't be sad
|
||||
'Cause the lyrics belong to ICE, You can call me Dad
|
||||
You're pitchin' a fit, so step back and endure
|
||||
Let the witch doctor, Ice, do the dance to cure
|
||||
So come up close and don't be square
|
||||
You wanna battle me -- Anytime, anywhere
|
||||
|
||||
You thought that I was weak, Boy, you're dead wrong
|
||||
So come on, everybody and sing this song
|
||||
|
||||
Say -- Play that funky music Say, go white boy, go white boy go
|
||||
play that funky music Go white boy, go white boy, go
|
||||
Lay down and boogie and play that funky music till you die.
|
||||
|
||||
Play that funky music Come on, Come on, let me hear
|
||||
Play that funky music white boy you say it, say it
|
||||
Play that funky music A little louder now
|
||||
Play that funky music, white boy Come on, Come on, Come on
|
||||
Play that funky music
|
11
set1/challenge6_break_repeating_xor/Cargo.toml
Normal file
11
set1/challenge6_break_repeating_xor/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "break_repeating_xor"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["Thomas Lindner <tom@dl6tom.de>"]
|
||||
|
||||
[dependencies]
|
||||
common = { path = "../../common" }
|
||||
log = "0.4"
|
||||
env_logger = "0.10"
|
||||
rustc-serialize = "0.3"
|
37
set1/challenge6_break_repeating_xor/src/main.rs
Normal file
37
set1/challenge6_break_repeating_xor/src/main.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use common::break_repeating_xor_cipher;
|
||||
use log::error;
|
||||
use rustc_serialize::base64::FromBase64;
|
||||
use std::error::Error;
|
||||
use std::io::{Read, read_to_string, stdin};
|
||||
|
||||
fn break_xor(input: &mut dyn Read) -> Result<String, Box<dyn Error>> {
|
||||
let ciphertext = read_to_string(input)?.from_base64()?;
|
||||
let decrypted = break_repeating_xor_cipher(ciphertext.as_slice());
|
||||
Ok(String::from_utf8(decrypted)?)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
match break_xor(&mut stdin().lock()) {
|
||||
Ok(s) => println!("{}", s),
|
||||
Err(e) => error!("{}", e)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::path::Path;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn challenge6_break_repeating_xor() {
|
||||
let cargo_manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||
let testinput = File::open(cargo_manifest_dir.join("6.txt")).unwrap();
|
||||
let decrypted = break_xor(&mut BufReader::new(testinput)).unwrap();
|
||||
let plaintext = read_to_string(File::open(cargo_manifest_dir.join("6_plaintext.txt")).unwrap()).unwrap();
|
||||
assert_eq!(decrypted, plaintext);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue