stage
This commit is contained in:
64
problems/p6/6.txt
Normal file
64
problems/p6/6.txt
Normal file
@@ -0,0 +1,64 @@
|
||||
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
|
||||
9
problems/p6/Cargo.toml
Normal file
9
problems/p6/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "p6"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.22.1"
|
||||
anyhow = "1.0.98"
|
||||
common = { path = "../../common/" }
|
||||
148
problems/p6/src/main.rs
Normal file
148
problems/p6/src/main.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
use core::f32;
|
||||
use std::fs;
|
||||
use std::{cmp::Ordering, str::from_utf8};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use common::xor_with_key;
|
||||
|
||||
fn base64_to_bytes(input: &str) -> Result<Vec<u8>> {
|
||||
Ok(STANDARD.decode(input)?)
|
||||
}
|
||||
|
||||
fn hamming_distance(input_1: &[u8], input_2: &[u8]) -> Result<u32> {
|
||||
if input_1.len() != input_2.len() {
|
||||
return Err(anyhow!("Can't count hamming distance"));
|
||||
}
|
||||
|
||||
let hamming_distance = input_1
|
||||
.iter()
|
||||
.zip(input_2.iter())
|
||||
.map(|(a, b)| (a ^ b).count_ones())
|
||||
.sum::<u32>();
|
||||
Ok(hamming_distance)
|
||||
}
|
||||
|
||||
fn get_posible_keysize(cipher_bytes: &[u8]) -> Result<usize> {
|
||||
let mut posible_keysizes: HashMap<usize, f32> = HashMap::new();
|
||||
for keysize in 2..=40 {
|
||||
if cipher_bytes.len() < 4 * keysize {
|
||||
return Err(anyhow!("Wrong keysize"));
|
||||
}
|
||||
let mut total_distance = 0;
|
||||
|
||||
for i in 0..=(cipher_bytes.len() - 4 * keysize) {
|
||||
let slice_1 = &cipher_bytes[i..i + keysize];
|
||||
let slice_2 = &cipher_bytes[i + keysize..i + 2 * keysize];
|
||||
let slice_3 = &cipher_bytes[i + 2 * keysize..i + 3 * keysize];
|
||||
let slice_4 = &cipher_bytes[i + 3 * keysize..i + 4 * keysize];
|
||||
total_distance += hamming_distance(slice_1, slice_2)?;
|
||||
total_distance += hamming_distance(slice_1, slice_3)?;
|
||||
total_distance += hamming_distance(slice_1, slice_4)?;
|
||||
total_distance += hamming_distance(slice_2, slice_3)?;
|
||||
total_distance += hamming_distance(slice_2, slice_4)?;
|
||||
total_distance += hamming_distance(slice_3, slice_4)?;
|
||||
}
|
||||
let score = total_distance as f32 / keysize as f32;
|
||||
posible_keysizes.insert(keysize, score);
|
||||
}
|
||||
let mut posible_keysizes: Vec<_> = posible_keysizes.into_iter().collect();
|
||||
posible_keysizes.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(Ordering::Equal));
|
||||
Ok(posible_keysizes.first().unwrap().0)
|
||||
}
|
||||
|
||||
fn score_english_text(input: &[u8]) -> f32 {
|
||||
use std::collections::HashMap;
|
||||
let mut score = 0_f32;
|
||||
let freq: HashMap<u8, f32> = [
|
||||
(b'a', 0.0817),
|
||||
(b'b', 0.0150),
|
||||
(b'c', 0.0278),
|
||||
(b'd', 0.0425),
|
||||
(b'e', 0.1270),
|
||||
(b'f', 0.0223),
|
||||
(b'g', 0.0202),
|
||||
(b'h', 0.0609),
|
||||
(b'i', 0.0697),
|
||||
(b'j', 0.0015),
|
||||
(b'k', 0.0077),
|
||||
(b'l', 0.0403),
|
||||
(b'm', 0.0241),
|
||||
(b'n', 0.0675),
|
||||
(b'o', 0.0751),
|
||||
(b'p', 0.0193),
|
||||
(b'q', 0.0010),
|
||||
(b'r', 0.0599),
|
||||
(b's', 0.0633),
|
||||
(b't', 0.0906),
|
||||
(b'u', 0.0276),
|
||||
(b'v', 0.00981),
|
||||
(b'w', 0.0236),
|
||||
(b'x', 0.0015),
|
||||
(b'y', 0.0197),
|
||||
(b'z', 0.0007),
|
||||
(b' ', 0.1300),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
for c in input.iter().map(|b| b.to_ascii_lowercase()) {
|
||||
if let Some(f) = freq.get(&c) {
|
||||
score += f;
|
||||
}
|
||||
}
|
||||
score
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cipher = fs::read_to_string("./problems/p6/6.txt")?;
|
||||
let cipher: String = cipher.lines().collect();
|
||||
let cipher_bytes = base64_to_bytes(&cipher)?;
|
||||
|
||||
let posible_keysize = get_posible_keysize(&cipher_bytes)?;
|
||||
// posible_keysize = 29
|
||||
|
||||
// 按密钥长度分组
|
||||
let mut blocks: Vec<Vec<u8>> = vec![Vec::new(); posible_keysize];
|
||||
for (i, &byte) in cipher_bytes.iter().enumerate() {
|
||||
blocks[i % posible_keysize].push(byte);
|
||||
}
|
||||
let mut key_list: Vec<u8> = Vec::new();
|
||||
for block in blocks {
|
||||
let mut high_score = 0_f32;
|
||||
let mut possible_key = 0_u8;
|
||||
for key in 0..=255 {
|
||||
let decrypted: Vec<u8> = block.iter().map(|&b| b ^ key).collect();
|
||||
let score = score_english_text(&decrypted);
|
||||
if score > high_score {
|
||||
high_score = score;
|
||||
possible_key = key;
|
||||
}
|
||||
}
|
||||
key_list.push(possible_key);
|
||||
}
|
||||
let str_key = String::from_utf8(key_list.clone())?;
|
||||
println!("key: {str_key}");
|
||||
println!();
|
||||
let plaintext = xor_with_key(&cipher_bytes, &key_list)?;
|
||||
let str_plaintext = from_utf8(&plaintext)?;
|
||||
println!("plaintext: {str_plaintext}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// 导入外部作用域中的所有内容
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_hamming_distance() {
|
||||
let str_1 = "this is a test".as_bytes();
|
||||
let str_2 = "wokka wokka!!!".as_bytes();
|
||||
let result = hamming_distance(str_1, str_2).unwrap();
|
||||
assert_eq!(result, 37)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user