Compare commits
No commits in common. "f806cfec457fd9196c6268cc72badd1112e32ce8" and "9f86bb4b27e63640c7e4a769faaac910d9ac4d68" have entirely different histories.
f806cfec45
...
9f86bb4b27
|
@ -58,7 +58,7 @@ impl Aes {
|
||||||
Some(data.clone())
|
Some(data.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ecb(&self, data: Vec<u8>, mode: Mode) -> Option<Vec<u8>> {
|
pub fn ecb(&self, mut data: Vec<u8>, mode: Mode) -> Option<Vec<u8>> {
|
||||||
if (!self.pad) && (data.len() % Self::BLOCK_SIZE != 0) {
|
if (!self.pad) && (data.len() % Self::BLOCK_SIZE != 0) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
206
src/main.rs
206
src/main.rs
|
@ -180,7 +180,9 @@ fn q11() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let oracle = |data: &Vec<u8>| -> bool { data[16..32] == data[32..48] };
|
let oracle = |data: &Vec<u8>| -> bool {
|
||||||
|
data[16..32] == data[32..48]
|
||||||
|
};
|
||||||
|
|
||||||
for i in 0..128 {
|
for i in 0..128 {
|
||||||
let data = [0u8;64];
|
let data = [0u8;64];
|
||||||
|
@ -189,12 +191,10 @@ fn q11() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn q12() {
|
fn q12()
|
||||||
|
{
|
||||||
println!("Running q12");
|
println!("Running q12");
|
||||||
let key: Vec<u8> = rand::thread_rng()
|
let key: Vec<u8> = rand::thread_rng().sample_iter(rand::distributions::Standard).take(16).collect();
|
||||||
.sample_iter(rand::distributions::Standard)
|
|
||||||
.take(16)
|
|
||||||
.collect();
|
|
||||||
let plaintext: Vec<u8> = Bytes::from_base64("Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK").into();
|
let plaintext: Vec<u8> = Bytes::from_base64("Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK").into();
|
||||||
let aes = crate::crypto::Aes::new(&key, true).unwrap();
|
let aes = crate::crypto::Aes::new(&key, true).unwrap();
|
||||||
|
|
||||||
|
@ -204,10 +204,7 @@ fn q12() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let starting_size = blackbox(Vec::new()).len();
|
let starting_size = blackbox(Vec::new()).len();
|
||||||
let (first_increment, next_size) = (0..)
|
let (first_increment, next_size) = (0..).map(|x:usize| (x, blackbox(std::iter::repeat(0u8).take(x).collect()).len())).find(|(i,x)| *x != starting_size).unwrap();
|
||||||
.map(|x: usize| (x, blackbox(std::iter::repeat(0u8).take(x).collect()).len()))
|
|
||||||
.find(|(_, x)| *x != starting_size)
|
|
||||||
.unwrap();
|
|
||||||
let block_size = next_size - starting_size;
|
let block_size = next_size - starting_size;
|
||||||
println!(" Block size is {}", block_size);
|
println!(" Block size is {}", block_size);
|
||||||
assert!(block_size == 16);
|
assert!(block_size == 16);
|
||||||
|
@ -223,23 +220,15 @@ fn q12() {
|
||||||
let mut known: Vec<u8> = Vec::with_capacity(data_length);
|
let mut known: Vec<u8> = Vec::with_capacity(data_length);
|
||||||
println!(" Data length: {}", data_length);
|
println!(" Data length: {}", data_length);
|
||||||
|
|
||||||
for _ in 0..data_length {
|
for byte_index in 0..data_length
|
||||||
let nulls: Vec<u8> = std::iter::repeat(0u8)
|
{
|
||||||
.take(starting_size - known.len() - 1)
|
let nulls: Vec<u8> = std::iter::repeat(0u8).take(starting_size - known.len() - 1).collect();
|
||||||
.collect();
|
|
||||||
let target_block = &blackbox(nulls.clone())[0..starting_size];
|
let target_block = &blackbox(nulls.clone())[0..starting_size];
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
'byteiter: for b in 0u8..=255u8 {
|
'byteiter: for b in 0u8..=255u8 {
|
||||||
let this_block = &blackbox(
|
let this_block = &blackbox(nulls.iter().chain(known.iter()).chain(std::iter::once(&b)).cloned().take(starting_size).collect())[0..starting_size];
|
||||||
nulls
|
if this_block == target_block
|
||||||
.iter()
|
{
|
||||||
.chain(known.iter())
|
|
||||||
.chain(std::iter::once(&b))
|
|
||||||
.cloned()
|
|
||||||
.take(starting_size)
|
|
||||||
.collect(),
|
|
||||||
)[0..starting_size];
|
|
||||||
if this_block == target_block {
|
|
||||||
known.push(b);
|
known.push(b);
|
||||||
found = true;
|
found = true;
|
||||||
break 'byteiter;
|
break 'byteiter;
|
||||||
|
@ -250,172 +239,6 @@ fn q12() {
|
||||||
// println!(" {}", String::from_utf8(known).unwrap().replace("\n", "\n "));
|
// println!(" {}", String::from_utf8(known).unwrap().replace("\n", "\n "));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn q13() {
|
|
||||||
println!("Running q13");
|
|
||||||
let key: Vec<u8> = rand::thread_rng()
|
|
||||||
.sample_iter(rand::distributions::Standard)
|
|
||||||
.take(16)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let parse = |x: &str| -> std::collections::HashMap<String, String> {
|
|
||||||
let mut out = std::collections::HashMap::new();
|
|
||||||
for pair in x.split(|y| y == '&') {
|
|
||||||
let elements: Vec<&str> = pair.split(|z| z == '=').collect();
|
|
||||||
if elements.len() == 2 {
|
|
||||||
out.insert(elements[0].to_owned(), elements[1].to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out
|
|
||||||
};
|
|
||||||
|
|
||||||
let profile_for = |mail: &str| -> String {
|
|
||||||
format!(
|
|
||||||
"email={}&uid=10&role=user",
|
|
||||||
mail.replace("&", "").replace("=", "")
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let encrypt = |profile: &str| -> Vec<u8> {
|
|
||||||
let profile: Vec<u8> = profile.bytes().collect();
|
|
||||||
let aes = crypto::Aes::new(&key, true).unwrap();
|
|
||||||
aes.ecb(profile, Mode::Encrypt).unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let is_admin = |profile: Vec<u8>| -> bool {
|
|
||||||
let aes = crypto::Aes::new(&key, true).unwrap();
|
|
||||||
let profile = aes.ecb(profile, Mode::Decrypt).unwrap();
|
|
||||||
let profile = String::from_utf8(profile).unwrap();
|
|
||||||
parse(&profile)["role"] == "admin"
|
|
||||||
};
|
|
||||||
|
|
||||||
let mail1 = "a".repeat(32 - "email=".len() - "@example.com&uid=10&role=".len());
|
|
||||||
let mail1 = mail1 + "@example.com";
|
|
||||||
let part1: &[u8] = &encrypt(&profile_for(&mail1))[0..32];
|
|
||||||
let mail2 = " ".repeat(16 - "email=".len());
|
|
||||||
let mail2 = mail2 + "admin";
|
|
||||||
let padding_char = (16 - "admin".len()) as u8;
|
|
||||||
let mail2 = mail2
|
|
||||||
+ &String::from_utf8(vec![padding_char])
|
|
||||||
.unwrap()
|
|
||||||
.repeat(padding_char as usize);
|
|
||||||
let part2: &[u8] = &encrypt(&profile_for(&mail2))[16..32];
|
|
||||||
let whole: Vec<u8> = part1.iter().chain(part2.iter()).cloned().collect();
|
|
||||||
|
|
||||||
assert!(is_admin(whole));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn q14() {
|
|
||||||
println!("Running q14");
|
|
||||||
let key: Vec<u8> = rand::thread_rng()
|
|
||||||
.sample_iter(rand::distributions::Standard)
|
|
||||||
.take(16)
|
|
||||||
.collect();
|
|
||||||
let plaintext: Vec<u8> = Bytes::from_base64("Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK").into();
|
|
||||||
let aes = crate::crypto::Aes::new(&key, true).unwrap();
|
|
||||||
let prefix: Vec<u8> = rand::thread_rng()
|
|
||||||
.sample_iter(rand::distributions::Standard)
|
|
||||||
.take(rand::thread_rng().gen_range(5, 11))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let blackbox = |mut attacker_data: Vec<u8>| -> Vec<u8> {
|
|
||||||
let mut data: Vec<u8> = prefix.clone();
|
|
||||||
data.append(&mut attacker_data);
|
|
||||||
data.append(&mut plaintext.clone());
|
|
||||||
let rv = aes.ecb(data, Mode::Encrypt).unwrap();
|
|
||||||
rv
|
|
||||||
};
|
|
||||||
|
|
||||||
let starting_size = blackbox(Vec::new()).len();
|
|
||||||
let (first_increment, next_size) = (0..)
|
|
||||||
.map(|x: usize| (x, blackbox(std::iter::repeat(0u8).take(x).collect()).len()))
|
|
||||||
.find(|(_, x)| *x != starting_size)
|
|
||||||
.unwrap();
|
|
||||||
println!(" First size increment at {}", first_increment);
|
|
||||||
|
|
||||||
let block_size = next_size - starting_size;
|
|
||||||
println!(" Block size is {}", block_size);
|
|
||||||
assert!(block_size == 16);
|
|
||||||
|
|
||||||
let long_block = blackbox(std::iter::repeat(0u8).take(1280).collect());
|
|
||||||
let using_ecb = long_block[480..496] == long_block[496..512];
|
|
||||||
println!(" Using ECB: {}", using_ecb);
|
|
||||||
assert!(using_ecb);
|
|
||||||
|
|
||||||
let all_zero_ciphertext = blackbox(std::iter::repeat(0u8).take(block_size).collect());
|
|
||||||
let first_different_block = |x: usize| -> usize {
|
|
||||||
let data: Vec<u8> = std::iter::repeat(0u8)
|
|
||||||
.take(x)
|
|
||||||
.chain(std::iter::once(1u8))
|
|
||||||
.chain(std::iter::repeat(0u8).take(block_size - 1 - x))
|
|
||||||
.collect();
|
|
||||||
let data: Vec<u8> = blackbox(data);
|
|
||||||
data.chunks_exact(block_size)
|
|
||||||
.zip(all_zero_ciphertext.chunks_exact(block_size))
|
|
||||||
.enumerate()
|
|
||||||
.find(|(_, (a, b))| a != b)
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
};
|
|
||||||
let start_block = first_different_block(0);
|
|
||||||
let mut prefix_size = start_block * block_size + block_size - 1;
|
|
||||||
for i in 2..block_size {
|
|
||||||
let diff_block = first_different_block(i);
|
|
||||||
if diff_block == start_block {
|
|
||||||
prefix_size = start_block * block_size + block_size - 1 - i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println!(" Prefix length is {}", prefix_size);
|
|
||||||
assert!(prefix_size == prefix.len());
|
|
||||||
|
|
||||||
let data_length = starting_size - first_increment - prefix_size;
|
|
||||||
let mut known: Vec<u8> = Vec::with_capacity(data_length);
|
|
||||||
println!(" Data length: {}", data_length);
|
|
||||||
assert!(data_length == plaintext.len());
|
|
||||||
|
|
||||||
let prefix_total = (prefix_size + block_size - 1) / block_size * block_size;
|
|
||||||
let prefix_nulls = prefix_total - prefix_size;
|
|
||||||
let starting_size = (prefix_total + data_length + block_size - 1) / block_size * block_size;
|
|
||||||
|
|
||||||
for _ in 0..data_length {
|
|
||||||
let nulls: Vec<u8> = std::iter::repeat(0u8)
|
|
||||||
.take(starting_size - prefix_size - known.len() - 1)
|
|
||||||
.collect();
|
|
||||||
let target_block = &blackbox(nulls.clone())[prefix_total..starting_size];
|
|
||||||
let mut found = false;
|
|
||||||
'byteiter: for b in 0u8..=255u8 {
|
|
||||||
let this_block = &blackbox(
|
|
||||||
nulls
|
|
||||||
.iter()
|
|
||||||
.chain(known.iter())
|
|
||||||
.chain(std::iter::once(&b))
|
|
||||||
.cloned()
|
|
||||||
.take(starting_size)
|
|
||||||
.collect(),
|
|
||||||
)[prefix_total..starting_size];
|
|
||||||
if this_block == target_block {
|
|
||||||
known.push(b);
|
|
||||||
found = true;
|
|
||||||
break 'byteiter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert!(found);
|
|
||||||
}
|
|
||||||
assert!(known == plaintext);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn q15() {
|
|
||||||
println!("Running q15");
|
|
||||||
let input = b"ICE ICE BABY\x05\x05\x05\x05";
|
|
||||||
let output = Bytes::from(&input[..]);
|
|
||||||
let output = output.unpad();
|
|
||||||
assert!(output == None);
|
|
||||||
|
|
||||||
let input = b"ICE ICE BABY\x04\x04\x04\x04";
|
|
||||||
let output = Bytes::from(&input[..]);
|
|
||||||
let output = output.unpad().unwrap();
|
|
||||||
assert!(output.to_string().unwrap() == "ICE ICE BABY");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
q01();
|
q01();
|
||||||
q02();
|
q02();
|
||||||
|
@ -429,7 +252,4 @@ fn main() {
|
||||||
q10();
|
q10();
|
||||||
q11();
|
q11();
|
||||||
q12();
|
q12();
|
||||||
q13();
|
|
||||||
q14();
|
|
||||||
q15();
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user