Implement challenge 27
This commit is contained in:
@@ -13,7 +13,7 @@ mod set4;
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
const RUN_ALL: bool = true;
|
const RUN_ALL: bool = false;
|
||||||
if RUN_ALL {
|
if RUN_ALL {
|
||||||
set1::challenge1();
|
set1::challenge1();
|
||||||
set1::challenge2();
|
set1::challenge2();
|
||||||
@@ -42,7 +42,8 @@ fn main() {
|
|||||||
set4::challenge25();
|
set4::challenge25();
|
||||||
set4::challenge26();
|
set4::challenge26();
|
||||||
set4::challenge27();
|
set4::challenge27();
|
||||||
|
set4::challenge28();
|
||||||
} else {
|
} else {
|
||||||
set4::challenge27();
|
set4::challenge28();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
62
src/set4.rs
62
src/set4.rs
@@ -1,4 +1,4 @@
|
|||||||
use crate::{bytes::Bytes, ctr, parser, utils};
|
use crate::{bytes::Bytes, cbc, ctr, parser, utils};
|
||||||
|
|
||||||
pub fn challenge25() {
|
pub fn challenge25() {
|
||||||
let cipher = utils::read_base64("data/25.txt");
|
let cipher = utils::read_base64("data/25.txt");
|
||||||
@@ -80,5 +80,63 @@ pub fn challenge26() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn challenge27() {
|
pub fn challenge27() {
|
||||||
println!("[xxxx] Challenge 27: tbd");
|
fn encrypt(key: &Bytes) -> Bytes {
|
||||||
|
// AES-CBC(P_1, P_2, P_3) -> C_1, C_2, C_3
|
||||||
|
let mut ct = Bytes::from_utf8("comment1=cooking%20MCs;userdata=secretsaucenouse");
|
||||||
|
ct.pad_pkcs7(16);
|
||||||
|
cbc::encrypt(&key, &key, &ct)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrypt(key: &Bytes, cipher: &Bytes) -> Result<Bytes, Bytes> {
|
||||||
|
// The CBC code from exercise 16 encrypts a URL string. Verify each byte
|
||||||
|
// of the plaintext for ASCII compliance (ie, look for high-ASCII
|
||||||
|
// values). Noncompliant messages should raise an exception or return an
|
||||||
|
// error that includes the decrypted plaintext (this happens all the
|
||||||
|
// time in real systems, for what it's worth).
|
||||||
|
let mut cleartext = cbc::decrypt(&key, &key, &cipher);
|
||||||
|
cleartext.remove_pkcs7(16);
|
||||||
|
match std::str::from_utf8(&cleartext.0) {
|
||||||
|
Ok(_) => Ok(cleartext),
|
||||||
|
Err(_) => Err(cleartext),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn modify(cipher: &Bytes) -> Bytes {
|
||||||
|
// C_1, C_2, C_3 -> C_1, 0, C_1
|
||||||
|
let c1 = cipher.get_block(0, 16).0;
|
||||||
|
let mut modified = c1.to_vec();
|
||||||
|
modified.append(&mut vec![0; 16]);
|
||||||
|
modified.append(&mut c1.to_vec());
|
||||||
|
Bytes(modified)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recover_key(plaintext: &Bytes) -> Bytes {
|
||||||
|
// P'_1 XOR P'_3
|
||||||
|
let block_size = 16;
|
||||||
|
Bytes(utils::xor(
|
||||||
|
&plaintext.get_block(0, block_size).0,
|
||||||
|
&plaintext.get_block(2, block_size).0,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
let key = Bytes::random(16);
|
||||||
|
|
||||||
|
// Use your code to encrypt a message that is at least 3 blocks long:
|
||||||
|
let cipher = encrypt(&key);
|
||||||
|
|
||||||
|
// Modify the message (you are now the attacker):
|
||||||
|
let cipher = modify(&cipher);
|
||||||
|
let plaintext = decrypt(&key, &cipher);
|
||||||
|
|
||||||
|
// As the attacker, recovering the plaintext from the error, extract the key:
|
||||||
|
let recovered_key = match plaintext {
|
||||||
|
Ok(plaintext) => panic!("Ok: {:?}", plaintext.to_utf8()),
|
||||||
|
Err(plaintext) => recover_key(&plaintext),
|
||||||
|
};
|
||||||
|
assert_eq!(key, recovered_key);
|
||||||
|
println!("[okay] Challenge 27: recovered key successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn challenge28() {
|
||||||
|
println!("[xxxx] Challenge 28: TBD");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user