From 3f4de3d0d2dc7b763d487bc2d9fd4d751cccfb54 Mon Sep 17 00:00:00 2001 From: Thomas Lindner Date: Sun, 17 Dec 2023 03:14:16 +0100 Subject: [PATCH] solve Challenge 5 of Set 1 --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + common/src/lib.rs | 18 ++++++++++++----- set1/challenge2_fixed_xor/src/main.rs | 4 ++-- set1/challenge3_xor_cipher/src/main.rs | 4 ++-- set1/challenge4_detect_xor/src/main.rs | 2 +- set1/challenge5_repeating_xor/Cargo.toml | 11 +++++++++++ set1/challenge5_repeating_xor/src/main.rs | 24 +++++++++++++++++++++++ 8 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 set1/challenge5_repeating_xor/Cargo.toml create mode 100644 set1/challenge5_repeating_xor/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 914577e..407f824 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,6 +149,16 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "repeating_xor" +version = "0.1.0" +dependencies = [ + "common", + "env_logger", + "log", + "rustc-serialize", +] + [[package]] name = "rustc-serialize" version = "0.3.25" diff --git a/Cargo.toml b/Cargo.toml index 433d8db..f4424ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,6 @@ members = [ "set1/challenge2_fixed_xor", "set1/challenge3_xor_cipher", "set1/challenge4_detect_xor", + "set1/challenge5_repeating_xor", ] resolver = "2" diff --git a/common/src/lib.rs b/common/src/lib.rs index fe01fe2..ecee692 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -18,15 +18,19 @@ pub fn score(plaintext: &Vec) -> u32 { score } -pub fn fixed_xor_cipher(ciphertext: &Vec, keyiter: &mut dyn Iterator) -> Vec { - ciphertext.iter().zip(keyiter).map(|(c, k)| c ^ k).collect() +pub fn generic_xor_cipher(text: &[u8], keyiter: &mut dyn Iterator) -> Vec { + text.iter().zip(keyiter).map(|(c, k)| c ^ k).collect() } -pub fn xor_cipher(ciphertext: &Vec, key: u8) -> Vec { - fixed_xor_cipher(ciphertext, &mut repeat(key)) +pub fn fixed_xor_cipher(text: &[u8], key: &[u8]) -> Vec { + generic_xor_cipher(text, &mut key.iter()) } -pub fn break_xor_cipher(ciphertext: &Vec) -> (Vec, u32) { +pub fn xor_cipher(text: &[u8], key: u8) -> Vec { + generic_xor_cipher(text, &mut repeat(&key)) +} + +pub fn break_xor_cipher(ciphertext: &[u8]) -> (Vec, u32) { let mut maxscore = 0; let mut decrypted: Vec = vec![]; @@ -40,3 +44,7 @@ pub fn break_xor_cipher(ciphertext: &Vec) -> (Vec, u32) { } (decrypted, maxscore) } + +pub fn repeating_xor_cipher(text: &[u8], key: &[u8]) -> Vec { + generic_xor_cipher(text, &mut key.iter().cycle()) +} diff --git a/set1/challenge2_fixed_xor/src/main.rs b/set1/challenge2_fixed_xor/src/main.rs index 8f79338..8082833 100644 --- a/set1/challenge2_fixed_xor/src/main.rs +++ b/set1/challenge2_fixed_xor/src/main.rs @@ -22,7 +22,7 @@ fn main() { for (line1, line2) in Pairwise(stdin().lock().lines().filter_map(|x| x.ok())) { match (line1.from_hex(), line2.from_hex()) { - (Ok(v1), Ok(v2)) => println!("{}", fixed_xor_cipher(&v1, &mut v2.into_iter()).to_hex()), + (Ok(v1), Ok(v2)) => println!("{}", fixed_xor_cipher(v1.as_slice(), v2.as_slice()).to_hex()), (Err(e), _) => error!("{}", e), (_, Err(e)) => error!("{}", e) } @@ -37,7 +37,7 @@ mod tests { fn challenge2_fixed_xor() { let v1 = "1c0111001f010100061a024b53535009181c".from_hex().unwrap(); let v2 = "686974207468652062756c6c277320657965".from_hex().unwrap(); - let r = fixed_xor_cipher(&v1, &mut v2.into_iter()).to_hex(); + let r = fixed_xor_cipher(v1.as_slice(), v2.as_slice()).to_hex(); assert_eq!(r, "746865206b696420646f6e277420706c6179"); } } diff --git a/set1/challenge3_xor_cipher/src/main.rs b/set1/challenge3_xor_cipher/src/main.rs index 5caff28..59114ac 100644 --- a/set1/challenge3_xor_cipher/src/main.rs +++ b/set1/challenge3_xor_cipher/src/main.rs @@ -9,7 +9,7 @@ fn main() { for line in stdin().lock().lines().filter_map(|x| x.ok()) { match line.from_hex() { Ok(ciphertext) => { - let (decrypted, _) = break_xor_cipher(&ciphertext); + let (decrypted, _) = break_xor_cipher(ciphertext.as_slice()); match String::from_utf8(decrypted) { Ok(s) => println!("{}", s), Err(e) => error!("{}", e) @@ -27,7 +27,7 @@ mod tests { #[test] fn challenge3_xor_cipher() { let ciphertext = "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736".from_hex().unwrap(); - let (decrypted, _) = break_xor_cipher(&ciphertext); + let (decrypted, _) = break_xor_cipher(ciphertext.as_slice()); assert_eq!(String::from_utf8(decrypted).unwrap(), "Cooking MC's like a pound of bacon"); } } diff --git a/set1/challenge4_detect_xor/src/main.rs b/set1/challenge4_detect_xor/src/main.rs index e931c4b..78c842a 100644 --- a/set1/challenge4_detect_xor/src/main.rs +++ b/set1/challenge4_detect_xor/src/main.rs @@ -10,7 +10,7 @@ fn detect_xor(input: &mut dyn BufRead) -> Result> { for line in input.lines() { let ciphertext = line?.from_hex()?; - let (plaintext, score) = break_xor_cipher(&ciphertext); + let (plaintext, score) = break_xor_cipher(ciphertext.as_slice()); if score > maxscore { maxscore = score; decrypted = plaintext; diff --git a/set1/challenge5_repeating_xor/Cargo.toml b/set1/challenge5_repeating_xor/Cargo.toml new file mode 100644 index 0000000..69b324d --- /dev/null +++ b/set1/challenge5_repeating_xor/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "repeating_xor" +version = "0.1.0" +edition = "2021" +authors = ["Thomas Lindner "] + +[dependencies] +common = { path = "../../common" } +log = "0.4" +env_logger = "0.10" +rustc-serialize = "0.3" diff --git a/set1/challenge5_repeating_xor/src/main.rs b/set1/challenge5_repeating_xor/src/main.rs new file mode 100644 index 0000000..565d995 --- /dev/null +++ b/set1/challenge5_repeating_xor/src/main.rs @@ -0,0 +1,24 @@ +use common::repeating_xor_cipher; +use rustc_serialize::hex::ToHex; +use std::io::{BufRead, stdin}; + +fn main() { + env_logger::init(); + + for line in stdin().lock().lines().filter_map(|x| x.ok()) { + let ciphertext = repeating_xor_cipher(line.as_bytes(), "ICE".as_bytes()); + println!("{}", ciphertext.to_hex()); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn challenge5_repeating_xor() { + let plaintext = "Burning 'em, if you ain't quick and nimble\nI go crazy when I hear a cymbal".as_bytes(); + let ciphertext = repeating_xor_cipher(plaintext, "ICE".as_bytes()); + assert_eq!(ciphertext.to_hex(), "0b3637272a2b2e63622c2e69692a23693a2a3c6324202d623d63343c2a26226324272765272a282b2f20430a652e2c652a3124333a653e2b2027630c692b20283165286326302e27282f"); + } +}