cryptopals

Matasano's cryptopals challenges (cryptopals.com).
Log | Files | Refs | README | LICENSE

commit 764abb1eac66fed75c70cd50bb98c976968c6c30
parent 0d1dcef0700764e8143ac6c8f7bd5eb0bd68d976
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun, 18 Nov 2018 20:12:36 +1300

Update.

Diffstat:
MCargo.toml | 4++--
Mdocs/s1.md | 24++++++++++++++++++++----
Mdocs/s2.md | 6++++++
Msrc/errors.rs | 51+++++++++++++++++++++++++++------------------------
Msrc/main.rs | 36+++++++++++++++++++-----------------
Msrc/s1c01.rs | 27+++++++++++++++------------
Msrc/s1c02.rs | 29++++++++---------------------
Msrc/s1c03.rs | 23+++++++----------------
Asrc/s2c13.rs | 43+++++++++++++++++++++++++++++++++++++++++++
9 files changed, 147 insertions(+), 96 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" authors = ["Jared Tobin <jared@jtobin.ca>"] [dependencies] -base64 = "0.6" +base64 = "0.10.0" clap = "2.26" -hex = "0.2" +hex = "0.3.2" openssl = "0.10" rand = "0.3" combine = "2.5" diff --git a/docs/s1.md b/docs/s1.md @@ -1,5 +1,8 @@ ### Set 1 +I am constantly picking at these things. You can run most everything with +a `cargo test`. + #### 1.1 We want to go from hex (i.e., base 16) to base64 (i.e., base.. uh, 64). So @@ -25,10 +28,13 @@ equality: $ diff <(xxd -r -p data/s1/q1_input.txt | base64) data/s1/q1_output.txt +In Rust it's easy enough to just use the appropriate functionality from the +`hex` and `base64` crates. + #### 1.2 Fixed-xor just encrypts by XOR'ing every bit with some corresponding bit. -An example, using `xxd` to output bits this time: +An example, using `xxd -b` to output bits this time: $ parallel -k 'echo -n {} | xxd -b' ::: FAB ICE 00000000: 01000110 01000001 01000010 FAB @@ -48,17 +54,27 @@ zero-padded: $ echo 'obase=16; ibase=2; 000011110000001000000111' | bc F0207 -The `fixed_xor` binary in `./bin` will perform the reverse task here: +The `fixed_xor` binary in `./bin` will perform the reverse task on the +zero-padded string here: $ ./bin/fixed_xor '0f0207' $(echo -n ICE | xxd -p) | xxd -r -p FAB -Running `fixed_xor` on the question input: +The Rust implementation is trivial: + + fn fixed_xor(target: &[u8], partner: &[u8]) -> Vec<u8> { + target.iter() + .zip(partner) + .map(|(l, r)| l ^ r) + .collect() + } + +And running `fixed_xor` on the question input yields the following: $ SOLUTION=$(./bin/fixed_xor $(< data/s1/q2_input.txt) $(< data/s1/q2_against.txt)) 746865206b696420646f6e277420706c6179 -Note that the ASCII-encoded output is fun: +The ASCII encoding is fun: $ echo $SOLUTION | xxd -r -p the kid don't play diff --git a/docs/s2.md b/docs/s2.md @@ -67,3 +67,9 @@ Check out [the Rust source][src] to see a sane version. [src]: https://github.com/jtobin/cryptopals/blob/master/src/s2c11.rs +#### 2.12 + +I found the text to this question to be incredibly sloppy and hard to follow. +Maybe my own shortcoming. + + diff --git a/src/errors.rs b/src/errors.rs @@ -3,57 +3,60 @@ extern crate hex; use std::error; use std::fmt; -use std::process; -use std::string; +// use std::process; +use std::result; +// use std::string; -pub enum CryptopalsError { - HexConversionError(hex::FromHexError), - Utf8ConversionError(string::FromUtf8Error) +pub type Possibly<T> = result::Result<T, CPError>; + +pub enum CPError { + HexConversion(hex::FromHexError), +// Utf8Conversion(string::FromUtf8Error) } -impl fmt::Display for CryptopalsError { +impl fmt::Display for CPError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - CryptopalsError::HexConversionError(ref err) => + CPError::HexConversion(ref err) => fmt::Display::fmt(err, f), - CryptopalsError::Utf8ConversionError(ref err) => - fmt::Display::fmt(err, f) +// CPError::Utf8Conversion(ref err) => +// fmt::Display::fmt(err, f) } } } -impl error::Error for CryptopalsError { +impl error::Error for CPError { fn description(&self) -> &str { match *self { - CryptopalsError::HexConversionError(ref err) => err.description(), - CryptopalsError::Utf8ConversionError(ref err) => err.description() + CPError::HexConversion(ref err) => err.description(), +// CPError::Utf8Conversion(ref err) => err.description() } } fn cause(&self) -> Option<&error::Error> { match *self { - CryptopalsError::HexConversionError(ref err) => Some(err), - CryptopalsError::Utf8ConversionError(ref err) => Some(err) + CPError::HexConversion(ref err) => Some(err), +// CPError::Utf8Conversion(ref err) => Some(err) } } } -impl fmt::Debug for CryptopalsError { +impl fmt::Debug for CPError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - CryptopalsError::HexConversionError(ref err) => + CPError::HexConversion(ref err) => fmt::Debug::fmt(err, f), - CryptopalsError::Utf8ConversionError(ref err) => - fmt::Debug::fmt(err, f) +// CPError::Utf8Conversion(ref err) => +// fmt::Debug::fmt(err, f) } } } -pub fn handle<A>(input: Result<A, CryptopalsError>) -> A { - input.unwrap_or_else(|err| { - println!("error (cryptopals):\n {}", err); - process::exit(1); - }) -} +// pub fn handle<A>(input: Result<A, CPError>) -> A { +// input.unwrap_or_else(|err| { +// println!("cryptopals (error):\n {}", err); +// process::exit(1); +// }) +// } diff --git a/src/main.rs b/src/main.rs @@ -2,22 +2,24 @@ mod s1c01; mod s1c02; mod s1c03; -mod s1c07; - -mod s2c09; -mod s2c10; -mod s2c11; -mod s2c12; +// mod s1c07; +// +// mod s2c09; +// mod s2c10; +// mod s2c11; +// mod s2c12; +// mod s2c13; mod errors; - -fn main() { - println!("s1c01:\n{}\n", errors::handle(s1c01::s1c01())); - println!("s1c02:\n{}\n", errors::handle(s1c02::s1c02())); - println!("s1c03:\n{}\n", errors::handle(s1c03::s1c03())); - println!("s1c07:\n{}\n", s1c07::s1c07()); - println!("s2c09:\n{}\n", s2c09::s2c09()); - println!("s2c10:\n{}\n", s2c10::s2c10()); - println!("s2c11:\n{}\n", s2c11::s2c11()); - println!("s2c12:\n{}\n", s2c12::s2c12()); -} +// +// fn main() { +// println!("s1c01:\n{}\n", errors::handle(s1c01::s1c01())); +// println!("s1c02:\n{}\n", errors::handle(s1c02::s1c02())); +// // println!("s1c03:\n{}\n", errors::handle(s1c03::s1c03())); +// // println!("s1c07:\n{}\n", s1c07::s1c07()); +// // println!("s2c09:\n{}\n", s2c09::s2c09()); +// // println!("s2c10:\n{}\n", s2c10::s2c10()); +// // println!("s2c11:\n{}\n", s2c11::s2c11()); +// // println!("s2c12:\n{}\n", s2c12::s2c12()); +// // println!("s2c13:\n{}\n", s2c13::s2c13()); +// } diff --git a/src/s1c01.rs b/src/s1c01.rs @@ -2,21 +2,24 @@ extern crate base64; extern crate hex; -use errors::CryptopalsError; -use self::hex::FromHex; +use errors::{Possibly, CPError}; -const INPUT: &str = - "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6\ - f7573206d757368726f6f6d"; +pub fn hex_to_b64(hex: &str) -> Possibly<String> { + let bytes: Possibly<Vec<u8>> = + hex::decode(&hex) + .map_err(|err| CPError::HexConversion(err)); -pub fn hex_to_b64(input: &str) -> Result<String, CryptopalsError> { - let raw: Result<Vec<u8>, _> = FromHex::from_hex(&input) - .map_err(|err| CryptopalsError::HexConversionError(err)); - - raw.map(|contents| base64::encode(&contents)) + bytes.map(|bs| base64::encode(&bs)) } -pub fn s1c01() -> Result<String, CryptopalsError> { - hex_to_b64(INPUT) +#[test] +fn test_hex_to_b64() { + const INPUT: &str = "49276d206b696c6c696e6720796f757220627261696e206c696b6\ + 5206120706f69736f6e6f7573206d757368726f6f6d"; + + const OUTPUT: &str = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3Vz\ + IG11c2hyb29t"; + let b64 = hex_to_b64(INPUT).unwrap(); + assert_eq!(OUTPUT, b64); } diff --git a/src/s1c02.rs b/src/s1c02.rs @@ -1,9 +1,6 @@ extern crate hex; -use errors::CryptopalsError; -use self::hex::{FromHex, ToHex}; - const TARGET: &str = "1c0111001f010100061a024b53535009181c"; const PARTNER: &str = "686974207468652062756c6c277320657965"; @@ -14,22 +11,12 @@ pub fn fixed_xor(target: &[u8], partner: &[u8]) -> Vec<u8> { .collect() } -pub fn s1c02() -> Result<String, CryptopalsError> { - let target: Result<Vec<u8>, _> = FromHex::from_hex(&TARGET) - .map_err(|err| CryptopalsError::HexConversionError(err)); - - let target = match target { - Ok(val) => val, - Err(err) => return Err(err) - }; - - let partner: Result<Vec<u8>, _> = FromHex::from_hex(&PARTNER) - .map_err(|err| CryptopalsError::HexConversionError(err)); - - let partner = match partner { - Ok(val) => val, - Err(err) => return Err(err) - }; - - Ok(fixed_xor(&target, &partner).to_hex()) +#[test] +fn test_fixed_xor() { + let hex0 = hex::decode(TARGET).unwrap(); + let hex1 = hex::decode(PARTNER).unwrap(); + let xor = fixed_xor(&hex0, &hex1); + let expected = "746865206b696420646f6e277420706c6179"; + assert_eq!(hex::encode(xor), expected) } + diff --git a/src/s1c03.rs b/src/s1c03.rs @@ -1,14 +1,10 @@ extern crate hex; -use errors::CryptopalsError; use std::collections::HashMap; use std::f32; use std::u8; -const INPUT: &'static str = - "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736"; - fn tally(vec: Vec<u8>) -> HashMap<u8, u8> { let mut hashmap = HashMap::new(); @@ -185,19 +181,14 @@ pub fn break_single_byte_xor(bytes: &[u8]) -> (u8, Vec<u8>) { (min.1, min.0) } -pub fn s1c03() -> Result<String, CryptopalsError> { - let ciphertext: Result<Vec<u8>, CryptopalsError> = - hex::FromHex::from_hex(INPUT) - .map_err(|err| CryptopalsError::HexConversionError(err)); - - let ciphertext = match ciphertext { - Ok(val) => val, - Err(err) => return Err(err) - }; +#[test] +fn test_break_single_byte_xor() { + const INPUT: &'static str = + "1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736"; + let ciphertext = hex::decode(INPUT).unwrap(); let message = break_single_byte_xor(&ciphertext).1; - - String::from_utf8(message) - .map_err(|err| CryptopalsError::Utf8ConversionError(err)) + let output = String::from_utf8(message).unwrap(); + assert_eq!(output, "Cooking MC's like a pound of bacon"); } diff --git a/src/s2c13.rs b/src/s2c13.rs @@ -0,0 +1,43 @@ + +extern crate combine; + +use self::combine::{many1, sep_by, token, none_of}; +// use self::combine::char::letter; + +pub fn foo(input: String) -> String { + let metachars = "&=".iter().cloned(); + let word = many1(none_of(metachars)); + let pair = sep_by(word, token('=')); + let pairs = sep_by(pair, token('&')); + + String::from("hello") +} + + +pub fn s2c13() -> String{ + String::from("foo") +} + + + +// pub fn s2c13() -> String { +// // FIXME & is not right here - there shouldn't be a hanging & +// let structured_cookie = Regex::new(r"([A-Za-z]+=[^&=]*&?)*").unwrap(); +// +// let test = structured_cookie.captures("foo=bar&baz=quux").unwrap(); +// +// println!("{} {}", test.get(0).unwrap().as_str(), test.get(1).unwrap().as_str()); +// +// String::from("foo") +// } + +// +// foo=bar&baz=qux +// +// parse that into some kind of json +// +// { +// 'foo': 'bar', +// 'baz': 'qux' +// } +//