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 }