use rand::Rng; use std::io::Read; mod util; #[test] fn problem_25() { let key = util::random_aes_128_key(); let nonce: u64 = rand::thread_rng().gen(); let plaintext = util::read("data/25.txt"); let ciphertext = matasano::aes_128_ctr(&plaintext[..], &key[..], nonce); let edit = |ciphertext: &[u8], offset: usize, newtext: &[u8]| { let block_start_number = offset / 16; let block_start = block_start_number * 16; let block_end_number = (offset + newtext.len() - 1) / 16; let block_end = std::cmp::min((block_end_number + 1) * 16, ciphertext.len()); let mut plaintext = matasano::aes_128_ctr_with_counter( &ciphertext[block_start..block_end], &key[..], nonce, (offset / 16) as u64, ); for i in 0..newtext.len() { plaintext[offset - block_start + i] = newtext[i]; } let new_ciphertext = matasano::aes_128_ctr_with_counter( &plaintext[..], &key[..], nonce, (offset / 16) as u64, ); return ciphertext .iter() .take(block_start) .chain(new_ciphertext.iter()) .chain(ciphertext.iter().skip(block_end)) .map(|x| *x) .collect(); }; let got = matasano::crack_aes_128_ctr_random_access(&ciphertext[..], edit); assert_eq!(&got[..], &plaintext[..]); } #[test] fn problem_26() { let key = util::random_aes_128_key(); let nonce = rand::thread_rng().gen(); 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::aes_128_ctr(&plaintext[..], &key[..], nonce); }; let verify = |ciphertext: &[u8]| -> bool { let plaintext = matasano::aes_128_ctr(ciphertext, &key[..], nonce); return (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_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 { 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()); } // problem 28 is just matasano::sha1_mac #[test] fn problem_29() { let key: Vec = rand::thread_rng() .sample_iter(&rand::distributions::Standard) .take(::rand::thread_rng().gen_range(5, 25)) .collect(); let valid_input = b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon"; let valid_mac = matasano::sha1_mac(valid_input, &key[..]); let possibles = matasano::crack_sha1_mac_length_extension( valid_input, valid_mac, b";admin=true", ); assert!(possibles .iter() .all(|&(ref input, _)| input.ends_with(b";admin=true"))); assert!(possibles.iter().any( |&(ref input, ref mac)| &matasano::sha1_mac(&input[..], &key[..])[..] == &mac[..] )); } #[test] fn problem_30() { let key: Vec = rand::thread_rng() .sample_iter(&rand::distributions::Standard) .take(::rand::thread_rng().gen_range(5, 25)) .collect(); let valid_input = b"comment1=cooking%20MCs;userdata=foo;comment2=%20like%20a%20pound%20of%20bacon"; let valid_mac = matasano::md4_mac(valid_input, &key[..]); let possibles = matasano::crack_md4_mac_length_extension( valid_input, valid_mac, b";admin=true", ); assert!(possibles .iter() .all(|&(ref input, _)| input.ends_with(b";admin=true"))); assert!(possibles.iter().any( |&(ref input, ref mac)| &matasano::md4_mac(&input[..], &key[..])[..] == &mac[..] )); } // ignored because this takes ~40 minutes #[test] #[ignore] fn problem_31() { let exe_path = std::env::current_exe().unwrap(); let exe_dir = exe_path.parent().unwrap().parent().unwrap(); let server_bin = exe_dir.join("timing_attack"); let (ready_w, ready_r) = std::sync::mpsc::channel(); let (kill_w, kill_r) = std::sync::mpsc::channel(); std::thread::spawn(move || { let mut child = std::process::Command::new(server_bin) .args(&["50"]) .stdout(std::process::Stdio::piped()) .spawn() .unwrap(); let mut key = [0u8; 32]; let _ = child.stdout.as_mut().unwrap().read_exact(&mut key); ready_w.send(key).unwrap(); let _ = kill_r.recv(); child.kill().unwrap(); child.wait().unwrap(); }); let key = hex::decode(ready_r.recv().unwrap()).unwrap(); let file = "filename.txt"; let got = matasano::crack_hmac_timing_basic(file, |guess| { let mut params = std::collections::HashMap::new(); params.insert("file", file.to_string()); params.insert("signature", guess.to_string()); let res = reqwest::get(&format!( "{}{}", "http://localhost:9000/?", matasano::create_query_string(¶ms) )) .unwrap(); let status = res.status(); status.is_success() }); let expected = matasano::sha1_hmac(file.as_bytes(), &key); assert_eq!(got, expected); kill_w.send(()).unwrap(); } // ignored because this takes ~18 hours #[test] #[ignore] fn problem_32() { let exe_path = std::env::current_exe().unwrap(); let exe_dir = exe_path.parent().unwrap().parent().unwrap(); let server_bin = exe_dir.join("timing_attack"); let (ready_w, ready_r) = std::sync::mpsc::channel(); let (kill_w, kill_r) = std::sync::mpsc::channel(); std::thread::spawn(move || { let mut child = std::process::Command::new(server_bin) .args(&["5"]) .stdout(std::process::Stdio::piped()) .spawn() .unwrap(); let mut key = [0u8; 32]; let _ = child.stdout.as_mut().unwrap().read_exact(&mut key); ready_w.send(key).unwrap(); let _ = kill_r.recv(); child.kill().unwrap(); child.wait().unwrap(); }); let key = hex::decode(ready_r.recv().unwrap()).unwrap(); let file = "filename.txt"; let got = matasano::crack_hmac_timing_advanced(file, |uri| { let res = reqwest::get(uri).unwrap(); res.status().is_success() }); let expected = matasano::sha1_hmac(file.as_bytes(), &key); assert_eq!(got, expected); kill_w.send(()).unwrap(); }