-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cleanup and preparation for challenge 13
- Loading branch information
1 parent
ae86842
commit 020e5db
Showing
6 changed files
with
243 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use crate::aes; | ||
|
||
pub fn aes_oracle() -> (BlockCipherMode, BlockCipherMode) { | ||
let plaintext = vec![b'A'; 16 * 6]; | ||
let (ciphertext, mode) = encrypt_aes_cbc_or_ecb(&plaintext); | ||
|
||
// If the encryption function is using ECB, there will be at least | ||
// 4 repeated blocks | ||
if aes::count_repetitions(&ciphertext) >= 4 { | ||
(BlockCipherMode::ECB, mode) | ||
} else { | ||
(BlockCipherMode::CBC, mode) | ||
} | ||
} | ||
|
||
#[derive(Debug, PartialEq, Eq)] | ||
pub enum BlockCipherMode { | ||
ECB, | ||
CBC | ||
} | ||
|
||
fn encrypt_aes_cbc_or_ecb(plaintext: &[u8]) -> (Vec<u8>, BlockCipherMode) { | ||
use rand::{RngCore, Rng}; | ||
|
||
// Generate random key | ||
let mut key = vec![0; 16]; | ||
let mut rng = rand::thread_rng(); | ||
rng.fill_bytes(&mut key); | ||
|
||
// Modify the plaintext | ||
let prepend_count: usize = rng.gen_range(5, 11); | ||
let mut prepend_bytes = vec![0; prepend_count]; | ||
rng.fill_bytes(&mut prepend_bytes); | ||
|
||
let append_count: usize = rng.gen_range(5, 11); | ||
let mut append_bytes = vec![0; append_count]; | ||
rng.fill_bytes(&mut append_bytes); | ||
|
||
let mut new_plaintext = prepend_bytes; | ||
new_plaintext.extend_from_slice(plaintext); | ||
new_plaintext.extend_from_slice(&append_bytes); | ||
|
||
// Encrypt! | ||
if rng.gen_bool(0.5) { | ||
// CBC | ||
let mut iv = vec![0; 16]; | ||
rng.fill_bytes(&mut iv); | ||
(aes::encrypt_aes_cbc(&new_plaintext, &key, &iv), BlockCipherMode::CBC) | ||
} else { | ||
// ECB | ||
(aes::encrypt_aes_ecb(&new_plaintext, &key), BlockCipherMode::ECB) | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_detect_aes_ecb() { | ||
for _ in 0..20 { | ||
let (detected, real) = aes_oracle(); | ||
assert_eq!(detected, real); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
use crate::aes; | ||
|
||
pub fn break_aes_ecb() -> Vec<u8> { | ||
// Set up a random key | ||
use rand::RngCore; | ||
let mut random_key = vec![0; 16]; | ||
rand::thread_rng().fill_bytes(&mut random_key); | ||
|
||
let (block_size, padding_bytes) = aes::detect_block_size_and_padding_bytes( | ||
|bytes| encrypt_aes_ecb_with_appendix(bytes, &random_key) | ||
); | ||
|
||
assert_eq!(block_size, 16); // Sanity check | ||
|
||
// Detect that this is indeed a case of ECB | ||
if !aes::is_ecb( | ||
|bytes| encrypt_aes_ecb_with_appendix(bytes, &random_key), | ||
block_size) { | ||
panic!("Not ECB!"); | ||
} | ||
|
||
// Find the length of the secret text | ||
let secret_text = encrypt_aes_ecb_with_appendix(b"", &random_key); | ||
let secret_text_len = secret_text.len() - padding_bytes; | ||
let input_len = secret_text_len + padding_bytes; | ||
|
||
assert!(input_len % block_size == 0); | ||
|
||
let mut discovered_bytes = Vec::new(); | ||
while discovered_bytes.len() < secret_text_len { | ||
// Find all combinations for the last char | ||
let mut input = vec![0; input_len - discovered_bytes.len() - 1]; | ||
input.extend_from_slice(&discovered_bytes); | ||
input.push(0); | ||
|
||
let mut map = std::collections::HashMap::new(); | ||
for x in 0..=255 { | ||
input[input_len - 1] = x; | ||
let encrypted = encrypt_aes_ecb_with_appendix(&input, &random_key); | ||
|
||
let block = encrypted[input_len - block_size..input_len].to_owned(); | ||
assert_eq!(block.len(), block_size); // Sanity check | ||
map.insert(block, x); | ||
} | ||
|
||
// Craft an input block that allows an undiscovered byte to be included in the block | ||
let input = vec![0; input_len - discovered_bytes.len() - 1]; | ||
let encrypted = encrypt_aes_ecb_with_appendix(&input, &random_key); | ||
let discovered_byte = map[&encrypted[input_len - block_size..input_len]]; | ||
discovered_bytes.push(discovered_byte); | ||
} | ||
|
||
discovered_bytes | ||
} | ||
|
||
pub fn encrypt_aes_ecb_with_appendix(plaintext: &[u8], key: &[u8]) -> Vec<u8> { | ||
let mut plaintext = plaintext.to_owned(); | ||
let appendix = crate::base64::decode(b"Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK"); | ||
plaintext.extend_from_slice(&appendix); | ||
|
||
aes::encrypt_aes_ecb(&plaintext, key) | ||
} | ||
|
||
#[test] | ||
fn test_break_aes_ecb() { | ||
let secret = break_aes_ecb(); | ||
let expected = crate::base64::decode(b"Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK"); | ||
assert_eq!(secret, expected) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use crate::aes; | ||
use crate::profile::Profile; | ||
|
||
fn profile_ciphertext(email: String, key: &[u8]) -> Vec<u8> { | ||
let p = Profile::new(email); | ||
let plaintext = p.encode_as_string(); | ||
aes::encrypt_aes_ecb(plaintext.as_bytes(), &key) | ||
} | ||
|
||
#[test] | ||
fn ecb_cut_and_paste() { | ||
// Set up a random key | ||
use rand::RngCore; | ||
let mut random_key = vec![0; 16]; | ||
rand::thread_rng().fill_bytes(&mut random_key); | ||
|
||
let ciphertext = profile_ciphertext("user@email.com".into(), &random_key); | ||
|
||
// Do magic to create a ciphertext containing role=admin instead of role=user | ||
// Only calls to `profile_ciphertext` are allowed | ||
// Are we allowed to change the email? The wording of the challenge is a bit vague... Probably irrelevant | ||
|
||
let decrypted = aes::decrypt_aes_ecb(&ciphertext, &random_key); | ||
let decrypted_p = Profile::from_string(&String::from_utf8_lossy(&decrypted)); | ||
assert_eq!(decrypted_p.email, "user@email.com"); | ||
assert_eq!(decrypted_p.uid, 0); | ||
assert_eq!(decrypted_p.role, "admin"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.