summaryrefslogtreecommitdiffstats
path: root/src/aes.rs
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2015-03-28 03:37:58 -0400
committerJesse Luehrs <doy@tozt.net>2015-03-28 03:37:58 -0400
commit301a4e5cdf5d206edc63f2bb632d1e0f0d4cc7f6 (patch)
tree85714f9d3ce0d1d4d7aeb2381f96aab5ae6b2ad2 /src/aes.rs
parent1505a949589b17837319a292a07e1c15ed9296e4 (diff)
downloadmatasano-301a4e5cdf5d206edc63f2bb632d1e0f0d4cc7f6.tar.gz
matasano-301a4e5cdf5d206edc63f2bb632d1e0f0d4cc7f6.zip
reorganize
Diffstat (limited to 'src/aes.rs')
-rw-r--r--src/aes.rs289
1 files changed, 0 insertions, 289 deletions
diff --git a/src/aes.rs b/src/aes.rs
index 0d262cb..77cbf7a 100644
--- a/src/aes.rs
+++ b/src/aes.rs
@@ -1,17 +1,7 @@
-use std;
-use std::borrow::ToOwned;
-use std::collections::{HashMap, 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]) -> Option<Vec<u8>> {
// openssl already doesn't return differentiable results for invalid
// padding, so we can't either
@@ -63,285 +53,6 @@ pub fn encrypt_aes_128_cbc (bytes: &[u8], key: &[u8], iv: &[u8]) -> Vec<u8> {
return ciphertext;
}
-pub fn find_aes_128_ecb_encrypted_string (inputs: &[Vec<u8>]) -> Vec<u8> {
- let mut max_dups = 0;
- let mut found = vec![];
- for input in inputs {
- let dups = count_duplicate_blocks(input, 16);
- if dups > max_dups {
- max_dups = dups;
- found = input.clone();
- }
- }
- return found;
-}
-
-pub fn detect_ecb_cbc<F> (f: &F, block_size: usize) -> BlockCipherMode where F: Fn(&[u8]) -> Vec<u8> {
- if block_size >= std::u8::MAX as usize {
- panic!("invalid block size: {}", block_size);
- }
- let block_size_byte = block_size as u8;
- let plaintext: Vec<u8> = (0..block_size_byte)
- .cycle()
- .take(block_size * 2)
- .flat_map(|n| std::iter::repeat(n).take(block_size + 1))
- .collect();
- let ciphertext = f(&plaintext[..]);
-
- if count_duplicate_blocks(&ciphertext[..], block_size) >= block_size {
- return BlockCipherMode::ECB;
- }
- else {
- return BlockCipherMode::CBC;
- }
-}
-
-pub fn crack_padded_aes_128_ecb<F> (f: &F) -> Vec<u8> where F: Fn(&[u8]) -> Vec<u8> {
- let block_size = find_block_size(f);
- if detect_ecb_cbc(f, block_size) != BlockCipherMode::ECB {
- panic!("Can only crack ECB-encrypted data");
- }
-
- let mut plaintext = vec![];
-
- let get_block = |input: &[u8], i| {
- let encrypted = f(input);
- let block_number = i / block_size;
- let low = block_number * block_size;
- let high = (block_number + 1) * block_size;
- encrypted[low..high].to_vec()
- };
-
- let mut i = 0;
- loop {
- let mut map = HashMap::new();
-
- let prefix: Vec<u8> = std::iter::repeat(b'A')
- .take(block_size - ((i % block_size) + 1))
- .collect();
- for c in 0..256 {
- let mut prefix_with_next_char = prefix.clone();
- for &c in plaintext.iter() {
- prefix_with_next_char.push(c);
- }
- prefix_with_next_char.push(c as u8);
- map.insert(get_block(&prefix_with_next_char[..], i), c as u8);
- }
-
- let next_char = map.get(&get_block(&prefix[..], i));
- if next_char.is_some() {
- plaintext.push(*next_char.unwrap());
- }
- else {
- break;
- }
-
- i += 1;
- }
-
- return unpad_pkcs7(&plaintext[..]).expect("invalid padding").to_vec();
-}
-
-pub fn crack_padded_aes_128_ecb_with_prefix<F> (f: &F) -> Vec<u8> where F: Fn(&[u8]) -> Vec<u8> {
- let (block_size, prefix_len) = find_block_size_and_fixed_prefix_len(f);
- let wrapped_f = |input: &[u8]| {
- let alignment_padding = block_size - (prefix_len % block_size);
- let padded_input: Vec<u8> = std::iter::repeat(b'A')
- .take(alignment_padding)
- .chain(input.iter().map(|x| *x))
- .collect();
- return f(&padded_input[..])
- .iter()
- .skip(prefix_len + alignment_padding)
- .map(|x| *x)
- .collect();
- };
- return crack_padded_aes_128_ecb(&wrapped_f);
-}
-
-pub fn crack_querystring_aes_128_ecb<F> (encrypter: &F) -> (String, Vec<Vec<u8>>) where F: Fn(&str) -> Vec<u8> {
- fn incr_map_element (map: &mut HashMap<Vec<u8>, usize>, key: Vec<u8>) {
- if let Some(val) = map.get_mut(&key) {
- *val += 1;
- return;
- }
- map.insert(key, 1);
- };
-
- // find blocks that correspond to "uid=10&role=user" or "role=user&uid=10"
- let find_uid_role_blocks = || {
- let mut map = HashMap::new();
- for c in 32..127 {
- let email_bytes: Vec<u8> = std::iter::repeat(c).take(9).collect();
- let email = std::str::from_utf8(&email_bytes[..]).unwrap();
- let ciphertext = encrypter(email);
- incr_map_element(&mut map, ciphertext[..16].to_vec());
- incr_map_element(&mut map, ciphertext[16..32].to_vec());
- }
-
- let mut most_common_blocks = vec![];
- for (k, v) in map {
- most_common_blocks.push((k, v));
- if most_common_blocks.len() > 2 {
- let (idx, _) = most_common_blocks
- .iter()
- .enumerate()
- .fold(
- (0, (vec![], 10000)),
- |(aidx, (ablock, acount)), (idx, &(ref block, count))| {
- if count < acount {
- (idx, (block.clone(), count))
- }
- else {
- (aidx, (ablock.clone(), acount))
- }
- }
- );
- most_common_blocks.swap_remove(idx);
- }
- }
-
- if let [(ref block1, _), (ref block2, _)] = &most_common_blocks[..] {
- return (block1.clone(), block2.clone());
- }
- else {
- panic!("couldn't find most common blocks");
- }
- };
-
- // encrypt:
- // email=..........admin<pcks7 padding>...............&uid=10&role=user
- let calculate_admin_block = |block1, block2| {
- for _ in 0..1000 {
- let email = "blorg@bar.admin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b...............";
- let ciphertext = encrypter(email);
- if &ciphertext[48..64] == block1 || &ciphertext[48..64] == block2 {
- return ciphertext[16..32].to_vec();
- }
- }
- panic!("couldn't find a ciphertext with the correct role/uid block");
- };
-
- // find all possible encryptions with email=............ and then replace
- // the last block with the padded admin block above
- let calculate_possible_admin_ciphertexts = |admin_block: Vec<u8>| {
- let email = "blorg@bar.com";
- let mut possibles = vec![];
- while possibles.len() < 6 {
- let ciphertext = encrypter(email);
- let modified_ciphertext = ciphertext
- .iter()
- .take(32)
- .chain(admin_block.iter())
- .map(|x| *x)
- .collect();
- if !possibles.iter().any(|possible| possible == &modified_ciphertext) {
- possibles.push(modified_ciphertext);
- }
- }
- return (email.to_owned(), possibles);
- };
-
- let (block1, block2) = find_uid_role_blocks();
- let admin_block = calculate_admin_block(block1, block2);
- return calculate_possible_admin_ciphertexts(admin_block);
-}
-
-pub fn crack_cbc_bitflipping<F> (f: &F) -> Vec<u8> where F: Fn(&str) -> Vec<u8> {
- let mut ciphertext = f("AAAAAAAAAAAAAAAA:admin<true:AAAA");
- ciphertext[32] = ciphertext[32] ^ 0x01;
- ciphertext[38] = ciphertext[38] ^ 0x01;
- ciphertext[43] = ciphertext[43] ^ 0x01;
- return ciphertext;
-}
-
-pub fn crack_cbc_padding_oracle<F> (iv: &[u8], ciphertext: &[u8], f: &F) -> Vec<u8> where F: Fn(&[u8], &[u8]) -> bool {
- let mut prev = iv;
- let mut plaintext = vec![];
- for block in ciphertext.chunks(16) {
- let mut plaintext_block = vec![];
- 'BYTE: for byte in 0..16u8 {
- for c_int in 0..256 {
- let c = (255 - c_int) as u8;
- let offset = (16 - byte - 1) as usize;
- let mut iv: Vec<u8> = prev
- .iter()
- .take(offset)
- .map(|x| *x)
- .collect();
- iv.push(prev[offset] ^ c ^ (byte + 1));
- for i in 0..(byte as usize) {
- iv.push(prev[offset + i + 1] ^ plaintext_block[i] ^ (byte + 1));
- }
- if f(&iv[..], block) {
- plaintext_block.insert(0, c);
- continue 'BYTE;
- }
- }
- panic!("no byte found! ({})", byte);
- }
- for c in plaintext_block {
- plaintext.push(c);
- }
- prev = block;
- }
- return unpad_pkcs7(&plaintext[..]).unwrap().to_vec();
-}
-
-fn count_duplicate_blocks (input: &[u8], block_size: usize) -> usize {
- let mut set = HashSet::new();
- let mut dups = 0;
- for block in input.chunks(block_size) {
- if !set.insert(block) {
- dups += 1;
- }
- }
- return dups;
-}
-
-fn find_block_size<F> (f: &F) -> usize where F: Fn(&[u8]) -> Vec<u8> {
- let (block_size, _) = find_block_size_and_fixed_prefix_len(f);
- return block_size;
-}
-
-fn find_block_size_and_fixed_prefix_len<F> (f: &F) -> (usize, usize) where F: Fn(&[u8]) -> Vec<u8> {
- let fixed_prefix_len = find_fixed_block_prefix_len(f);
- let byte = b'A';
- let mut prev = f(&[b'f']);
- let mut len = 0;
- loop {
- let prefix: Vec<u8> = std::iter::repeat(byte)
- .take(len)
- .collect();
- let next = f(&prefix[..]);
-
- let prefix_len = shared_prefix_len(
- prev.iter(),
- next.iter()
- );
- if prefix_len > fixed_prefix_len {
- let block_size = prefix_len - fixed_prefix_len;
- return (block_size, fixed_prefix_len + block_size - (len - 1));
- }
-
- prev = next;
- len += 1;
- }
-}
-
-fn find_fixed_block_prefix_len<F> (f: &F) -> usize where F: Fn(&[u8]) -> Vec<u8> {
- let ciphertext1 = f(b"");
- let ciphertext2 = f(b"A");
- return shared_prefix_len(ciphertext1.iter(), ciphertext2.iter());
-}
-
-fn shared_prefix_len<I> (i1: I, i2: I) -> usize where I: Iterator, <I as Iterator>::Item: PartialEq {
- return i1
- .zip(i2)
- .take_while(|&(ref c1, ref c2)| { c1 == c2 })
- .count();
-}
-
#[test]
fn test_encrypt_decrypt () {
let plaintext = b"Summertime and the wind is blowing outside in lower \