fix: fix mdbook content
This commit is contained in:
@@ -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,则最终编码末尾添加两个=。
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
- 读取包含多行十六进制字符串的文件
|
||||
- 将所有行连接成一个长字符串进行处理
|
||||
|
||||
### 3. 滑动窗口解密检测
|
||||
### 滑动窗口解密检测
|
||||
|
||||
**实现策略:**
|
||||
|
||||
|
||||
@@ -24,22 +24,7 @@ ICE
|
||||
4. **XOR运算**:对每对字节执行`a ^ b`操作
|
||||
5. **结果收集**:将所有XOR结果收集为`Vec<u8>`
|
||||
|
||||
### 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的迭代器和函数式编程特性来优雅地处理密码学算法。
|
||||
|
||||
@@ -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<Vec<u8>> {
|
||||
Ok(STANDARD.decode(input)?)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Hamming距离计算
|
||||
|
||||
```rust
|
||||
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)
|
||||
}
|
||||
```
|
||||
|
||||
**Hamming距离原理:**
|
||||
- 计算两个等长字节序列的位差异数量
|
||||
- 使用XOR运算找出不同的位
|
||||
- `count_ones()`统计结果中1的个数
|
||||
|
||||
### 4. 密钥长度推测
|
||||
|
||||
```rust
|
||||
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)
|
||||
}
|
||||
```
|
||||
### 密钥长度推测
|
||||
|
||||
**密钥长度推测策略:**
|
||||
|
||||
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<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}");
|
||||
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问题
|
||||
|
||||
Reference in New Issue
Block a user