From b4210c80d347e3d3d7aafe17349e7bf54448994f Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sat, 18 Apr 2015 02:19:02 -0400 Subject: problem 27 --- src/crack.rs | 27 +++++++++++++++++++++++++++ src/lib.rs | 1 + tests/set4.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/src/crack.rs b/src/crack.rs index b5ff9ff..5b387bb 100644 --- a/src/crack.rs +++ b/src/crack.rs @@ -3,6 +3,7 @@ use std::borrow::ToOwned; use std::collections::{HashMap, HashSet}; use rand::{Rng, SeedableRng}; +use aes::encrypt_aes_128_cbc; use data::ENGLISH_FREQUENCIES; use primitives::{fixed_xor, unpad_pkcs7, hamming, repeating_key_xor}; use random::MersenneTwister; @@ -446,6 +447,32 @@ pub fn crack_ctr_bitflipping (f: &F) -> Vec where F: Fn(&str) -> Vec .collect(); } +pub fn crack_cbc_iv_key (encrypt: &F1, verify: &F2) -> Vec where F1: Fn(&str) -> Vec, F2: Fn(&[u8]) -> Result> { + loop { + let plaintext_bytes: Vec = ::rand::thread_rng() + .gen_iter() + .filter(|&c| c >= 32 && c < 127) + .take(16*5) + .collect(); + let plaintext = ::std::str::from_utf8(&plaintext_bytes).unwrap(); + let ciphertext = encrypt(plaintext); + let modified_ciphertext: Vec = ciphertext[..16] + .iter() + .map(|x| *x) + .chain(::std::iter::repeat(0).take(16)) + .chain(ciphertext[..16].iter().map(|x| *x)) + .chain(ciphertext[48..].iter().map(|x| *x)) + .collect(); + if let Err(modified_plaintext) = verify(&modified_ciphertext[..]) { + let key = fixed_xor( + &modified_plaintext[..16], + &modified_plaintext[32..48] + ); + let desired_plaintext = b"comment1=cooking%20MCs;userdata=;admin=true;comment2=%20like%20a%20pound%20of%20bacon"; + return encrypt_aes_128_cbc(desired_plaintext, &key[..], &key[..]); + } + } +} fn crack_single_byte_xor_with_confidence (input: &[u8]) -> (u8, f64) { let mut min_diff = 100.0; diff --git a/src/lib.rs b/src/lib.rs index 4209c0d..40a9773 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,3 +44,4 @@ pub use crack::recover_16_bit_mt19937_key; pub use crack::recover_mt19937_key_from_time; pub use crack::crack_aes_128_ctr_random_access; pub use crack::crack_ctr_bitflipping; +pub use crack::crack_cbc_iv_key; diff --git a/tests/set4.rs b/tests/set4.rs index 35c3edf..013ef38 100644 --- a/tests/set4.rs +++ b/tests/set4.rs @@ -86,3 +86,49 @@ fn problem_26 () { let ciphertext = matasano::crack_ctr_bitflipping(&encode); assert!(verify(&ciphertext[..])); } + +#[test] +fn problem_27 () { + let key = util::random_aes_128_key(); + let iv = key; + let prefix = "comment1=cooking%20MCs;userdata="; + let suffix = ";comment2=%20like%20a%20pound%20of%20bacon"; + let admin = ";admin=true;"; + + let escape = |input: &str| { + input.replace("%", "%25").replace(";", "%3B").replace("=", "%3D") + }; + + let encode = |input: &str| -> Vec { + let plaintext: Vec = prefix + .as_bytes() + .iter() + .chain(escape(input).as_bytes().iter()) + .chain(suffix.as_bytes().iter()) + .map(|x| *x) + .collect(); + return matasano::encrypt_aes_128_cbc(&plaintext[..], &key[..], &iv[..]); + }; + + let verify = |ciphertext: &[u8]| -> Result> { + let plaintext = matasano::decrypt_aes_128_cbc(ciphertext, &key[..], &iv[..]).unwrap(); + if plaintext.iter().any(|&c| c < 32 || c > 126) { + return Err(plaintext); + } + else { + println!("{}", ::std::str::from_utf8(&plaintext[..]).unwrap()); + return Ok( + (0..(plaintext.len() - admin.len())).any(|i| { + plaintext + .iter() + .skip(i) + .zip(admin.as_bytes().iter()) + .all(|(&c1, &c2)| c1 == c2) + }) + ); + } + }; + + let ciphertext = matasano::crack_cbc_iv_key(&encode, &verify); + assert!(verify(&ciphertext[..]).unwrap()); +} -- cgit v1.2.3-54-g00ecf