solve Challenge 5 of Set 1
This commit is contained in:
parent
fd49c952b0
commit
3f4de3d0d2
Cargo.lockCargo.toml
common/src
set1
challenge2_fixed_xor/src
challenge3_xor_cipher/src
challenge4_detect_xor/src
challenge5_repeating_xor
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -149,6 +149,16 @@ version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "repeating_xor"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"common",
|
||||||
|
"env_logger",
|
||||||
|
"log",
|
||||||
|
"rustc-serialize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-serialize"
|
name = "rustc-serialize"
|
||||||
version = "0.3.25"
|
version = "0.3.25"
|
||||||
|
|
|
@ -6,5 +6,6 @@ members = [
|
||||||
"set1/challenge2_fixed_xor",
|
"set1/challenge2_fixed_xor",
|
||||||
"set1/challenge3_xor_cipher",
|
"set1/challenge3_xor_cipher",
|
||||||
"set1/challenge4_detect_xor",
|
"set1/challenge4_detect_xor",
|
||||||
|
"set1/challenge5_repeating_xor",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
|
@ -18,15 +18,19 @@ pub fn score(plaintext: &Vec<u8>) -> u32 {
|
||||||
score
|
score
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fixed_xor_cipher(ciphertext: &Vec<u8>, keyiter: &mut dyn Iterator<Item = u8>) -> Vec<u8> {
|
pub fn generic_xor_cipher(text: &[u8], keyiter: &mut dyn Iterator<Item = &u8>) -> Vec<u8> {
|
||||||
ciphertext.iter().zip(keyiter).map(|(c, k)| c ^ k).collect()
|
text.iter().zip(keyiter).map(|(c, k)| c ^ k).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn xor_cipher(ciphertext: &Vec<u8>, key: u8) -> Vec<u8> {
|
pub fn fixed_xor_cipher(text: &[u8], key: &[u8]) -> Vec<u8> {
|
||||||
fixed_xor_cipher(ciphertext, &mut repeat(key))
|
generic_xor_cipher(text, &mut key.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn break_xor_cipher(ciphertext: &Vec<u8>) -> (Vec<u8>, u32) {
|
pub fn xor_cipher(text: &[u8], key: u8) -> Vec<u8> {
|
||||||
|
generic_xor_cipher(text, &mut repeat(&key))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn break_xor_cipher(ciphertext: &[u8]) -> (Vec<u8>, u32) {
|
||||||
let mut maxscore = 0;
|
let mut maxscore = 0;
|
||||||
let mut decrypted: Vec<u8> = vec![];
|
let mut decrypted: Vec<u8> = vec![];
|
||||||
|
|
||||||
|
@ -40,3 +44,7 @@ pub fn break_xor_cipher(ciphertext: &Vec<u8>) -> (Vec<u8>, u32) {
|
||||||
}
|
}
|
||||||
(decrypted, maxscore)
|
(decrypted, maxscore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn repeating_xor_cipher(text: &[u8], key: &[u8]) -> Vec<u8> {
|
||||||
|
generic_xor_cipher(text, &mut key.iter().cycle())
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn main() {
|
||||||
|
|
||||||
for (line1, line2) in Pairwise(stdin().lock().lines().filter_map(|x| x.ok())) {
|
for (line1, line2) in Pairwise(stdin().lock().lines().filter_map(|x| x.ok())) {
|
||||||
match (line1.from_hex(), line2.from_hex()) {
|
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),
|
||||||
(_, Err(e)) => error!("{}", e)
|
(_, Err(e)) => error!("{}", e)
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ mod tests {
|
||||||
fn challenge2_fixed_xor() {
|
fn challenge2_fixed_xor() {
|
||||||
let v1 = "1c0111001f010100061a024b53535009181c".from_hex().unwrap();
|
let v1 = "1c0111001f010100061a024b53535009181c".from_hex().unwrap();
|
||||||
let v2 = "686974207468652062756c6c277320657965".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");
|
assert_eq!(r, "746865206b696420646f6e277420706c6179");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ fn main() {
|
||||||
for line in stdin().lock().lines().filter_map(|x| x.ok()) {
|
for line in stdin().lock().lines().filter_map(|x| x.ok()) {
|
||||||
match line.from_hex() {
|
match line.from_hex() {
|
||||||
Ok(ciphertext) => {
|
Ok(ciphertext) => {
|
||||||
let (decrypted, _) = break_xor_cipher(&ciphertext);
|
let (decrypted, _) = break_xor_cipher(ciphertext.as_slice());
|
||||||
match String::from_utf8(decrypted) {
|
match String::from_utf8(decrypted) {
|
||||||
Ok(s) => println!("{}", s),
|
Ok(s) => println!("{}", s),
|
||||||
Err(e) => error!("{}", e)
|
Err(e) => error!("{}", e)
|
||||||
|
@ -27,7 +27,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn challenge3_xor_cipher() {
|
fn challenge3_xor_cipher() {
|
||||||
let ciphertext = "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736".from_hex().unwrap();
|
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");
|
assert_eq!(String::from_utf8(decrypted).unwrap(), "Cooking MC's like a pound of bacon");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ fn detect_xor(input: &mut dyn BufRead) -> Result<String, Box<dyn Error>> {
|
||||||
|
|
||||||
for line in input.lines() {
|
for line in input.lines() {
|
||||||
let ciphertext = line?.from_hex()?;
|
let ciphertext = line?.from_hex()?;
|
||||||
let (plaintext, score) = break_xor_cipher(&ciphertext);
|
let (plaintext, score) = break_xor_cipher(ciphertext.as_slice());
|
||||||
if score > maxscore {
|
if score > maxscore {
|
||||||
maxscore = score;
|
maxscore = score;
|
||||||
decrypted = plaintext;
|
decrypted = plaintext;
|
||||||
|
|
11
set1/challenge5_repeating_xor/Cargo.toml
Normal file
11
set1/challenge5_repeating_xor/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "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"
|
24
set1/challenge5_repeating_xor/src/main.rs
Normal file
24
set1/challenge5_repeating_xor/src/main.rs
Normal file
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue