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