Start with challenge 17.
This commit is contained in:
10
data/17.txt
Normal file
10
data/17.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
MDAwMDAwTm93IHRoYXQgdGhlIHBhcnR5IGlzIGp1bXBpbmc=
|
||||||
|
MDAwMDAxV2l0aCB0aGUgYmFzcyBraWNrZWQgaW4gYW5kIHRoZSBWZWdhJ3MgYXJlIHB1bXBpbic=
|
||||||
|
MDAwMDAyUXVpY2sgdG8gdGhlIHBvaW50LCB0byB0aGUgcG9pbnQsIG5vIGZha2luZw==
|
||||||
|
MDAwMDAzQ29va2luZyBNQydzIGxpa2UgYSBwb3VuZCBvZiBiYWNvbg==
|
||||||
|
MDAwMDA0QnVybmluZyAnZW0sIGlmIHlvdSBhaW4ndCBxdWljayBhbmQgbmltYmxl
|
||||||
|
MDAwMDA1SSBnbyBjcmF6eSB3aGVuIEkgaGVhciBhIGN5bWJhbA==
|
||||||
|
MDAwMDA2QW5kIGEgaGlnaCBoYXQgd2l0aCBhIHNvdXBlZCB1cCB0ZW1wbw==
|
||||||
|
MDAwMDA3SSdtIG9uIGEgcm9sbCwgaXQncyB0aW1lIHRvIGdvIHNvbG8=
|
||||||
|
MDAwMDA4b2xsaW4nIGluIG15IGZpdmUgcG9pbnQgb2g=
|
||||||
|
MDAwMDA5aXRoIG15IHJhZy10b3AgZG93biBzbyBteSBoYWlyIGNhbiBibG93
|
||||||
@@ -5,6 +5,7 @@ mod ecb;
|
|||||||
mod parser;
|
mod parser;
|
||||||
mod set1;
|
mod set1;
|
||||||
mod set2;
|
mod set2;
|
||||||
|
mod set3;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
set1::challenge1();
|
set1::challenge1();
|
||||||
@@ -23,4 +24,5 @@ fn main() {
|
|||||||
set2::challenge14();
|
set2::challenge14();
|
||||||
set2::challenge15();
|
set2::challenge15();
|
||||||
set2::challenge16();
|
set2::challenge16();
|
||||||
|
set3::challenge17();
|
||||||
}
|
}
|
||||||
|
|||||||
40
src/set2.rs
40
src/set2.rs
@@ -146,10 +146,10 @@ pub fn challenge12() {
|
|||||||
fn decode(key: &Bytes) -> Bytes {
|
fn decode(key: &Bytes) -> Bytes {
|
||||||
let block_size = get_block_size(&key);
|
let block_size = get_block_size(&key);
|
||||||
let block_count = encryption_oracle(&key, &Bytes(vec![])).0.len() / block_size;
|
let block_count = encryption_oracle(&key, &Bytes(vec![])).0.len() / block_size;
|
||||||
let mut clear_text = vec![];
|
let mut cleartext = vec![];
|
||||||
|
|
||||||
for block_index in 0..block_count {
|
for block_index in 0..block_count {
|
||||||
let mut clear_text_block = vec![];
|
let mut cleartext_block = vec![];
|
||||||
for padding_length in (0..block_size).rev() {
|
for padding_length in (0..block_size).rev() {
|
||||||
let padding_text = vec![b'-'; padding_length];
|
let padding_text = vec![b'-'; padding_length];
|
||||||
let expected = encryption_oracle(&key, &Bytes(padding_text.to_vec()));
|
let expected = encryption_oracle(&key, &Bytes(padding_text.to_vec()));
|
||||||
@@ -158,11 +158,11 @@ pub fn challenge12() {
|
|||||||
let mut known_text = if block_index == 0 {
|
let mut known_text = if block_index == 0 {
|
||||||
padding_text.to_vec()
|
padding_text.to_vec()
|
||||||
} else {
|
} else {
|
||||||
let clear_text_offset =
|
let cleartext_offset =
|
||||||
((block_index - 1) * block_size) + (block_size - padding_length);
|
((block_index - 1) * block_size) + (block_size - padding_length);
|
||||||
clear_text[clear_text_offset..(clear_text_offset + padding_length)].to_vec()
|
cleartext[cleartext_offset..(cleartext_offset + padding_length)].to_vec()
|
||||||
};
|
};
|
||||||
known_text.append(&mut clear_text_block.to_vec());
|
known_text.append(&mut cleartext_block.to_vec());
|
||||||
|
|
||||||
for i in 0..255 {
|
for i in 0..255 {
|
||||||
let mut guess_text = known_text.to_vec();
|
let mut guess_text = known_text.to_vec();
|
||||||
@@ -170,27 +170,27 @@ pub fn challenge12() {
|
|||||||
let cipher_block =
|
let cipher_block =
|
||||||
encryption_oracle(&key, &Bytes(guess_text)).get_block(0, block_size);
|
encryption_oracle(&key, &Bytes(guess_text)).get_block(0, block_size);
|
||||||
if cipher_block.0 == expected_block.0 {
|
if cipher_block.0 == expected_block.0 {
|
||||||
clear_text_block.push(i);
|
cleartext_block.push(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clear_text.append(&mut clear_text_block);
|
cleartext.append(&mut cleartext_block);
|
||||||
}
|
}
|
||||||
Bytes(clear_text)
|
Bytes(cleartext)
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = Bytes::random(16); // consistent but unknown key
|
let key = Bytes::random(16); // consistent but unknown key
|
||||||
assert_eq!(get_block_size(&key), 16); // 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
|
assert_eq!(is_encryption_ecb(&key), true); // 2. confirm oracle uses ecb
|
||||||
let roundtrip_text = decode(&key); // 3.-6.
|
let roundtrip_text = decode(&key); // 3.-6.
|
||||||
let clear_text = read("data/12.txt");
|
let cleartext = read("data/12.txt");
|
||||||
|
|
||||||
// 138 (instead of 139); I think we get one additional byte because we guess
|
// 138 (instead of 139); I think we get one additional byte because we guess
|
||||||
// the first padding byte. The right approach would be to remove the last
|
// the first padding byte. The right approach would be to remove the last
|
||||||
// byte, encrypt it, and then compare it to the result of the encryption
|
// byte, encrypt it, and then compare it to the result of the encryption
|
||||||
// oracle, but this approach is fine too.
|
// oracle, but this approach is fine too.
|
||||||
assert_eq!(roundtrip_text.0[..138], clear_text.0);
|
assert_eq!(roundtrip_text.0[..138], cleartext.0);
|
||||||
println!(
|
println!(
|
||||||
"[okay] Challenge 12: {}",
|
"[okay] Challenge 12: {}",
|
||||||
roundtrip_text.to_utf8()[..17].to_string()
|
roundtrip_text.to_utf8()[..17].to_string()
|
||||||
@@ -331,7 +331,7 @@ pub fn challenge14() {
|
|||||||
let prefix_padding = Bytes(vec![b'a'; prefix_padding_size]);
|
let prefix_padding = Bytes(vec![b'a'; prefix_padding_size]);
|
||||||
let block_count = encryption_oracle(&prefix, &key, &prefix_padding).len() / block_size;
|
let block_count = encryption_oracle(&prefix, &key, &prefix_padding).len() / block_size;
|
||||||
let first_block_index = (prefix_size + prefix_padding_size) / block_size;
|
let first_block_index = (prefix_size + prefix_padding_size) / block_size;
|
||||||
let mut clear_text = vec![];
|
let mut cleartext = vec![];
|
||||||
|
|
||||||
// AES-128-ECB(random-prefix || attacker-controlled || target-bytes, random-key)
|
// AES-128-ECB(random-prefix || attacker-controlled || target-bytes, random-key)
|
||||||
// rrrrrrrrrrrrrrrrrrrpppppppppppppaaaaaaaaaaaaaaathe real text
|
// rrrrrrrrrrrrrrrrrrrpppppppppppppaaaaaaaaaaaaaaathe real text
|
||||||
@@ -340,7 +340,7 @@ pub fn challenge14() {
|
|||||||
// | ^ first_block_index
|
// | ^ first_block_index
|
||||||
// \ prefix_padding
|
// \ prefix_padding
|
||||||
for block_index in first_block_index..block_count {
|
for block_index in first_block_index..block_count {
|
||||||
let mut clear_text_block = vec![];
|
let mut cleartext_block = vec![];
|
||||||
for padding_length in (0..block_size).rev() {
|
for padding_length in (0..block_size).rev() {
|
||||||
let full_padding_text = vec![b'-'; prefix_padding_size + padding_length];
|
let full_padding_text = vec![b'-'; prefix_padding_size + padding_length];
|
||||||
let expected = encryption_oracle(prefix, key, &Bytes(full_padding_text.to_vec()));
|
let expected = encryption_oracle(prefix, key, &Bytes(full_padding_text.to_vec()));
|
||||||
@@ -350,15 +350,15 @@ pub fn challenge14() {
|
|||||||
full_padding_text.to_vec()
|
full_padding_text.to_vec()
|
||||||
} else {
|
} else {
|
||||||
let mut prefix_padding = vec![b'-'; prefix_padding_size];
|
let mut prefix_padding = vec![b'-'; prefix_padding_size];
|
||||||
let clear_text_offset = ((block_index - first_block_index - 1) * block_size)
|
let cleartext_offset = ((block_index - first_block_index - 1) * block_size)
|
||||||
+ (block_size - padding_length);
|
+ (block_size - padding_length);
|
||||||
prefix_padding.append(
|
prefix_padding.append(
|
||||||
&mut clear_text[clear_text_offset..(clear_text_offset + padding_length)]
|
&mut cleartext[cleartext_offset..(cleartext_offset + padding_length)]
|
||||||
.to_vec(),
|
.to_vec(),
|
||||||
);
|
);
|
||||||
prefix_padding
|
prefix_padding
|
||||||
};
|
};
|
||||||
known_text.append(&mut clear_text_block.to_vec());
|
known_text.append(&mut cleartext_block.to_vec());
|
||||||
|
|
||||||
for i in 0..255 {
|
for i in 0..255 {
|
||||||
let mut guess_text = known_text.to_vec();
|
let mut guess_text = known_text.to_vec();
|
||||||
@@ -366,15 +366,15 @@ pub fn challenge14() {
|
|||||||
let cipher_block = encryption_oracle(prefix, key, &Bytes(guess_text))
|
let cipher_block = encryption_oracle(prefix, key, &Bytes(guess_text))
|
||||||
.get_block(first_block_index, block_size);
|
.get_block(first_block_index, block_size);
|
||||||
if cipher_block.0 == expected_block.0 {
|
if cipher_block.0 == expected_block.0 {
|
||||||
clear_text_block.push(i);
|
cleartext_block.push(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clear_text.append(&mut clear_text_block);
|
cleartext.append(&mut cleartext_block);
|
||||||
}
|
}
|
||||||
// We get last byte from cbs padding so remove it.
|
// We get last byte from cbs padding so remove it.
|
||||||
Bytes(clear_text[0..(clear_text.len() - 1)].to_vec())
|
Bytes(cleartext[0..(cleartext.len() - 1)].to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefix = Bytes::random_range(0, 200);
|
let prefix = Bytes::random_range(0, 200);
|
||||||
@@ -383,8 +383,8 @@ pub fn challenge14() {
|
|||||||
let prefix_len = get_prefix_size(&prefix, &key);
|
let prefix_len = get_prefix_size(&prefix, &key);
|
||||||
assert_eq!(prefix.len(), prefix_len);
|
assert_eq!(prefix.len(), prefix_len);
|
||||||
let roundtrip_text = decode(&prefix, &key);
|
let roundtrip_text = decode(&prefix, &key);
|
||||||
let clear_text = read("data/12.txt");
|
let cleartext = read("data/12.txt");
|
||||||
assert_eq!(roundtrip_text, clear_text);
|
assert_eq!(roundtrip_text, cleartext);
|
||||||
println!(
|
println!(
|
||||||
"[okay] Challenge 14: {}",
|
"[okay] Challenge 14: {}",
|
||||||
roundtrip_text.to_utf8()[..17].to_string()
|
roundtrip_text.to_utf8()[..17].to_string()
|
||||||
|
|||||||
36
src/set3.rs
Normal file
36
src/set3.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
use crate::bytes::Bytes;
|
||||||
|
use crate::bytes_base64::BytesBase64;
|
||||||
|
use crate::cbc;
|
||||||
|
use rand::Rng;
|
||||||
|
use std::io::{BufRead, BufReader};
|
||||||
|
|
||||||
|
pub fn challenge17() {
|
||||||
|
fn read(path: &str) -> Vec<Bytes> {
|
||||||
|
let file = std::fs::File::open(path).unwrap();
|
||||||
|
let br = BufReader::new(file);
|
||||||
|
br.lines()
|
||||||
|
.map(|line| BytesBase64::from_base64(&line.unwrap()).to_bytes())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt(ten_strings: &Vec<Bytes>, key: &Bytes) -> (Bytes, Bytes) {
|
||||||
|
// The first function should select at random one of the ten strings
|
||||||
|
let index: usize = rand::thread_rng().gen_range(0..ten_strings.len());
|
||||||
|
let mut cleartext = Bytes(ten_strings[index].0.to_vec());
|
||||||
|
|
||||||
|
// pad the string out to the 16-byte AES block size and
|
||||||
|
cleartext.pad_pkcs7(16);
|
||||||
|
|
||||||
|
// CBC-encrypt it under that key, providing the caller the ciphertext
|
||||||
|
// and IV.
|
||||||
|
let iv = Bytes::random(16);
|
||||||
|
(cbc::encrypt(&key, &iv, &cleartext), iv)
|
||||||
|
}
|
||||||
|
let cleartexts = read("data/17.txt");
|
||||||
|
|
||||||
|
// generate a random AES key (which it should save for all future encryptions)
|
||||||
|
let key = Bytes::random(16);
|
||||||
|
let (cipher, _iv) = encrypt(&cleartexts, &key);
|
||||||
|
|
||||||
|
println!("[xxxx] Challenge 17: {}", cipher.len());
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user