cryptopals

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

1-4.rs (2462B)


      1 use cryptopals::utils::read_buffer;
      2 
      3 fn main() -> Result<(), Box<dyn std::error::Error>> {
      4     let mut keys: Vec<u8> = Vec::new();
      5     loop {
      6         let input = read_buffer()?;
      7         if input.is_empty() {
      8             break;
      9         }
     10         keys.push(detect_key(&hex_to_bytes(&input))?);
     11     }
     12     println!("keys: {}", String::from_utf8_lossy(&keys));
     13     Ok(())
     14 }
     15 
     16 fn detect_key(crypted: &[u8]) -> Result<u8, Box<dyn std::error::Error>> {
     17     let (key, msg, score) = crack_single_byte_xor(crypted);
     18     // println!(
     19     //     "key: {}, msg: {}, score: {}",
     20     //     bytes_to_hex(&[key]),
     21     //     bytes_to_hex(&xor(&crypted, &[key])),
     22     //     score
     23     // );
     24     println!("{}", String::from_utf8_lossy(&[key]));
     25     Ok(key)
     26 }
     27 fn hex_to_bytes(hex: &str) -> Vec<u8> {
     28     hex.as_bytes()
     29         .chunks(2)
     30         .map(|chunk| {
     31             let s = std::str::from_utf8(chunk).unwrap();
     32             u8::from_str_radix(s, 16).expect("Invalid hex")
     33         })
     34         .collect()
     35 }
     36 fn bytes_to_hex(bytes: &[u8]) -> String {
     37     bytes.iter().map(|b| format!("{:02x}", b)).collect()
     38 }
     39 fn xor(first: &[u8], second: &[u8]) -> Vec<u8> {
     40     first
     41         .iter()
     42         .zip(second.iter().cycle())
     43         .map(|(a, b)| a ^ b)
     44         .collect()
     45 }
     46 fn score_text(bytes: &[u8]) -> f64 {
     47     let mut score = 0.0;
     48     for &b in bytes {
     49         match b.to_ascii_lowercase() {
     50             b'e' => score += 12.02,
     51             b't' => score += 9.10,
     52             b'a' => score += 8.12,
     53             b'o' => score += 7.68,
     54             b'i' => score += 7.31,
     55             b'n' => score += 6.95,
     56             b's' => score += 6.28,
     57             b'r' => score += 6.02,
     58             b'h' => score += 5.92,
     59             b'd' => score += 4.32,
     60             b'l' => score += 3.98,
     61             b'u' => score += 2.88,
     62             b' ' => score += 15.0,
     63             0..=31 | 127 => score -= 50.0,
     64             32..=126 => score += 1.0,
     65             _ => score -= 10.0,
     66         }
     67     }
     68     score
     69 }
     70 
     71 fn crack_single_byte_xor(crypted: &[u8]) -> (u8, Vec<u8>, f64) {
     72     let mut best_score = f64::MIN;
     73     let mut best_key = 0;
     74     let mut best_msg = Vec::new();
     75 
     76     for key in 0..=255 {
     77         let decrypted: Vec<u8> = crypted.iter().map(|&b| b ^ key).collect();
     78         let score = score_text(&decrypted);
     79 
     80         if score > best_score {
     81             best_score = score;
     82             best_key = key;
     83             best_msg = decrypted;
     84         }
     85     }
     86     (best_key, best_msg, best_score)
     87 }