Remove duplicated code and make base64 error handling better

This commit is contained in:
2022-08-14 09:12:36 -04:00
parent fbf26efa44
commit 5158c16d56
8 changed files with 132 additions and 88 deletions

View File

@@ -55,7 +55,7 @@ impl BytesBase64 {
Bytes(v.chunks(4).map(|c| to_bytes(c)).flatten().collect())
}
pub fn from_base64(s: &str) -> BytesBase64 {
pub fn from_base64(s: &str) -> Result<BytesBase64, String> {
let mut r: Vec<u8> = Vec::with_capacity(s.len());
for c in s.chars() {
match c {
@@ -64,10 +64,15 @@ impl BytesBase64 {
'0'..='9' => r.push((c as u8) - ('0' as u8) + 52),
'+' => r.push(62),
'/' => r.push(63),
_ => (),
'\n' => (),
'=' => (),
' ' => (),
_ => {
return Err(format!("Unexpected character '{}'", c));
}
}
}
BytesBase64(r)
Ok(BytesBase64(r))
}
pub fn to_string(&self) -> String {

View File

@@ -13,7 +13,7 @@ mod set4;
mod utils;
fn main() {
const RUN_ALL: bool = false;
const RUN_ALL: bool = true;
if RUN_ALL {
set1::challenge1();
set1::challenge2();

View File

@@ -1,8 +1,8 @@
#![allow(dead_code)]
use crate::bytes::Bytes;
use crate::bytes_base64::BytesBase64;
use crate::ecb;
use std::io::{BufRead, BufReader, Write};
use crate::{ecb, utils};
use std::io::Write;
use std::str;
pub fn challenge1() {
@@ -38,15 +38,7 @@ pub fn challenge3() {
}
pub fn challenge4() {
fn read(path: &str) -> Vec<Bytes> {
let file = std::fs::File::open(path).unwrap();
let br = BufReader::new(file);
br.lines()
.map(|line| Bytes::from_hex(&line.unwrap()))
.collect()
}
let bytes_vector = read("data/4.txt");
let bytes_vector = utils::read_hex_lines("data/4.txt");
let mut xored_bytes_vector: Vec<Bytes> = vec![];
for i in 32..=127 {
for bytes in bytes_vector.iter() {
@@ -73,11 +65,6 @@ pub fn challenge5() {
}
pub fn challenge6() {
fn read(path: &str) -> Bytes {
let s = std::fs::read_to_string(path).unwrap();
BytesBase64::from_base64(&s).to_bytes()
}
fn _write(path: &str, bytes_base64: &BytesBase64) {
let width = 60;
let bytes = bytes_base64.to_string();
@@ -96,7 +83,7 @@ pub fn challenge6() {
fn _test_roundtrip() {
// Test that conversion from to bytes and back works
let bytes = read("data/6.txt");
let bytes = utils::read_base64("data/6.txt");
let bytes_base64 = BytesBase64::from_bytes(bytes);
_write("data/6.txt", &bytes_base64);
}
@@ -139,7 +126,7 @@ pub fn challenge6() {
}
_test_roundtrip();
let bytes = read("data/6.txt");
let bytes = utils::read_base64("data/6.txt");
let key_size = guess_key_size(&bytes);
let bytes_tranposed = transpose(&bytes, key_size);
let key = Bytes(
@@ -155,10 +142,6 @@ pub fn challenge6() {
}
pub fn challenge7() {
fn read(path: &str) -> Bytes {
let s = std::fs::read_to_string(path).unwrap();
BytesBase64::from_base64(&s).to_bytes()
}
let text = Bytes::from_utf8("We meet at burger king!");
let key = Bytes::from_utf8("YELLOW SUBMARINE");
let ciphertext = ecb::encrypt(&key, &text);
@@ -166,21 +149,13 @@ pub fn challenge7() {
if text != roundtrip {
panic!("ECB roundtrip not working.");
}
let ciphertext = read("data/7.txt");
let ciphertext = utils::read_base64("data/7.txt");
let data = ecb::decrypt(&key, &ciphertext);
let partial_msg = data.to_utf8()[..20].to_string();
println!("[okay] Challenge 7: {}...", partial_msg);
}
pub fn challenge8() {
fn read(path: &str) -> Vec<Bytes> {
let file = std::fs::File::open(path).unwrap();
let br = BufReader::new(file);
br.lines()
.map(|line| Bytes::from_hex(&line.unwrap()))
.collect()
}
fn rate(Bytes(v): &Bytes, size: usize) -> u32 {
let mut rating = 0;
let chunks: Vec<&[u8]> = v.chunks(size).collect();
@@ -193,7 +168,7 @@ pub fn challenge8() {
}
let expected_index: usize = 132;
let bytes_vector = read("data/8.txt");
let bytes_vector = utils::read_hex_lines("data/8.txt");
let ratings: Vec<u32> = bytes_vector.iter().map(|b| rate(&b, 16)).collect();
let min_rating = ratings.iter().min().unwrap();
let index = ratings.iter().position(|e| e == min_rating).unwrap();
@@ -208,7 +183,7 @@ pub fn challenge8() {
);
// More elegant solution.
let bytes_vector = read("data/8.txt");
let bytes_vector = utils::read_hex_lines("data/8.txt");
let ix: Vec<usize> = bytes_vector
.iter()
.enumerate()

View File

@@ -1,8 +1,8 @@
use crate::bytes::Bytes;
use crate::bytes_base64::BytesBase64;
use crate::cbc;
use crate::ecb;
use crate::parser;
use crate::utils;
use rand::Rng;
use std::collections::HashMap;
@@ -13,10 +13,6 @@ pub fn challenge9() {
}
pub fn challenge10() {
fn read(path: &str) -> Bytes {
let s = std::fs::read_to_string(path).unwrap();
BytesBase64::from_base64(&s).to_bytes()
}
let iv = Bytes(vec![0; 16]);
let key = Bytes::from_utf8("YELLOW SUBMARINE");
@@ -24,7 +20,7 @@ pub fn challenge10() {
let ciphertext = cbc::encrypt(&key, &iv, &text);
let roundtrip = cbc::decrypt(&key, &iv, &ciphertext);
if text == roundtrip {
let ciphertext = read("data/10.txt");
let ciphertext = utils::read_base64("data/10.txt");
let cleartext = cbc::decrypt(&key, &iv, &ciphertext);
let output = cleartext.to_utf8()[..16].to_string();
println!("[okay] Challenge 10: {}", output);
@@ -104,16 +100,11 @@ pub fn challenge11() {
}
pub fn challenge12() {
fn read(path: &str) -> Bytes {
let s = std::fs::read_to_string(path).unwrap();
BytesBase64::from_base64(&s).to_bytes()
}
fn encryption_oracle(key: &Bytes, Bytes(data): &Bytes) -> Bytes {
// Copy your oracle function to a new function that encrypts buffers under ECB mode using a consistent but unknown key
// Now take that same function and have it append to the plaintext, BEFORE ENCRYPTING, the following string (from 12.txt):
let mut data = data.to_vec();
let mut string = read("data/12.txt");
let mut string = utils::read_base64("data/12.txt");
data.append(&mut string.0);
let cipher = ecb::encrypt(&key, &Bytes(data));
cipher
@@ -184,7 +175,7 @@ pub fn challenge12() {
assert_eq!(get_block_size(&key), 16); // 1. discover block size
assert_eq!(is_encryption_ecb(&key), true); // 2. confirm oracle uses ecb
let roundtrip_text = decode(&key); // 3.-6.
let cleartext = read("data/12.txt");
let cleartext = utils::read_base64("data/12.txt");
// 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
@@ -254,11 +245,6 @@ pub fn challenge13() {
}
pub fn challenge14() {
fn read(path: &str) -> Bytes {
let s = std::fs::read_to_string(path).unwrap();
BytesBase64::from_base64(&s).to_bytes()
}
fn encryption_oracle(
Bytes(random_prefix): &Bytes,
random_key: &Bytes,
@@ -271,7 +257,7 @@ pub fn challenge14() {
// long it is and then adjust the decoding routine.
let mut plaintext = random_prefix.to_vec();
plaintext.append(&mut attacker_controlled.to_vec());
let mut target_bytes = read("data/12.txt").0;
let mut target_bytes = utils::read_base64("data/12.txt").0;
plaintext.append(&mut target_bytes);
let cipher = ecb::encrypt(&random_key, &Bytes(plaintext));
cipher
@@ -383,7 +369,7 @@ pub fn challenge14() {
let prefix_len = get_prefix_size(&prefix, &key);
assert_eq!(prefix.len(), prefix_len);
let roundtrip_text = decode(&prefix, &key);
let cleartext = read("data/12.txt");
let cleartext = utils::read_base64("data/12.txt");
assert_eq!(roundtrip_text, cleartext);
println!(
"[okay] Challenge 14: {}",

View File

@@ -9,21 +9,12 @@ use rand::Rng;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::HashSet;
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()
}
let key = Bytes::random(16);
let encrypt = || -> (Bytes, Bytes, usize) {
// The first function should select at random one of the ten strings
let cleartexts = read("data/17.txt");
let cleartexts = utils::read_base64_lines("data/17.txt");
let index: usize = rand::thread_rng().gen_range(0..cleartexts.len());
let mut cleartext = Bytes(cleartexts[index].0.to_vec());
@@ -95,7 +86,7 @@ pub fn challenge17() {
roundtrip.0.append(&mut clear_block.0);
}
roundtrip.remove_pkcs7(16);
let cleartexts = read("data/17.txt");
let cleartexts = utils::read_base64_lines("data/17.txt");
let cleartext = Bytes(cleartexts[cleartext_index].0.to_vec());
assert_eq!(roundtrip, cleartext);
println!("[okay] Challenge 17: {}", roundtrip.to_utf8());
@@ -112,20 +103,13 @@ pub fn challenge18() {
let cipher = BytesBase64::from_base64(
"L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==",
)
.unwrap()
.to_bytes();
let cleartext = ctr::decrypt(&key, 0, &cipher).to_utf8();
println!("[okay] Challenge 18: {cleartext}");
}
pub fn challenge19() {
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 xor_to_char_set(letters: &Vec<u8>) -> HashMap<u8, RefCell<HashSet<u8>>> {
let mut h = HashMap::new();
for i in 0..255_u8 {
@@ -255,7 +239,7 @@ pub fn challenge19() {
decrypts[37].borrow_mut()[30] = b'i';
}
let plaintexts = read("data/19.txt");
let plaintexts = utils::read_base64_lines("data/19.txt");
let key = Bytes::from_utf8("YELLOW SUBMARINE");
let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) };
let ciphers: Vec<Bytes> = plaintexts.iter().map(|ct| encrypt(&ct)).collect();
@@ -271,14 +255,6 @@ pub fn challenge19() {
}
pub fn challenge20() {
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 attack(ciphers: Vec<Bytes>) -> Vec<Bytes> {
let min_cipher_len = ciphers.iter().map(|c| c.len()).min().unwrap_or(0);
let mut key: Vec<u8> = vec![];
@@ -294,7 +270,7 @@ pub fn challenge20() {
.collect()
}
let plaintexts = read("data/20.txt");
let plaintexts = utils::read_base64_lines("data/20.txt");
let key = Bytes::from_utf8("YELLOW SUBMARINE");
let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) };
let ciphers: Vec<Bytes> = plaintexts.iter().map(|ct| encrypt(&ct)).collect();

View File

@@ -1,3 +1,9 @@
use crate::{bytes::Bytes, utils};
pub fn challenge25() {
println!("[xxxx] Challenge 25: TBD");
let cipher = utils::read_base64("data/25.txt");
let key = Bytes::from_utf8("YELLOW SUBMARINE");
let _cleartext = crate::ecb::decrypt(&key, &cipher);
println!("[xxxx] Challenge 25: wip");
}

View File

@@ -1,4 +1,8 @@
use std::time::{SystemTime, UNIX_EPOCH};
use crate::{bytes::Bytes, bytes_base64::BytesBase64};
use std::{
io::{BufRead, BufReader},
time::{SystemTime, UNIX_EPOCH},
};
pub fn unix_timestamp() -> u32 {
let start = SystemTime::now();
@@ -7,3 +11,31 @@ pub fn unix_timestamp() -> u32 {
.expect("Time went backwards");
since_the_epoch.as_secs() as u32
}
pub fn read_base64(path: &str) -> Bytes {
let s = std::fs::read_to_string(path).unwrap();
match BytesBase64::from_base64(&s) {
Ok(bytes) => bytes.to_bytes(),
Err(msg) => panic!("Failed to read_base64 {}: {}", path, msg),
}
}
pub fn read_base64_lines(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.expect(&format!("Failed to read line in {}", path)))
.expect(&format!("Invalid base64 in {}", path))
.to_bytes()
})
.collect()
}
pub fn read_hex_lines(path: &str) -> Vec<Bytes> {
let file = std::fs::File::open(path).unwrap();
let br = BufReader::new(file);
br.lines()
.map(|line| Bytes::from_hex(&line.unwrap()))
.collect()
}