diff --git a/cryptopal_book/src/challenge_01.md b/cryptopal_book/src/challenge_01.md index c127c3a..fdb6907 100644 --- a/cryptopal_book/src/challenge_01.md +++ b/cryptopal_book/src/challenge_01.md @@ -47,7 +47,7 @@ Base64是一种基于64个可打印字符来表示二进制数据个表示方法 Padding: = -例如编码一个"Hello World"字符串: +例如使用ascii(或等效兼容的utf8)编码一个"Hello World"字符串: H -> 01001000 e -> 01100101 @@ -69,7 +69,7 @@ d -> 01100100 此处对应最后一组不足6位,因此填充两位0,对齐至6位。 并在最终的编码末尾添加一个=,表示填充了两位0。 -对应的编码就是SGVsbG8gV29ybGQ= +对应的Base64编码就是SGVsbG8gV29ybGQ= 如果最后一组填充了四位0,则最终编码末尾添加两个=。 diff --git a/cryptopal_book/src/challenge_04.md b/cryptopal_book/src/challenge_04.md index 36167b7..40e37c5 100644 --- a/cryptopal_book/src/challenge_04.md +++ b/cryptopal_book/src/challenge_04.md @@ -24,7 +24,7 @@ - 读取包含多行十六进制字符串的文件 - 将所有行连接成一个长字符串进行处理 -### 3. 滑动窗口解密检测 +### 滑动窗口解密检测 **实现策略:** diff --git a/cryptopal_book/src/challenge_05.md b/cryptopal_book/src/challenge_05.md index 6c0c98f..1f6d97e 100644 --- a/cryptopal_book/src/challenge_05.md +++ b/cryptopal_book/src/challenge_05.md @@ -24,22 +24,7 @@ ICE 4. **XOR运算**:对每对字节执行`a ^ b`操作 5. **结果收集**:将所有XOR结果收集为`Vec` -### 3. 主函数实现 - -```rust -fn main() -> Result<()> { - let plaintexts = r#" -Burning 'em, if you ain't quick and nimble I go crazy when I hear a cymbal -"#; - let key = b"ICE"; - for plaintext in plaintexts.lines() { - let plaintext_bytes = plaintext.as_bytes(); - let cipher = xor_with_key(plaintext_bytes, key)?; - println!("{}", hex::encode(cipher)); - } - Ok(()) -} -``` +### 主函数实现 **执行流程:** @@ -63,5 +48,3 @@ Burning 'em, if you ain't quick and nimble I go crazy when I hear a cymbal - **比单字节XOR更安全**:密钥长度增加了破解难度 - **仍然脆弱**:存在重复模式,可通过频率分析攻击 - **历史意义**:Vigenère密码的电子版本 - -这种实现展示了如何使用Rust的迭代器和函数式编程特性来优雅地处理密码学算法。 diff --git a/cryptopal_book/src/challenge_06.md b/cryptopal_book/src/challenge_06.md index e382171..52b5e00 100644 --- a/cryptopal_book/src/challenge_06.md +++ b/cryptopal_book/src/challenge_06.md @@ -7,6 +7,7 @@ **数据文件:** `6.txt` 该文件包含Base64编码的加密数据,例如: + ``` HUIfTQsPAh9PE048GmllH0kcDk4TAQsHThsBFkU2AB4BSWQgVB0dQzNTTmVS BgBHVBwNRU0HBAxTEjwMHghJGgkRTxRMIRpHKwAFHUdZEQQJAGQmB1MANxYG @@ -16,83 +17,18 @@ DBoXQR0BUlQwXwAgEwoFR08SSAhFTmU+Fgk4RQYFCBpGB08fWXh+amI2DB0P **原始数据来源:** [https://cryptopals.com/static/challenge-data/6.txt](https://cryptopals.com/static/challenge-data/6.txt) -## 代码实现与解析 +## 原理简介 -### 1. 依赖引入 +### Hamming距离原理 -```rust -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; -``` - -### 2. Base64解码函数 - -```rust -fn base64_to_bytes(input: &str) -> Result> { - Ok(STANDARD.decode(input)?) -} -``` - -### 3. Hamming距离计算 - -```rust -fn hamming_distance(input_1: &[u8], input_2: &[u8]) -> Result { - 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::(); - Ok(hamming_distance) -} -``` - -**Hamming距离原理:** - 计算两个等长字节序列的位差异数量 - 使用XOR运算找出不同的位 - `count_ones()`统计结果中1的个数 -### 4. 密钥长度推测 - -```rust -fn get_posible_keysize(cipher_bytes: &[u8]) -> Result { - let mut posible_keysizes: HashMap = 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) -} -``` +### 密钥长度推测 **密钥长度推测策略:** + 1. **多块采样**:取连续的4个密钥长度大小的块 2. **距离计算**:计算所有块之间的Hamming距离 3. **归一化评分**:除以密钥长度进行归一化 @@ -127,51 +63,13 @@ fn score_english_text(input: &[u8]) -> f32 { ``` **频率分析原理:** + - 使用英文字母的标准频率分布 - 计算文本与标准频率的匹配程度 - 分数越高,越可能是有效英文文本 -### 6. 主破解流程 - -```rust -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)?; - - // 按密钥长度分组 - let mut blocks: Vec> = vec![Vec::new(); posible_keysize]; - for (i, &byte) in cipher_bytes.iter().enumerate() { - blocks[i % posible_keysize].push(byte); - } - - let mut key_list: Vec = 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 = 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}"); - let plaintext = xor_with_key(&cipher_bytes, &key_list)?; - let str_plaintext = from_utf8(&plaintext)?; - println!("plaintext: {str_plaintext}"); - Ok(()) -} -``` - **破解步骤:** + 1. **读取密文**:从Base64文件读取加密数据 2. **推测密钥长度**:使用Hamming距离分析 3. **分组密文**:按密钥长度将密文分组 @@ -181,6 +79,7 @@ fn main() -> Result<()> { ## 密码分析原理 这个挑战展示了经典的Vigenère密码分析技术: + - **Hamming距离**:利用重复密钥的周期性特征 - **频率分析**:基于英文字母的统计分布 - **分组技术**:将复杂问题分解为多个单字节XOR问题