From 52222e90e9cafb8d74e40cec79eabba5417d7c48 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Thu, 23 Jun 2022 09:46:31 -0400 Subject: [PATCH] Start work on challenge 14. --- src/main.rs | 11 +++++----- src/set2.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 88442d6..00fdcda 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,9 +15,10 @@ fn main() { // set1::challenge6(); // set1::challenge7(); // set1::challenge8(); - set2::challenge9(); - set2::challenge10(); - set2::challenge11(); - set2::challenge12(); - set2::challenge13(); + // set2::challenge9(); + // set2::challenge10(); + // set2::challenge11(); + // set2::challenge12(); + // set2::challenge13(); + set2::challenge14(); } diff --git a/src/set2.rs b/src/set2.rs index ae9b19d..3c1c4f5 100644 --- a/src/set2.rs +++ b/src/set2.rs @@ -221,7 +221,7 @@ pub fn challenge13() { // "valid" ciphertexts) and the ciphertexts themselves, make a // role=admin profile. // (FelixM) I assume ECB and block_size = 16; we could figure - // it out easily my adding enough 'a' to the email + // it out easily by adding enough 'a' to the email let mut r = vec![]; // ________________________________ @@ -250,9 +250,61 @@ pub fn challenge13() { let dict = decrypt(&key, &profile); let role = dict.get("role").unwrap(); assert_eq!(role, "admin"); - println!("[done] Challenge 13: role={}", role); + println!("[okay] Challenge 13: role={}", role); } pub fn challenge14() { - println!("[xxxx] Challenge 14:"); + fn read(path: &str) -> Bytes { + let s = std::fs::read_to_string(path).unwrap(); + BytesBase64::from_base64(&s).to_bytes() + } + + fn encryption_oracle( + Bytes(random_prefix): &Bytes, + random_key: &Bytes, + Bytes(attacker_controlled): &Bytes, + ) -> Bytes { + // AES-128-ECB(random-prefix || attacker-controlled || target-bytes, random-key) + // Thoughts: If I generate a random prefix for every encryption, then I don't + // know how to decode it because I cannot really run experiments. If I generate + // a single random prefix it becomes rather trivial. I just have to find out how + // long it is and then adjust the decoding routine. + let mut plaintext = random_prefix.to_vec(); + plaintext.append(&mut attacker_controlled.to_vec()); + let mut target_bytes = read("data/12.txt").0; + plaintext.append(&mut target_bytes); + let cipher = ecb::encrypt(&random_key, &Bytes(plaintext)); + cipher + } + + fn get_block_size(prefix: &Bytes, key: &Bytes) -> usize { + // Detect cipher block size this approach also confirms that it is ECB + let v = vec![b'a'; 256]; + let cipher = encryption_oracle(prefix, key, &Bytes(v)); + + for i in 1..10 { + let block_size = i * 16; + let chunks: Vec<&[u8]> = cipher.0.chunks(block_size).collect(); + for i in 0..chunks.len() { + for j in (i + 1)..chunks.len() { + if chunks[i] == chunks[j] { + return block_size; + } + } + } + } + 0 + } + + let prefix = Bytes::random_range(0, 200); + let key = Bytes::random(16); // consistent but unknown key + assert_eq!(get_block_size(&prefix, &key), 16); + let _clear_text = read("data/12.txt"); + + // AES-128-ECB(random-prefix || attacker-controlled || target-bytes, random-key) + // rrrrrrrrrrrrrrrrrrraaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaathe real text + // 0..34..78..bc..f0..34..78..bc..f0..34..78..bc..f0..34..78..bc..f0..34..78..bc..f + // 0 1 2 4 5 + + println!("[xxxx] Challenge 14: {}", get_block_size(&prefix, &key)); }