summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/aes.rs39
-rw-r--r--src/lib.rs1
-rw-r--r--tests/lib.rs30
3 files changed, 62 insertions, 8 deletions
diff --git a/src/aes.rs b/src/aes.rs
index c40d1c6..bc7b528 100644
--- a/src/aes.rs
+++ b/src/aes.rs
@@ -140,6 +140,23 @@ pub fn crack_padded_aes_128_ecb<F> (f: &F) -> Vec<u8> where F: Fn(&[u8]) -> Vec<
return unpad_pkcs7(&plaintext[..]).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) {
@@ -240,10 +257,15 @@ fn count_duplicate_blocks (input: &[u8], block_size: usize) -> usize {
}
fn find_block_size<F> (f: &F) -> usize where F: Fn(&[u8]) -> Vec<u8> {
- let fixed_prefix_len = find_fixed_prefix_len(f);
+ 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(&[byte]);
- let mut len = 2;
+ let mut prev = f(&[b'f']);
+ let mut len = 0;
loop {
let prefix: Vec<u8> = std::iter::repeat(byte)
.take(len)
@@ -251,11 +273,12 @@ fn find_block_size<F> (f: &F) -> usize where F: Fn(&[u8]) -> Vec<u8> {
let next = f(&prefix[..]);
let prefix_len = shared_prefix_len(
- prev.iter().skip(fixed_prefix_len),
- next.iter().skip(fixed_prefix_len)
+ prev.iter(),
+ next.iter()
);
- if prefix_len > 0 {
- return prefix_len;
+ 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;
@@ -263,7 +286,7 @@ fn find_block_size<F> (f: &F) -> usize where F: Fn(&[u8]) -> Vec<u8> {
}
}
-fn find_fixed_prefix_len<F> (f: &F) -> usize where F: Fn(&[u8]) -> Vec<u8> {
+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());
diff --git a/src/lib.rs b/src/lib.rs
index 1aa6f4c..e2d83ea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -16,6 +16,7 @@ pub use aes::encrypt_aes_128_cbc;
pub use aes::find_aes_128_ecb_encrypted_string;
pub use aes::detect_ecb_cbc;
pub use aes::crack_padded_aes_128_ecb;
+pub use aes::crack_padded_aes_128_ecb_with_prefix;
pub use aes::crack_querystring_aes_128_ecb;
pub use base64::to_base64;
pub use http::parse_query_string;
diff --git a/tests/lib.rs b/tests/lib.rs
index 3ddeae1..3f66d16 100644
--- a/tests/lib.rs
+++ b/tests/lib.rs
@@ -252,3 +252,33 @@ fn problem_13 () {
decrypter(ciphertext).map(|params| params == expected).unwrap_or(false)
}));
}
+
+#[test]
+fn problem_14 () {
+ let padding = b"Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWct\
+ dG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpU\
+ aGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBq\
+ dXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5v\
+ LCBJIGp1c3QgZHJvdmUgYnkK".from_base64().unwrap();
+ let front_padding: Vec<u8> = thread_rng()
+ .gen_iter()
+ .take(thread_rng().gen_range(1, 100))
+ .collect();
+ let fixed_padding = |input: &[u8]| -> Vec<u8> {
+ return front_padding
+ .iter()
+ .chain(input.iter())
+ .chain(padding.iter())
+ .map(|x| *x)
+ .collect()
+ };
+
+ let key = random_aes_128_key();
+ let random_encrypter = |input: &[u8]| {
+ let padded_input = fixed_padding(input);
+ return matasano::encrypt_aes_128_ecb(&padded_input[..], &key[..]);
+ };
+
+ let got = matasano::crack_padded_aes_128_ecb_with_prefix(&random_encrypter);
+ assert_eq!(got, padding);
+}