Clean up and lay groundwork for challange 32

This commit is contained in:
2022-08-28 15:53:23 -04:00
parent 75d4b97524
commit f50197e480
6 changed files with 111 additions and 92 deletions

View File

@@ -7,8 +7,6 @@ use crate::mtcipher;
use crate::utils;
use rand::Rng;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::HashSet;
pub fn challenge17() {
let key = Bytes::random(16);
@@ -118,7 +116,13 @@ pub fn challenge18() {
println!("[okay] Challenge 18: {cleartext}");
}
fn challenge19_attack(ciphers: &[Bytes]) -> Vec<RefCell<Vec<u8>>> {
mod challenge19 {
use crate::bytes::Bytes;
use std::cell::RefCell;
use std::collections::HashMap;
use std::collections::HashSet;
fn xor_to_char_set(letters: &Vec<u8>) -> HashMap<u8, RefCell<HashSet<u8>>> {
let mut h = HashMap::new();
for i in 0..255_u8 {
@@ -152,80 +156,83 @@ fn challenge19_attack(ciphers: &[Bytes]) -> Vec<RefCell<Vec<u8>>> {
letters
}
let ciphers_len = ciphers.len();
let deciphered = vec![RefCell::new(vec![]); ciphers_len];
let max_cipher_len = ciphers.iter().map(Bytes::len).max().unwrap_or(0);
pub fn attack(ciphers: &[Bytes]) -> Vec<RefCell<Vec<u8>>> {
let ciphers_len = ciphers.len();
let deciphered = vec![RefCell::new(vec![]); ciphers_len];
let max_cipher_len = ciphers.iter().map(Bytes::len).max().unwrap_or(0);
for byte_index in 0..max_cipher_len {
let letters = match byte_index {
// chars that work for 10 and 20 found via trial and error
10 => ascii_letters(" _-.,;:'"),
20 => ascii_letters(" _-.,;:?"),
_ => ascii_letters(" _-.,;:"),
};
let lookup = xor_to_char_set(&letters);
for byte_index in 0..max_cipher_len {
let letters = match byte_index {
// chars that work for 10 and 20 found via trial and error
10 => ascii_letters(" _-.,;:'"),
20 => ascii_letters(" _-.,;:?"),
_ => ascii_letters(" _-.,;:"),
};
let lookup = xor_to_char_set(&letters);
let target_bytes: Vec<Option<u8>> = ciphers
.iter()
.map(|c| {
if c.len() > byte_index {
Some(c.0[byte_index])
} else {
None
let target_bytes: Vec<Option<u8>> = ciphers
.iter()
.map(|c| {
if c.len() > byte_index {
Some(c.0[byte_index])
} else {
None
}
})
.collect();
let mut possible_chars: Vec<HashSet<u8>> = ciphers
.iter()
.map(|_| letters.iter().copied().collect())
.collect();
for i in 0..ciphers_len {
for j in i..ciphers_len {
if target_bytes[i] == None || target_bytes[j] == None {
continue;
}
let xored = target_bytes[i].unwrap() ^ target_bytes[j].unwrap();
let chars = lookup.get(&xored).unwrap().borrow();
possible_chars[i] = possible_chars[i].intersection(&chars).copied().collect();
possible_chars[j] = possible_chars[j].intersection(&chars).copied().collect();
}
})
.collect();
let mut possible_chars: Vec<HashSet<u8>> = ciphers
.iter()
.map(|_| letters.iter().copied().collect())
.collect();
}
for i in 0..ciphers_len {
for j in i..ciphers_len {
if target_bytes[i] == None || target_bytes[j] == None {
for cipher_index in 0..ciphers_len {
if ciphers[cipher_index].len() <= byte_index {
continue;
}
let xored = target_bytes[i].unwrap() ^ target_bytes[j].unwrap();
let chars = lookup.get(&xored).unwrap().borrow();
possible_chars[i] = possible_chars[i].intersection(&chars).copied().collect();
possible_chars[j] = possible_chars[j].intersection(&chars).copied().collect();
}
}
for cipher_index in 0..ciphers_len {
if ciphers[cipher_index].len() <= byte_index {
continue;
}
let chars: Vec<u8> = possible_chars[cipher_index].iter().copied().collect();
match chars.len() {
0 => {
// println!("No chars for {cipher_index} {byte_index}");
deciphered[cipher_index].borrow_mut().push(b'?');
}
1 => {
deciphered[cipher_index]
.borrow_mut()
.push(u8_lower(chars[0]));
}
2 => {
if u8_lower(chars[0]) == u8_lower(chars[1]) {
let chars: Vec<u8> = possible_chars[cipher_index].iter().copied().collect();
match chars.len() {
0 => {
// println!("No chars for {cipher_index} {byte_index}");
deciphered[cipher_index].borrow_mut().push(b'?');
}
1 => {
deciphered[cipher_index]
.borrow_mut()
.push(u8_lower(chars[0]));
} else {
}
2 => {
if u8_lower(chars[0]) == u8_lower(chars[1]) {
deciphered[cipher_index]
.borrow_mut()
.push(u8_lower(chars[0]));
} else {
// println!("Two {chars:?} {cipher_index} {byte_index}");
deciphered[cipher_index].borrow_mut().push(b'^');
}
}
_ => {
// println!("Two {chars:?} {cipher_index} {byte_index}");
deciphered[cipher_index].borrow_mut().push(b'^');
}
}
_ => {
// println!("Two {chars:?} {cipher_index} {byte_index}");
deciphered[cipher_index].borrow_mut().push(b'^');
}
}
}
deciphered
}
deciphered
}
pub fn challenge19() {
@@ -252,7 +259,7 @@ pub fn challenge19() {
let key = Bytes::from_utf8("YELLOW SUBMARINE");
let encrypt = |plaintext: &Bytes| -> Bytes { ctr::encrypt(&key, 0, plaintext) };
let ciphers: Vec<Bytes> = plaintexts.iter().map(encrypt).collect();
let decrypts = challenge19_attack(&ciphers);
let decrypts = challenge19::attack(&ciphers);
manual(&decrypts);
let first_line = Bytes(decrypts[0].borrow().to_vec()).to_utf8();
println!("[okay] Challenge 19: {first_line}");