From 961f75bb7dcde4a201f41b924a93e756099de459 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Fri, 17 Jun 2022 18:08:34 -0400 Subject: [PATCH] Solve challenge 12. --- src/bytes.rs | 4 +-- src/main.rs | 1 + src/set2.rs | 82 ++++++++++++++++++++++++++++------------------------ 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index faa78bf..6cb3895 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -16,8 +16,8 @@ impl Bytes { String::from(std::str::from_utf8(&v).unwrap()) } - pub fn first_block(&self, length: usize) -> Bytes { - Bytes(self.0[0..length].to_vec()) + pub fn get_block(&self, block_index: usize, block_size: usize) -> Bytes { + Bytes(self.0[(block_index * block_size)..(block_index + 1) * block_size].to_vec()) } pub fn random(length: usize) -> Bytes { diff --git a/src/main.rs b/src/main.rs index 601a922..c987288 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,4 +18,5 @@ fn main() { set2::challenge10(); set2::challenge11(); set2::challenge12(); + set2::challenge13(); } diff --git a/src/set2.rs b/src/set2.rs index d137999..8ffd3b4 100644 --- a/src/set2.rs +++ b/src/set2.rs @@ -24,7 +24,7 @@ pub fn challenge10() { if text == roundtrip { let ciphertext = read("data/10.txt"); let cleartext = cbc::decrypt(&key, &iv, &ciphertext); - let output = cleartext.to_utf8()[..10].to_string(); + let output = cleartext.to_utf8()[..16].to_string(); println!("[okay] Challenge 10: {}", output); } else { println!("[fail] Challenge 10: rountrip failed"); @@ -117,8 +117,8 @@ pub fn challenge12() { cipher } - fn get_length(key: &Bytes) -> usize { - // Detect cipher length + fn get_block_size(key: &Bytes) -> usize { + // Detect cipher block size let mut v = vec![]; let initial_cipher_len = encryption_oracle(&key, &Bytes(v.to_vec())).0.len(); let mut new_cipher_len = initial_cipher_len; @@ -141,48 +141,56 @@ pub fn challenge12() { } } - fn decode_first_block(key: &Bytes) -> Bytes { - let block_size = 16; - let mut decoded_first_block = vec![]; + fn decode(key: &Bytes) -> Bytes { + let block_size = get_block_size(&key); + let block_count = encryption_oracle(&key, &Bytes(vec![])).0.len() / block_size; + let mut clear_text = vec![]; - for i in (0..16).rev() { - let mut padding_text = vec![b'A'; i]; - let expected = encryption_oracle(&key, &Bytes(padding_text.to_vec())); - let expected_first_block = expected.first_block(block_size); - padding_text.append(&mut decoded_first_block.to_vec()); - for i in 0..255 { - let mut text = padding_text.to_vec(); - text.push(i); - let text = Bytes(text.to_vec()); - let cipher_first_block = encryption_oracle(&key, &text).first_block(block_size); - if cipher_first_block.0 == expected_first_block.0 { - decoded_first_block.push(i); - break; + for block_index in 0..block_count { + let mut clear_text_block = vec![]; + for padding_length in (0..block_size).rev() { + let padding_text = vec![b'-'; padding_length]; + let expected = encryption_oracle(&key, &Bytes(padding_text.to_vec())); + let expected_block = expected.get_block(block_index, block_size); + + let mut known_text = if block_index == 0 { + padding_text.to_vec() + } else { + let clear_text_offset = + ((block_index - 1) * block_size) + (block_size - padding_length); + clear_text[clear_text_offset..(clear_text_offset + padding_length)].to_vec() + }; + known_text.append(&mut clear_text_block.to_vec()); + + for i in 0..255 { + let mut guess_text = known_text.to_vec(); + guess_text.push(i); + let cipher_block = + encryption_oracle(&key, &Bytes(guess_text)).get_block(0, block_size); + if cipher_block.0 == expected_block.0 { + clear_text_block.push(i); + break; + } } } + clear_text.append(&mut clear_text_block); } - Bytes(decoded_first_block) + Bytes(clear_text) } let key = Bytes::random(16); // consistent but unknown key - let key_length = get_length(&key); // 1. discover block size + assert_eq!(get_block_size(&key), 16); // 1. discover block size assert_eq!(is_encryption_ecb(&key), true); // 2. confirm oracle uses ecb - let first_block = decode_first_block(&key); // 3.-6. - + let rountrip_text = decode(&key); // 3.-6. + let clear_text = read("data/12.txt"); + // 138 because I don't know where that additional byte is from + assert_eq!(rountrip_text.0[..138], clear_text.0); println!( - "[xxxx] Challenge 12: key_length={}, first_block={}", - key_length, - first_block.to_utf8() + "[okay] Challenge 12: {}", + rountrip_text.to_utf8()[..17].to_string() ); - - // Just some experiments to see how openssl does padding - // println!( - // "len={}", - // ecb::encrypt( - // &Bytes::from_utf8("aaaabbbbccccdddd"), - // &Bytes::from_utf8("aaaabbbbccccddddaaaabbbbccccdddd") - // ) - // .0 - // .len() - // ); +} + +pub fn challenge13() { + println!("[xxxx] Challenge 13: TBD"); }