From 07b711c7736dcf0a7f25ec7a59ae4bffa2c3df9d Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 17 Mar 2015 07:46:55 -0400 Subject: problem 11 --- Cargo.lock | 15 +++++++++++++++ Cargo.toml | 1 + src/aes.rs | 26 +++++++++++++++++++++++++- src/lib.rs | 2 ++ tests/lib.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 7a7b9ec..e3a428c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,7 @@ name = "matasano" version = "0.0.1" dependencies = [ "openssl 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -24,6 +25,11 @@ dependencies = [ "pnacl-build-helper 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "log" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "openssl" version = "0.5.1" @@ -54,6 +60,15 @@ name = "pnacl-build-helper" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-serialize" version = "0.3.3" diff --git a/Cargo.toml b/Cargo.toml index 4a8eb22..573fc44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ authors = ["Jesse Luehrs "] [dependencies] rustc-serialize = "0.3.3" openssl = "0.5.1" +rand = "0.2.0" diff --git a/src/aes.rs b/src/aes.rs index 9baf595..e4a7184 100644 --- a/src/aes.rs +++ b/src/aes.rs @@ -1,8 +1,16 @@ -use openssl; +use std; use std::collections::HashSet; +use openssl; + use primitives::{fixed_xor, pad_pkcs7, unpad_pkcs7}; +#[derive(PartialEq,Eq,Debug)] +pub enum BlockCipherMode { + ECB, + CBC, +} + pub fn decrypt_aes_128_ecb (bytes: &[u8], key: &[u8]) -> Vec { return openssl::crypto::symm::decrypt( openssl::crypto::symm::Type::AES_128_ECB, @@ -65,6 +73,22 @@ pub fn find_aes_128_ecb_encrypted_string (inputs: &[Vec]) -> Vec { return found; } +pub fn detect_ecb_cbc (f: F) -> BlockCipherMode where F: Fn(&[u8]) -> Vec { + let plaintext: Vec = (0..16) + .cycle() + .take(32) + .flat_map(|n| std::iter::repeat(n).take(17)) + .collect(); + let ciphertext = f(&plaintext[..]); + + if count_duplicate_blocks(&ciphertext[..]) >= 16 { + return BlockCipherMode::ECB; + } + else { + return BlockCipherMode::CBC; + } +} + fn count_duplicate_blocks (input: &[u8]) -> usize { let mut set = HashSet::new(); let mut dups = 0; diff --git a/src/lib.rs b/src/lib.rs index 901cbd6..48418ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,13 @@ mod data; mod primitives; mod xor; +pub use aes::BlockCipherMode; pub use aes::decrypt_aes_128_ecb; pub use aes::decrypt_aes_128_cbc; pub use aes::encrypt_aes_128_ecb; pub use aes::encrypt_aes_128_cbc; pub use aes::find_aes_128_ecb_encrypted_string; +pub use aes::detect_ecb_cbc; pub use base64::to_base64; pub use primitives::fixed_xor; pub use primitives::pad_pkcs7; diff --git a/tests/lib.rs b/tests/lib.rs index 553213a..d1bc806 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,9 +1,11 @@ extern crate matasano; extern crate "rustc-serialize" as serialize; +extern crate rand; use std::io::prelude::*; use std::fs::File; +use rand::{Rng, thread_rng}; use serialize::base64::FromBase64; use serialize::hex::FromHex; @@ -29,6 +31,16 @@ fn read (filename: &str) -> Vec { return outfh.bytes().map(|c| c.unwrap()).collect(); } +fn random_aes_128_key () -> [u8; 16] { + let mut key = [0; 16]; + thread_rng().fill_bytes(&mut key); + return key; +} + +fn coinflip () -> bool { + thread_rng().gen() +} + #[test] fn problem_1 () { let hex = "49276d206b696c6c696e6720796f757220627261\ @@ -127,3 +139,49 @@ fn problem_10 () { let got = matasano::decrypt_aes_128_cbc(&ciphertext[..], key, &[0; 16]); assert_eq!(got, plaintext); } + +#[test] +fn problem_11 () { + static mut last_mode: matasano::BlockCipherMode = matasano::BlockCipherMode::ECB; + + fn random_padding (input: &[u8]) -> Vec { + let front_padding: Vec = thread_rng() + .gen_iter() + .take(thread_rng().gen_range(5, 10)) + .collect(); + let back_padding: Vec = thread_rng() + .gen_iter() + .take(thread_rng().gen_range(5, 10)) + .collect(); + return front_padding + .iter() + .chain(input.iter()) + .chain(back_padding.iter()) + .map(|x| *x) + .collect() + } + + fn random_encrypter (input: &[u8]) -> Vec { + let key = random_aes_128_key(); + let padded_input = random_padding(input); + if coinflip() { + unsafe { + last_mode = matasano::BlockCipherMode::ECB; + } + return matasano::encrypt_aes_128_ecb(&padded_input[..], &key[..]); + } + else { + unsafe { + last_mode = matasano::BlockCipherMode::CBC; + } + let iv = random_aes_128_key(); + return matasano::encrypt_aes_128_cbc(&padded_input[..], &key[..], &iv[..]); + } + } + + for _ in 0..100 { + let got = matasano::detect_ecb_cbc(random_encrypter); + let expected = unsafe { &last_mode }; + assert_eq!(&got, expected); + } +} -- cgit v1.2.3-54-g00ecf