apppublic/aidocs/rc4.md
2025-10-05 11:23:33 +08:00

339 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RC4 加密与密钥链技术文档
---
## 概述
本文档详细描述了一个基于 **RC4 流加密算法** 和动态密钥生成机制(`KeyChain`)的 Python 实现。该系统支持数据加解密、自动密钥轮换、时间敏感的密钥管理,并具备一定的容错能力以应对时钟偏差。
主要特性包括:
- 使用 RC4 算法进行流加密
- 引入随机盐值salt和 SHA-1 密钥扩展增强安全性
- 支持 Base64 编码输出
- 动态密钥生成(基于时间窗口)
- 容忍一定时间偏移的解密尝试(前向/后向周期补偿)
---
## 依赖模块
```python
import time
import datetime
import random
import base64
from hashlib import sha1
```
> 注:`random` 模块当前未使用,可能是预留或冗余导入。
---
## 核心类说明
### 1. `RC4` 类 —— RC4 加密器
#### 初始化方法:`__init__(self, data_coding='utf8')`
初始化 RC4 加密实例。
| 参数 | 类型 | 描述 |
|--------------|--------|------|
| `data_coding` | str | 数据编码格式,默认为 `'utf8'`,用于字符串与字节之间的转换 |
##### 属性:
- `bcoding`: 内部字节编码,固定为 `'iso-8859-1'`(确保字节范围兼容)
- `dcoding`: 外部数据编码(默认 UTF-8
- `salt`: 固定盐值 `b'AFUqx9WZuI32lnHk'`16 字节),用于密钥强化
---
#### 私有方法:`_crypt(self, data: bytes, key: bytes) -> bytes`
执行标准 RC4 加密/解密操作。
##### 参数:
- `data`: 待处理的字节数据
- `key`: 密钥bytes
##### 返回:
- 加密或解密后的字节串(经 `'iso-8859-1'` 编码)
##### 算法流程:
1. 初始化长度为 256 的 S-box。
2. 使用密钥调度算法KSA打乱 S-box。
3. 使用伪随机生成算法PRGA逐字节异或加密。
> ⚠️ 注意:此实现中返回的是 `.join(chr(...))` 后再 `.encode('iso-8859-1')`,需注意字符边界问题。
---
#### 方法:`encode_bytes(self, bdata: bytes, key: bytes) -> bytes`
对字节数据执行带盐值的加密。
##### 流程:
1. 计算密钥摘要:`sha1(key + self.salt).digest()`
2. 使用上述密钥对 `bdata` 执行 `_crypt`
3. 将原始 salt 前缀附加到密文前(共 16 字节)
##### 返回:
- `salt + encrypted_data`bytes
---
#### 方法:`encode(self, data: str/bytes, key: str, encode=base64.b64encode) -> str`
高层加密接口,支持字符串输入和最终编码。
##### 参数:
- `data`: 明文(字符串或字节)
- `key`: 密钥(字符串)
- `encode`: 可选编码函数(如 `base64.b64encode`),设为 `None` 则不编码
##### 行为:
-`data` 是字符串,则按 `dcoding` 编码为字节
- 调用 `encode_bytes` 加密
- 若指定 `encode` 函数,则对结果进行编码(如 Base64
- 返回编码后的字符串UTF-8 解码)
> ✅ 示例:
> ```python
> rc = RC4()
> code = rc.encode("hello", "mykey")
> ```
---
#### 方法:`decode_bytes(self, data: bytes, key: bytes) -> bytes`
解密由 `encode_bytes` 生成的数据。
##### 步骤:
1. 提取前 16 字节作为 salt但实际未使用应为 bug
2. 使用 `sha1(key + self.salt)` 生成密钥
3. 对剩余部分调用 `_crypt` 解密
> ❗⚠️ Bug 提示:虽然提取了 salt但在密钥生成中仍使用固定的 `self.salt`,而非从输入读取的 salt。这导致无法正确处理不同 salt 的情况。
##### 返回:
- 解密后的原始数据bytes
---
#### 方法:`decode(self, data: str/bytes, key: str, decode=base64.b64decode) -> str`
高层解密接口。
##### 参数:
- `data`: 已加密并可选编码过的数据
- `key`: 解密密钥
- `decode`: 解码函数(默认 Base64
##### 行为:
-`data` 是字符串,先用 `dcoding` 编码成字节
-`decode` 存在,先解码(如 Base64 解码)
- 调用 `decode_bytes` 解密
- 结果以 `dcoding` 解码为字符串返回
> ✅ 示例:
> ```python
> text = rc.decode(code, "mykey")
> ```
---
### 2. `KeyChain` 类 —— 时间同步密钥链
提供基于时间窗口的动态密钥管理和自动密钥匹配功能,适用于分布式环境下的安全通信。
#### 初始化:`__init__(seed_str, crypter=None, keylen=23, period=600, threshold=60, time_delta=0)`
| 参数 | 类型 | 默认值 | 说明 |
|-------------|----------|-----------|------|
| `seed_str` | str/bytes | - | 种子字符串,用于派生密钥 |
| `crypter` | RC4 实例 | None | 自定义加密器,若无则创建默认 RC4 |
| `keylen` | int | 23 | 生成密钥的字符长度 |
| `period` | int | 600 | 时间窗口周期(秒),即每 10 分钟换一次密钥 |
| `threshold` | int | 60 | 容差阈值(秒),判断是否接近周期边界 |
| `time_delta` | int | 0 | 时间偏移量(可用于调试或校准) |
##### 内部属性:
- `keypool`: 缓存已生成的密钥 `{indicator: key}`
- `timezone`: 设置为 GMT 时区
- `indicator`: 当前时间所属的时间段起点(如每 600 秒一个区块)
---
#### 方法:`get_timestamp(self) -> int`
获取当前 Unix 时间戳(减去 `time_delta`
---
#### 方法:`get_indicator(ts=None) -> int`
计算时间指示器(所在周期的起始时间)
例如:
- `period=600` → 每 10 分钟一个周期
- `ts=1712345678` → indicator = `(1712345678 // 600) * 600`
##### 返回:
- 当前时间所属周期的起始时间戳
---
#### 方法:`genKey(indicator) -> bytes`
根据 `indicator``seed_str` 生成唯一密钥。
##### 算法逻辑:
1. 若缓存中已有对应密钥,直接返回
2. 否则使用循环算法从 `seed_str` 中按规则选取字符构造密钥:
- 初始值 `v = indicator`
- 每次取 `j = v % keylen` 作为索引
-`seed_str[j]` 取字符追加
- 更新 `v = v - (j + k1)*m + keylen`
- 直到生成 `keylen` 长度的密钥
3. 缓存密钥,并清理过期条目(早于 `indicator - period` 的)
> 🔐 安全性:密钥依赖时间和种子,难以预测
---
#### 方法:`encode_bytes(bdata: bytes) -> bytes`
使用当前时间对应的密钥加密数据。
##### 流程:
1. 获取当前 `indicator`
2. 生成对应密钥 `key`
3. 构造明文:`key + bdata`(将密钥本身也加密传输)
4. 使用 `crypter.encode_bytes(data, key)` 加密
> 📦 输出结构:`salt + encrypted(key + bdata)`
---
#### 方法:`decode_bytes(data: bytes) -> bytes or None`
智能解密:尝试用当前、上一周期、下一周期的密钥解密。
##### 步骤:
1. 获取当前 `indicator` 和密钥
2. 尝试解密
3. 验证解密后数据前缀是否等于密钥(完整性校验)
4. 如果失败且接近周期底部(即将切换),尝试上一周期密钥
5. 如果接近顶部(刚过切换点),尝试下一周期密钥
##### 返回:
- 成功:解密后的原始数据(不含密钥头)
- 失败:`None`
---
#### 方法:`encode(text: str) -> bytes`
加密字符串版本,内部转为 UTF-8 字节后调用 `encode_bytes`
---
#### 方法:`decode(data: bytes) -> str or None`
解密并返回 UTF-8 字符串;若失败返回 `None`
---
## 辅助函数
### `password(pwdtxt: str, key=pwdkey) -> str or None`
使用固定密钥对密码文本加密并验证。
##### 步骤:
1. 加密 `pwdtxt`
2. 立即解密验证一致性
3. 一致则返回加密结果Base64 编码字符串),否则返回 `None`
> ✅ 用途:确保加密过程可靠
---
### `unpassword(code: str, key=pwdkey) -> str or None`
解密由 `password()` 生成的密文。
##### 返回:
- 明文字符串 或 `None`
---
## 使用示例
```python
if __name__ == '__main__':
data = b"231r3 feregrenerjk gkht324g8924gnfw ;ejkvwkjerv"
key = b'123456'
rc4 = RC4()
kc = KeyChain('in the heaven, we are equal', rc4)
print("原始数据:", data)
# 加密
encoded_data = kc.encode_bytes(data)
print("加密后数据:", encoded_data, "长度:", len(encoded_data))
# 解密
decoded_data = kc.decode_bytes(encoded_data)
print("解密数据:", decoded_data)
print("解密成功:", decoded_data == data)
```
---
## 安全性分析
| 特性 | 评估 |
|------|------|
| **RC4 算法** | 已知存在弱点(如偏差输出),不推荐用于高安全场景 |
| **Salt 固定** | `self.salt` 固定可能导致重放攻击风险 |
| **密钥派生** | 自定义算法非标准,缺乏密码学证明 |
| **密钥包含在明文中加密** | 有一定防篡改作用,但仍可能被暴力破解 |
| **时间同步机制** | 适合短期令牌、API 认证等场景 |
| **Base64 支持** | 方便文本传输 |
> ✅ 推荐用途:轻量级认证令牌、会话加密、临时凭证
> ❌ 不推荐:金融交易、长期存储加密
---
## 已知问题与改进建议
| 问题 | 描述 | 建议 |
|------|------|-------|
| ❗ Salt 未真正参与密钥派生 | `decode_bytes` 忽略传入 salt始终用固定 salt | 应使用传入 salt 生成密钥 |
| ⚠️ `_crypt` 返回方式不安全 | 使用 `chr()` 可能超出 ASCII 范围引发错误 | 改为直接构建字节数组 |
| ⚠️ RC4 已过时 | 存在已知漏洞(如 WEP 攻击) | 替换为 AES-CTR 或 ChaCha20 |
| 🔒 自定义密钥生成算法 | 非标准化,可能存在碰撞或弱密钥 | 使用 HMAC-SHA256 等标准 KDF |
| 💤 时间依赖性强 | 严重依赖系统时间准确性 | 增加强时间验证或 NTP 校准提示 |
---
## 总结
本模块实现了一套基于 RC4 和时间窗口密钥链的安全通信原型,具备以下优点:
- 简洁易集成
- 支持自动密钥轮换
- 具备时间容忍机制
- 可用于短生命周期数据保护
建议在低风险场景中使用,并考虑升级至更现代的加密算法(如 AES-GCM 或 ChaCha20-Poly1305以提升安全性。
---
> 文档版本v1.0
> 最后更新2025-04-05