From 54047b3450211245a90b72044c6e07c993680033 Mon Sep 17 00:00:00 2001 From: Felix Martin Date: Tue, 16 Aug 2022 19:16:48 -0400 Subject: [PATCH] Implement challenge 27 --- src/main.rs | 5 +++-- src/set4.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index f8bbcc7..844109c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ mod set4; mod utils; fn main() { - const RUN_ALL: bool = true; + const RUN_ALL: bool = false; if RUN_ALL { set1::challenge1(); set1::challenge2(); @@ -42,7 +42,8 @@ fn main() { set4::challenge25(); set4::challenge26(); set4::challenge27(); + set4::challenge28(); } else { - set4::challenge27(); + set4::challenge28(); } } diff --git a/src/set4.rs b/src/set4.rs index 34e3f77..28e3683 100644 --- a/src/set4.rs +++ b/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() { let cipher = utils::read_base64("data/25.txt"); @@ -80,5 +80,63 @@ pub fn challenge26() { } 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 { + // 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"); }