diff --git a/Cargo.toml b/Cargo.toml index 3102ee0..9558d32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -openssl = ">= 0.10.38" \ No newline at end of file +openssl = ">= 0.10.38" +rand = ">= 0.8.5" \ No newline at end of file diff --git a/src/ecb.rs b/src/ecb.rs new file mode 100644 index 0000000..fdcbc79 --- /dev/null +++ b/src/ecb.rs @@ -0,0 +1,22 @@ +use crate::bytes::Bytes; +use openssl::symm; + +pub fn encrypt(Bytes(key): &Bytes, Bytes(data): &Bytes) -> Bytes { + let cipher = symm::Cipher::aes_128_ecb(); + let data = symm::encrypt(cipher, key, None, data); + let result = match data { + Ok(data) => Bytes(data), + Err(err) => panic!("{}", err.to_string()), + }; + result +} + +pub fn decrypt(Bytes(key): &Bytes, Bytes(data): &Bytes) -> Bytes { + let cipher = symm::Cipher::aes_128_ecb(); + let data = symm::decrypt(cipher, key, None, data); + let result = match data { + Ok(data) => Bytes(data), + Err(err) => panic!("{}", err.to_string()), + }; + result +} diff --git a/src/main.rs b/src/main.rs index d07d265..0930f6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ mod bytes; mod bytes_base64; mod cbs; +mod ecb; mod set1; mod set2; @@ -13,7 +14,7 @@ fn main() { // set1::challenge6(); // set1::challenge7(); // set1::challenge8(); - // set2::challenge9(); + set2::challenge9(); set2::challenge10(); set2::challenge11(); } diff --git a/src/set1.rs b/src/set1.rs index 99231d1..cd52292 100644 --- a/src/set1.rs +++ b/src/set1.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use crate::bytes::Bytes; use crate::bytes_base64::BytesBase64; -use openssl::symm::{decrypt, Cipher}; +use crate::ecb; use std::io::{BufRead, BufReader, Write}; use std::str; @@ -160,15 +160,16 @@ pub fn challenge7() { let s = std::fs::read_to_string(path).unwrap(); BytesBase64::from_base64(&s).to_bytes() } - let ciphertext = &read("data/7.txt").0; - let key = b"YELLOW SUBMARINE"; - let cipher = Cipher::aes_128_ecb(); - let data = decrypt(cipher, key, None, ciphertext); - let result = match data { - Ok(data) => Bytes(data).to_utf8(), - Err(err) => err.to_string(), - }; - let partial_msg = result[..20].to_string(); + let text = Bytes::from_utf8("We meet at burger king!"); + let key = Bytes::from_utf8("YELLOW SUBMARINE"); + let ciphertext = ecb::encrypt(&key, &text); + let roundtrip = ecb::decrypt(&key, &ciphertext); + if text != roundtrip { + panic!("ECB roundtrip not working."); + } + let ciphertext = read("data/7.txt"); + let data = ecb::decrypt(&key, &ciphertext); + let partial_msg = data.to_utf8()[..20].to_string(); println!("[okay] Challenge 7: {}...", partial_msg); } @@ -198,6 +199,9 @@ pub fn challenge8() { let index = ratings.iter().position(|e| e == min_rating).unwrap(); let average = ratings.iter().sum::() as f32 / ratings.len() as f32; let partial_cipher = bytes_vector[index].to_hex()[..10].to_string(); + if index != 132 { + panic!("Regression in challenge 8."); + } println!( "[okay] Challenge 8: Cipher {} [{}...] with rating {} (average = {}) is the solution.", index, partial_cipher, min_rating, average diff --git a/src/set2.rs b/src/set2.rs index e2ff132..9dd4d5d 100644 --- a/src/set2.rs +++ b/src/set2.rs @@ -1,7 +1,8 @@ -#![allow(dead_code)] use crate::bytes::Bytes; use crate::bytes_base64::BytesBase64; use crate::cbs; +use crate::ecb; +use rand::Rng; pub fn challenge9() { let mut bytes = Bytes::from_utf8("YELLOW SUBMARINE"); @@ -31,5 +32,36 @@ pub fn challenge10() { } pub fn challenge11() { - println!("[tbd] Challenge 11: TBD!"); + enum EncryptionType { + CBS, + ECB, + } + fn random_bytes(count: usize) -> Vec { + (0..count) + .map(|_| rand::thread_rng().gen_range(0..255)) + .collect() + } + + fn pad_data(mut v: Vec) -> Bytes { + let pre_count: usize = rand::thread_rng().gen_range(5..10); + let post_count: usize = rand::thread_rng().gen_range(5..10); + let mut pre_pad = random_bytes(pre_count); + let mut post_pad = random_bytes(post_count); + pre_pad.append(&mut v); + pre_pad.append(&mut post_pad); + Bytes(pre_pad) + } + + fn encryption_oracle(Bytes(data): &Bytes) -> (Bytes, EncryptionType) { + let zero_or_one: u32 = rand::thread_rng().gen_range(0..2); + let padded_data = pad_data(data.to_vec()); + let key = Bytes(random_bytes(16)); + let (data, encryption_type) = if zero_or_one == 1 { + (ecb::encrypt(&key, &padded_data), EncryptionType::ECB) + } else { + let iv = Bytes(random_bytes(16)); + (cbs::encrypt(&key, &iv, &padded_data), EncryptionType::CBS) + }; + (data, encryption_type) + } }