Clean up and lay groundwork for challange 32
This commit is contained in:
129
src/set3.rs
129
src/set3.rs
@@ -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}");
|
||||
|
||||
Reference in New Issue
Block a user