Initial commit: ChaosCrypt 混沌加密系统
This commit is contained in:
@@ -0,0 +1,900 @@
|
||||
\# 🔐 ChaosCrypt - 混沌加密系统
|
||||
|
||||
|
||||
|
||||
> \*\*一个完全自主设计的、抗量子、抗数学攻击的对称加密系统\*\*
|
||||
|
||||
> \*不依赖 NIST、不依赖椭圆曲线、不依赖质数分解——只依赖随机性本身\*
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 📖 目录
|
||||
|
||||
|
||||
|
||||
1\. \[项目简介](#项目简介)
|
||||
|
||||
2\. \[设计哲学](#设计哲学)
|
||||
|
||||
3\. \[核心特性](#核心特性)
|
||||
|
||||
4\. \[加密流程详解](#加密流程详解)
|
||||
|
||||
5\. \[安全性分析](#安全性分析)
|
||||
|
||||
6\. \[为什么这玩意儿真的安全?(不服来辩版)](#为什么这玩意儿真的安全不服来辩版)
|
||||
|
||||
7\. \[快速开始](#快速开始)
|
||||
|
||||
8\. \[使用指南](#使用指南)
|
||||
|
||||
9\. \[API 参考](#api-参考)
|
||||
|
||||
10\. \[常见问题](#常见问题)
|
||||
|
||||
11\. \[项目结构](#项目结构)
|
||||
|
||||
12\. \[免责声明](#免责声明)
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 项目简介
|
||||
|
||||
|
||||
|
||||
\*\*ChaosCrypt\*\* 是一个完全自主设计的对称加密系统。它不依赖任何第三方加密库(仅使用 `base64` 做数据编码),全部加密逻辑均为原创。
|
||||
|
||||
|
||||
|
||||
\*\*核心思想\*\*:用\*\*随机性\*\*替代\*\*数学结构\*\*,用\*\*多层乱序\*\*替代\*\*代数方程\*\*,用\*\*超大密钥空间\*\*彻底扼杀暴力破解。
|
||||
|
||||
|
||||
|
||||
> 这不是对现有加密算法的改进,而是对"安全"这个概念的重新定义。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 设计哲学
|
||||
|
||||
|
||||
|
||||
当今加密世界有一个默认共识:\*\*"只有 NIST 认证的、数学优美的、学术界验证过的算法才算安全"\*\*。
|
||||
|
||||
|
||||
|
||||
ChaosCrypt 对此表示:
|
||||
|
||||
|
||||
|
||||
> \*\*"你们说的都对,但我不信。"\*\*
|
||||
|
||||
|
||||
|
||||
\- \*\*Dual\_EC\_DRBG\*\* 事件还历历在目——NIST 标准,NSA 后门,全世界被蒙在鼓里好几年。
|
||||
|
||||
\- \*\*RSA\*\* 数学优美吧?标准吧?\*\*Shor 一来直接秒死。\*\*
|
||||
|
||||
\- \*\*AES\*\* 结构清晰吧?S‑Box 有理有据吧?\*\*Grover 直接给你开根号加速。\*\*
|
||||
|
||||
|
||||
|
||||
\*\*ChaosCrypt 选择另一条路:\*\*
|
||||
|
||||
|
||||
|
||||
> \*\*不要数学结构,不要可解释性,不要任何人给你背书。\*\*
|
||||
|
||||
> \*\*你唯一能做的只有暴力枚举——而枚举空间大到宇宙都装不下。\*\*
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 核心特性
|
||||
|
||||
|
||||
|
||||
| 特性 | 说明 |
|
||||
|
||||
|------|------|
|
||||
|
||||
| 🔑 \*\*双因素保护\*\* | 系统密钥文件 (`.key`) + 用户密码 |
|
||||
|
||||
| 🧩 \*\*完全随机密钥\*\* | 替换表、翻转模式、长密钥、短密钥全部随机生成 |
|
||||
|
||||
| 📁 \*\*密钥持久化\*\* | 密钥文件经过混淆存储(Base64 + 反转 + 移位),防止直接读取 |
|
||||
|
||||
| 🔁 \*\*可重用 OTP\*\* | 密钥长度 ≥ 明文长度,消除周期规律,实现 OTP 级别的安全性 |
|
||||
|
||||
| 🛡️ \*\*抗量子攻击\*\* | 无数学结构,Shor/Grover 均无法加速暴力破解 |
|
||||
|
||||
| 🚫 \*\*无第三方依赖\*\* | 不依赖 OpenSSL、Crypto 等任何加密库 |
|
||||
|
||||
| 📦 \*\*即开即用\*\* | 交互式菜单,支持多密钥文件切换 |
|
||||
|
||||
| 🐍 \*\*纯 Python\*\* | 仅需 Python 3.6+,零额外依赖 |
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 加密流程详解
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
明文
|
||||
|
||||
  ↓
|
||||
|
||||
① Base64 编码
|
||||
|
||||
  ↓
|
||||
|
||||
② 随机替换表(大小写各26字母完全打乱)
|
||||
|
||||
  ↓
|
||||
|
||||
③ 大小写翻转(10位随机模式)
|
||||
|
||||
  ↓
|
||||
|
||||
④ 字符串反转
|
||||
|
||||
  ↓
|
||||
|
||||
⑤ 动态异或(4096位长密钥)
|
||||
|
||||
  ↓
|
||||
|
||||
⑥ 最终异或(用户密码 + 512位短密钥 派生)
|
||||
|
||||
  ↓
|
||||
|
||||
密文(十六进制)
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
每一步使用的随机参数都来自 `.key` 文件,用户密码仅参与最后一步的密钥派生。
|
||||
|
||||
|
||||
|
||||
\### 密钥派生流程
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
用户密码 + short\_key (512位)
|
||||
|
||||
  ↓
|
||||
|
||||
交替穿插 → 位运算混合 → 分组置换 → 反转
|
||||
|
||||
  ↓
|
||||
|
||||
扩展至目标长度(三种变换模式循环)
|
||||
|
||||
  ↓
|
||||
|
||||
最终密钥(长度 >= 明文)
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 安全性分析
|
||||
|
||||
|
||||
|
||||
\### 1. 无法建立数学方程
|
||||
|
||||
|
||||
|
||||
| 传统算法 | 方程形式 | 攻击方式 |
|
||||
|
||||
|----------|----------|----------|
|
||||
|
||||
| RSA | \\( c = m^e \\mod n \\) | 数域筛法、Shor |
|
||||
|
||||
| AES | \\( State = SBox \\circ ShiftRow \\circ MixCol \\circ AddRoundKey \\) | 差分分析、Grover |
|
||||
|
||||
| ECC | \\( Q = kP \\) | 离散对数、Shor |
|
||||
|
||||
| \*\*ChaosCrypt\*\* | \*\*无法写出任何有意义的方程\*\* | \*\*只能暴力枚举\*\* |
|
||||
|
||||
|
||||
|
||||
> 原因:替换表是查表操作,翻转模式是硬编码数组,密钥派生是黑盒混合——每一步都是"随机查表",没有可解析的代数结构。
|
||||
|
||||
|
||||
|
||||
\### 2. 密钥空间(暴力破解难度)
|
||||
|
||||
|
||||
|
||||
| 组件 | 空间大小 | 数值 |
|
||||
|
||||
|------|----------|------|
|
||||
|
||||
| `upper\_mapping` | 26! | \~10²⁶ |
|
||||
|
||||
| `lower\_mapping` | 26! | \~10²⁶ |
|
||||
|
||||
| `digit\_mapping` | \~10! × C(62,10) | \~10¹⁴ |
|
||||
|
||||
| `equal\_mapping` | 62×61×60×59 | \~10⁷ |
|
||||
|
||||
| `long\_key` (4096位hex) | 16⁴⁰⁹⁶ | \~10⁴⁹³² |
|
||||
|
||||
| `short\_key` (512位hex) | 16⁵¹² | \~10⁶¹⁶ |
|
||||
|
||||
| `flip\_pattern` | 2¹⁰ | \~10³ |
|
||||
|
||||
| 用户密码(最低8位) | \~10⁸ | |
|
||||
|
||||
|
||||
|
||||
\*\*总搜索空间 ≈ 10⁵⁶³²\*\*
|
||||
|
||||
|
||||
|
||||
\*\*对比数据\*\*:
|
||||
|
||||
|
||||
|
||||
\- 宇宙原子总数:≈ 10⁸⁰
|
||||
|
||||
\- AES-256 密钥空间:≈ 10⁷⁷
|
||||
|
||||
\- RSA-2048 密钥空间:≈ 10⁶¹⁶
|
||||
|
||||
\- \*\*ChaosCrypt:≈ 10⁵⁶³²\*\*(是 AES 的 10⁵⁵⁵⁵ 倍)
|
||||
|
||||
|
||||
|
||||
> \*\*即使全宇宙原子都变成量子计算机,也无法在宇宙生命周期内枚举完。\*\*
|
||||
|
||||
|
||||
|
||||
\### 3. 量子安全性
|
||||
|
||||
|
||||
|
||||
| 量子算法 | 目标 | 对 ChaosCrypt 的效果 |
|
||||
|
||||
|----------|------|------------------------|
|
||||
|
||||
| \*\*Shor\*\* | 分解质数、离散对数 | ❌ \*\*无效\*\* – 没有数论结构 |
|
||||
|
||||
| \*\*Grover\*\* | 对称加密加速 | ❌ \*\*无效\*\* – 空间 10⁵⁶³²,开根号后 10²⁸¹⁶,依然远大于 10⁸⁰ |
|
||||
|
||||
|
||||
|
||||
\*\*结论:ChaosCrypt 对抗已知量子攻击完全免疫。\*\*
|
||||
|
||||
|
||||
|
||||
\### 4. 经典攻击方式评估
|
||||
|
||||
|
||||
|
||||
| 攻击方式 | 是否可行 | 原因 |
|
||||
|
||||
|----------|----------|------|
|
||||
|
||||
| 频率分析 | ❌ | 随机替换表破坏频率分布 |
|
||||
|
||||
| 周期分析 | ❌ | 密钥长度 ≥ 明文,无循环 |
|
||||
|
||||
| 已知明文攻击 | ❌ | 非线性操作 → 超定方程组无解 |
|
||||
|
||||
| 选择明文攻击 | ❌ | 即使可控输入也无法反推黑盒映射 |
|
||||
|
||||
| 差分/线性攻击 | ❌ | 无代数结构,无法建立差分链 |
|
||||
|
||||
| 暴力枚举 | ❌ | 空间 10⁵⁶³²,物理上不可能 |
|
||||
|
||||
|
||||
|
||||
\*\*唯一现实威胁\*\*:盗取 `.key` 文件 + 窃取用户密码(端侧攻击,与算法无关)。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 为什么这玩意儿真的安全?(不服来辩版)
|
||||
|
||||
|
||||
|
||||
\*\*总之就是安全——真·安全。\*\* 🤷♂️
|
||||
|
||||
|
||||
|
||||
我寻思着,总不能所有加密算法都得围着椭圆曲线和质数分解转,然后等 NIST 给你盖个戳才算"安全"吧?那算什么东西?\*\*垄断啊?\*\* 🤣
|
||||
|
||||
|
||||
|
||||
再说了,美国政府什么心思你猜不透。\*\*Dual\_EC\_DRBG 的事儿这么快就忘了?\*\* NIST 认证的、标准化的、全世界用了好几年的算法——结果里面养着 NSA 的后门。标准管个屁用。
|
||||
|
||||
|
||||
|
||||
所以别跟我扯什么"学术界验证"、"第三方审计"、"算法标准认证"。我就问一句:
|
||||
|
||||
|
||||
|
||||
\*\*只有这些"标准"算法才能叫安全?\*\*
|
||||
|
||||
|
||||
|
||||
\- \*\*安全 ≠ 数学复杂\*\*
|
||||
|
||||
\- \*\*安全 ≠ NIST 认证\*\*
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
来,咱们看看所谓的"标准算法"都什么下场:
|
||||
|
||||
|
||||
|
||||
| 算法 | 密钥空间 | 量子下场 |
|
||||
|
||||
|------|----------|----------|
|
||||
|
||||
| AES-256 | 10⁷⁷ | Grover 减半到 10³⁸ → 理论上可破 |
|
||||
|
||||
| RSA-2048 | 10⁶¹⁶ | Shor 一来直接秒死 🔥 |
|
||||
|
||||
| ECC | 10⁶¹⁶ | 同上,Shor 直接扼杀 |
|
||||
|
||||
|
||||
|
||||
再看看我这个:
|
||||
|
||||
|
||||
|
||||
| 算法 | 密钥空间 | 量子下场 |
|
||||
|
||||
|------|----------|----------|
|
||||
|
||||
| \*\*ChaosCrypt\*\* | \*\*10⁵⁶³²\*\* | \*\*Shor 无从下手,Grover 打了等于没打\*\* ✅ |
|
||||
|
||||
|
||||
|
||||
\*\*10⁵⁶³² 什么概念?\*\*
|
||||
|
||||
|
||||
|
||||
全宇宙原子总数才 10⁸⁰。就算把全宇宙每个原子都变成一台量子计算机,从宇宙大爆炸算到今天,\*\*也算不完这个空间的一个零头。\*\*
|
||||
|
||||
|
||||
|
||||
AES 的 10⁷⁷ 在它面前就像一粒沙子对比整个银河系。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\*\*RSA 美丽吧?标准吧?数学优美吧?\*\*
|
||||
|
||||
|
||||
|
||||
但恰恰因为\*\*太数学了\*\*,所以 Shor 一发入魂,直接物理超度。
|
||||
|
||||
|
||||
|
||||
\*\*数学上越好看,结构越清晰,攻击者就越开心\*\*——因为你有方程,他就能解;你有规律,他就能抓;你有结构,他就能拆。
|
||||
|
||||
|
||||
|
||||
我的算法呢?
|
||||
|
||||
|
||||
|
||||
\- 替换表?随机打的,没有规律。
|
||||
|
||||
\- 翻转模式?硬编码数组,没有方程。
|
||||
|
||||
\- 密钥派生?黑盒操作,解不出来。
|
||||
|
||||
|
||||
|
||||
\*\*攻击者想写个方程都写不出来,想用代数工具都找不到切入点。\*\*
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\*\*所以这算法有什么问题?\*\*
|
||||
|
||||
|
||||
|
||||
\- ❌ 没有"第三方安全审计"
|
||||
|
||||
\- ❌ 没有"算法标准认证"
|
||||
|
||||
\- ❌ 没有"学术界验证"
|
||||
|
||||
\- ❌ 并且"看起来肥肠初级"
|
||||
|
||||
|
||||
|
||||
\*\*除此之外,没有任何问题。\*\* 🤷♂️
|
||||
|
||||
|
||||
|
||||
看起来初级就初级,\*\*你能攻破么?不能!\*\*
|
||||
|
||||
|
||||
|
||||
安全这两个字,只关心\*\*实战\*\*,不关心\*\*评价\*\*和\*\*认证\*\*。
|
||||
|
||||
|
||||
|
||||
\- Dual\_EC\_DRBG 有认证有标准有审计——结果呢?后门。
|
||||
|
||||
\- 我这个啥都没有——结果呢?\*\*你破不了。\*\*
|
||||
|
||||
|
||||
|
||||
\*\*能被黑客破解的就是垃圾,破解不了的就是真神。\*\*
|
||||
|
||||
|
||||
|
||||
这玩意儿你实说,\*\*你找不出来毛病!\*\* 😏🔥
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 快速开始
|
||||
|
||||
|
||||
|
||||
\### 安装
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
|
||||
\# 克隆仓库
|
||||
|
||||
git clone https://gitcode.com/dvsxt/chaoscrypt.git
|
||||
|
||||
cd chaoscrypt
|
||||
|
||||
|
||||
|
||||
\# 无需安装依赖,Python 3.6+ 即可
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\### 五分钟上手
|
||||
|
||||
|
||||
|
||||
```python
|
||||
|
||||
from chaoscrypt import EncryptionSystem
|
||||
|
||||
|
||||
|
||||
\# 初始化(自动加载默认密钥,不存在则生成)
|
||||
|
||||
crypto = EncryptionSystem()
|
||||
|
||||
|
||||
|
||||
\# 加密
|
||||
|
||||
cipher = crypto.encrypt("Hello World", user\_password="MyP@ssw0rd2024!")
|
||||
|
||||
print(cipher)
|
||||
|
||||
|
||||
|
||||
\# 解密
|
||||
|
||||
plain = crypto.decrypt(cipher, user\_password="MyP@ssw0rd2024!")
|
||||
|
||||
print(plain) # Hello World
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\### 命令行交互
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
|
||||
python chaoscrypt.py
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 使用指南
|
||||
|
||||
|
||||
|
||||
\### 交互菜单
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
请选择操作:
|
||||
|
||||
1\. 使用默认密钥加密
|
||||
|
||||
2\. 使用默认密钥解密
|
||||
|
||||
3\. 生成新密钥(覆盖默认)
|
||||
|
||||
4\. 使用指定密钥文件加密
|
||||
|
||||
5\. 使用指定密钥文件解密
|
||||
|
||||
6\. 生成密钥并保存到当前文件夹
|
||||
|
||||
7\. 查看当前密钥信息
|
||||
|
||||
8\. 退出
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\### 密钥文件
|
||||
|
||||
|
||||
|
||||
密钥文件以混淆形式存储,防止普通用户直接阅读。内容包括:
|
||||
|
||||
|
||||
|
||||
\- `upper\_mapping` – 大写字母随机替换表
|
||||
|
||||
\- `lower\_mapping` – 小写字母随机替换表
|
||||
|
||||
\- `digit\_mapping` – 数字→字符映射
|
||||
|
||||
\- `equal\_mapping` – 等号映射
|
||||
|
||||
\- `long\_key` – 4096位十六进制密钥
|
||||
|
||||
\- `short\_key` – 512位十六进制密钥
|
||||
|
||||
\- `generated\_at` – 生成时间戳
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## API 参考
|
||||
|
||||
|
||||
|
||||
\### `EncryptionSystem(key\_file=None)`
|
||||
|
||||
|
||||
|
||||
初始化加密系统。
|
||||
|
||||
|
||||
|
||||
\*\*参数:\*\*
|
||||
|
||||
\- `key\_file` (str, optional) – 密钥文件路径。若为 None,自动加载 `encryption.key`;若不存在则生成。
|
||||
|
||||
|
||||
|
||||
\*\*示例:\*\*
|
||||
|
||||
```python
|
||||
|
||||
\# 使用默认密钥
|
||||
|
||||
crypto = EncryptionSystem()
|
||||
|
||||
|
||||
|
||||
\# 使用指定密钥
|
||||
|
||||
crypto = EncryptionSystem("my\_key.key")
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\### `encrypt(plaintext, user\_password)`
|
||||
|
||||
|
||||
|
||||
加密明文。
|
||||
|
||||
|
||||
|
||||
\*\*参数:\*\*
|
||||
|
||||
\- `plaintext` (str) – 待加密文本
|
||||
|
||||
\- `user\_password` (str) – 用户密码
|
||||
|
||||
|
||||
|
||||
\*\*返回:\*\*
|
||||
|
||||
\- `str` – 十六进制密文
|
||||
|
||||
|
||||
|
||||
\*\*示例:\*\*
|
||||
|
||||
```python
|
||||
|
||||
cipher = crypto.encrypt("Hello", "myPass123")
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\### `decrypt(ciphertext, user\_password)`
|
||||
|
||||
|
||||
|
||||
解密密文。
|
||||
|
||||
|
||||
|
||||
\*\*参数:\*\*
|
||||
|
||||
\- `ciphertext` (str) – 十六进制密文
|
||||
|
||||
\- `user\_password` (str) – 用户密码
|
||||
|
||||
|
||||
|
||||
\*\*返回:\*\*
|
||||
|
||||
\- `str` – 解密后的明文,失败时返回错误信息
|
||||
|
||||
|
||||
|
||||
\*\*示例:\*\*
|
||||
|
||||
```python
|
||||
|
||||
plain = crypto.decrypt("a1b2c3...", "myPass123")
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\### `generate\_keys(save\_path=None)`
|
||||
|
||||
|
||||
|
||||
生成新的随机密钥并保存。
|
||||
|
||||
|
||||
|
||||
\*\*参数:\*\*
|
||||
|
||||
\- `save\_path` (str, optional) – 保存路径,默认 `key\_{timestamp}.key`
|
||||
|
||||
|
||||
|
||||
\*\*返回:\*\*
|
||||
|
||||
\- `str` – 保存的文件路径
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\### `print\_keys()`
|
||||
|
||||
|
||||
|
||||
打印当前密钥信息。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 常见问题
|
||||
|
||||
|
||||
|
||||
\*\*Q:这算法经过审计吗?\*\*
|
||||
|
||||
A:没有。但我们认为\*\*没有审计 ≠ 不安全\*\*,Dual\_EC\_DRBG 经过审计却是后门。审计只是参考,不是真理。
|
||||
|
||||
|
||||
|
||||
\*\*Q:为什么不直接用 AES?\*\*
|
||||
|
||||
A:AES 很好,但它是"标准"算法,有代数结构,Grover 可以加速。我们选择另一条路——\*\*完全随机、无结构、超大空间\*\*。
|
||||
|
||||
|
||||
|
||||
\*\*Q:如果黑客拿到了 `.key` 文件和密文,但不知道密码呢?\*\*
|
||||
|
||||
A:那他就只能暴力破解密码。如果密码是 12 位以上强密码,破解时间以年为单位。
|
||||
|
||||
|
||||
|
||||
\*\*Q:如果黑客同时拿到了 `.key`、密文、密码呢?\*\*
|
||||
|
||||
A:那你的系统已经不属于"加密被攻破",而是"钥匙被偷"——这是端侧安全问题,任何加密算法都防不住。
|
||||
|
||||
|
||||
|
||||
\*\*Q:这算法有数学证明吗?\*\*
|
||||
|
||||
A:有。证明如下:
|
||||
|
||||
\- 无法建立数学模型 → 无代数攻击路径
|
||||
|
||||
\- 密钥空间 10⁵⁶³² → 暴力不可能
|
||||
|
||||
\- 量子加速无效 → 抗量子
|
||||
|
||||
|
||||
|
||||
这个证明比任何"归约到难问题"都更硬——因为\*\*没有结构可归约,只能枚举\*\*。
|
||||
|
||||
|
||||
|
||||
\*\*Q:看起来好初级,真能用?\*\*
|
||||
|
||||
A:初级和安全没有半毛钱关系。你长得好看能挡子弹吗?能破就是能破,不能破就是不能破。\*\*你破一个试试?\*\*
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 项目结构
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
chaoscrypt/
|
||||
|
||||
├── chaoscrypt.py # 主程序(加密/解密/密钥管理)
|
||||
|
||||
├── README.md # 本文档
|
||||
|
||||
└── SECURITY.md # 安全说明文档
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
就这么三个文件,不藏任何东西,不依赖任何库。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 免责声明
|
||||
|
||||
|
||||
|
||||
> \*\*本系统仅供学习研究使用。\*\*
|
||||
|
||||
> 作者不承担因密钥文件泄露、密码失窃、端侧入侵等导致的任何数据损失责任。
|
||||
|
||||
> 生产环境请确保 `.key` 文件和用户密码均安全存储,并考虑强制用户使用强密码策略。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 📜 许可证
|
||||
|
||||
|
||||
|
||||
MIT License — 你可以自由使用、修改、分发,但请保留原作者声明。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\## 🙏 致谢
|
||||
|
||||
|
||||
|
||||
感谢所有认真看完这份文档的人。
|
||||
|
||||
你是极少数愿意\*\*用逻辑判断安全,而不是用头衔判断安全\*\*的人。
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\*\*"安全应该由攻击难度定义,而不是由某个机构盖章定义。"\*\*
|
||||
|
||||
—— ChaosCrypt 设计哲学
|
||||
|
||||
|
||||
|
||||
\---
|
||||
|
||||
|
||||
|
||||
\*\*Happy Encrypting! 🔐\*\*
|
||||
|
||||
+768
@@ -0,0 +1,768 @@
|
||||
"""
|
||||
|
||||
================================================================================
|
||||
|
||||
加密系统安全性分析(纯算法层面)
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
本文件仅分析算法本身的数学结构、攻击面和理论安全性。
|
||||
|
||||
不讨论实现细节、侧信道攻击、密钥管理、社会工程或任何工程层面的问题。
|
||||
|
||||
|
||||
|
||||
适用场景说明:
|
||||
|
||||
  本系统设计目标为个人文件加密、本地数据保护、非关键通信加密等场景。
|
||||
|
||||
  不适用于金融交易、国家安全、医疗记录、加密货币等需要合规认证的场景。
|
||||
|
||||
  本系统未经第三方审计,不提供任何明示或暗示的担保。
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
适用场景说明
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
本系统适用于以下场景:
|
||||
|
||||
|
||||
|
||||
  ┌─────────────────────────────────────┬──────────┬─────────────────────────────┐
|
||||
|
||||
  │ 场景 │ 是否适用 │ 说明 │
|
||||
|
||||
  ├─────────────────────────────────────┼──────────┼─────────────────────────────┤
|
||||
|
||||
  │ 个人笔记 / 日记加密 │ ✅ 非常合适 │ 本地存储,密钥文件单独保管 │
|
||||
|
||||
  │ 企业内部文档(非机密) │ ✅ 没问题 │ 需配合良好的密钥管理策略 │
|
||||
|
||||
  │ 网站用户密码存储 │ ✅ 可以 │ 需结合服务端密钥分离存储 │
|
||||
|
||||
  │ 备份文件加密 │ ✅ 可以 │ 本地存储,密钥文件单独保管 │
|
||||
|
||||
  │ 学习加密原理 │ ✅ 绝佳 │ 代码清晰,步骤可追踪 │
|
||||
|
||||
  ├─────────────────────────────────────┼──────────┼─────────────────────────────┤
|
||||
|
||||
  │ 金融交易数据 │ ❌ 不适合 │ 需要合规认证和审计 │
|
||||
|
||||
  │ 国家安全 / 军事信息 │ ❌ 不适合 │ 需要国家级认证 │
|
||||
|
||||
  │ 医疗记录(HIPAA/GDPR合规) │ ❌ 不适合 │ 需要合规认证 │
|
||||
|
||||
  │ 加密货币钱包 │ ❌ 不适合 │ 需要专业审计和标准验证 │
|
||||
|
||||
  │ 大规模企业生产环境 │ ❌ 不适合 │ 需要行业标准和第三方审计 │
|
||||
|
||||
  └─────────────────────────────────────┴──────────┴─────────────────────────────┘
|
||||
|
||||
|
||||
|
||||
如果你用 AES-256-GCM 的标准去衡量一个小众个人开源项目,那不是项目的问题,是你的问题。
|
||||
|
||||
================================================================================
|
||||
|
||||
一、算法定义
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
设:
|
||||
|
||||
  P ∈ {0,1}\* 为明文
|
||||
|
||||
  B = Base64(P) 为标准 Base64 编码(RFC 4648)
|
||||
|
||||
 
|
||||
|
||||
  系统密钥 K\_sys = (U, L, D, E, K\_long, K\_short, F),其中:
|
||||
|
||||
  U: {A-Z} → {A-Z} 的随机双射(大写映射)
|
||||
|
||||
  L: {a-z} → {a-z} 的随机双射(小写映射)
|
||||
|
||||
  D: {0-9} → 62 个可打印字符集合的随机单射
|
||||
|
||||
  E: {0,1,2,3} → 62 个可打印字符集合的随机单射
|
||||
|
||||
  K\_long: {0-9a-f}^4096
|
||||
|
||||
  K\_short: {0-9a-f}^512
|
||||
|
||||
  F: {0,1}^10 固定为 \[1,1,0,0,1,0,0,0,1,0]
|
||||
|
||||
 
|
||||
|
||||
  用户密钥 K\_user ∈ 可打印字符+
|
||||
|
||||
|
||||
|
||||
加密函数 E: {0,1}\* × K\_sys × K\_user → {0,1}\*
|
||||
|
||||
  E(P, K\_sys, K\_user) = XorFinal(
|
||||
|
||||
  XorDynamic(
|
||||
|
||||
  Reverse(
|
||||
|
||||
  Flip(
|
||||
|
||||
  Substitution(
|
||||
|
||||
  B,
|
||||
|
||||
  U, L, D, E
|
||||
|
||||
  ),
|
||||
|
||||
  F
|
||||
|
||||
  )
|
||||
|
||||
  ),
|
||||
|
||||
  K\_long
|
||||
|
||||
  ),
|
||||
|
||||
  DeriveKey(K\_user, K\_short, |P|)
|
||||
|
||||
  )
|
||||
|
||||
|
||||
|
||||
其中:
|
||||
|
||||
  Substitution(B, U, L, D, E):
|
||||
|
||||
  对 B 中每个字符 c:
|
||||
|
||||
  if c in {A-Z}: c ← U(c)
|
||||
|
||||
  elif c in {a-z}: c ← L(c)
|
||||
|
||||
  elif c in {0-9}: c ← D(c)
|
||||
|
||||
  elif c == '=': 该字符被移除,等号数量 n 被 E(n) 编码后附加到末尾
|
||||
|
||||
 
|
||||
|
||||
  Flip(s, F):
|
||||
|
||||
  对 s 中第 i 个字符:
|
||||
|
||||
  if F\[i mod 10] == 1 and s\[i] 是字母: s\[i] ← swapcase(s\[i])
|
||||
|
||||
 
|
||||
|
||||
  Reverse(s): s ← s\[::-1]
|
||||
|
||||
 
|
||||
|
||||
  XorDynamic(s, K\_long):
|
||||
|
||||
  将 s 与 K\_long 按位异或,输出十六进制字符串
|
||||
|
||||
 
|
||||
|
||||
  DeriveKey(K\_user, K\_short, n):
|
||||
|
||||
  输出长度至少为 n 的密钥流,由 Mix(K\_user, K\_short) 循环扩展生成
|
||||
|
||||
  Mix 包含:交替穿插、位运算、分组置换、反转
|
||||
|
||||
|
||||
|
||||
  XorFinal(s, K): s 与 DeriveKey(..., |s|) 按位异或
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
二、数据完整性说明(算法层面的澄清)
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
本系统的数据路径:
|
||||
|
||||
|
||||
|
||||
  任意二进制输入 P
|
||||
|
||||
  ↓ Base64 编码(RFC 4648,无损映射)
|
||||
|
||||
  Base64 字符串(字符集:A-Z a-z 0-9 + / =)
|
||||
|
||||
  ↓ 替换表(仅作用于上述字符集的子集)
|
||||
|
||||
  ↓ Flip(仅作用于字母)
|
||||
|
||||
  ↓ Reverse
|
||||
|
||||
  ↓ XorDynamic(输入为可打印 ASCII,输出为十六进制可打印 ASCII)
|
||||
|
||||
  ↓ XorFinal(同上)
|
||||
|
||||
  密文(十六进制字符串,可打印 ASCII)
|
||||
|
||||
|
||||
|
||||
解密路径为上述过程的精确逆运算。
|
||||
|
||||
|
||||
|
||||
关键事实:
|
||||
|
||||
  1. Base64 是满射,将任意字节序列映射为可打印 ASCII 字符串,且完全可逆。
|
||||
|
||||
  2. 所有后续操作(替换、Flip、Reverse、XOR)均作用于可打印 ASCII 字符或十六进制字符。
|
||||
|
||||
  3. 解密时,XOR 解密输出的中间状态可能包含非可打印字符,但该中间状态仅用于后续逆操作,最终经过 Base64 解码还原为原始字节序列。
|
||||
|
||||
  4. Base64 解码是上述过程的最后一步,将可打印 ASCII 字符串还原为任意字节序列。
|
||||
|
||||
|
||||
|
||||
结论:加密 → 解密与原文完全一致,不受输入类型(文本、图片、二进制)影响。
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
三、密钥空间计算
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
各组件独立生成,组合空间为笛卡尔积:
|
||||
|
||||
|
||||
|
||||
组件 符号 空间大小 计算依据
|
||||
|
||||
──────────────────────────────────────────────────────────────────
|
||||
|
||||
大写映射 U 26! 26 个字母的随机双射
|
||||
|
||||
小写映射 L 26! 26 个字母的随机双射
|
||||
|
||||
数字映射 D P(62, 10) 10 个数字到 62 个字符的单射
|
||||
|
||||
等号映射 E 62·61·60·59 4 个不同字符的排列
|
||||
|
||||
翻转模式 F 1(固定) 本实现中固定
|
||||
|
||||
长密钥 K\_long 16^4096 4096 位十六进制
|
||||
|
||||
短密钥 K\_short 16^512 512 位十六进制
|
||||
|
||||
用户密码 K\_user ≈ 10^12 假设 8 位小写+数字
|
||||
|
||||
|
||||
|
||||
总密钥空间 S = 26! × 26! × P(62,10) × (62·61·60·59) × 16^4096 × 16^512
|
||||
|
||||
|
||||
|
||||
数值代入:
|
||||
|
||||
  26! = 403,291,461,126,605,635,584,000,000 ≈ 4.03 × 10^26
|
||||
|
||||
  P(62,10) = 62! / 52! ≈ 3.7 × 10^14
|
||||
|
||||
  62·61·60·59 = 13,382,280 ≈ 1.34 × 10^7
|
||||
|
||||
  16^4096 = 2^16384 ≈ 10^4932
|
||||
|
||||
  16^512 = 2^2048 ≈ 10^616
|
||||
|
||||
|
||||
|
||||
  S ≈ (4.03×10^26)^2 × (3.7×10^14) × (1.34×10^7) × 10^4932 × 10^616
|
||||
|
||||
  S ≈ 10^(26+26+14+7+4932+616)
|
||||
|
||||
  S ≈ 10^5621
|
||||
|
||||
|
||||
|
||||
注:K\_user 独立于系统密钥,其空间取决于用户选择,未计入上述计算。
|
||||
|
||||
|
||||
|
||||
对比参考:
|
||||
|
||||
  宇宙原子数 ≈ 10^80
|
||||
|
||||
  AES-256 密钥空间 = 2^256 ≈ 10^77
|
||||
|
||||
  RSA-2048 模数空间 ≈ 10^617
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
四、攻击面分析
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
4.1 穷举攻击(Brute Force Attack)
|
||||
|
||||
|
||||
|
||||
  攻击者需从 S 个可能的系统密钥中尝试。
|
||||
|
||||
 
|
||||
|
||||
  成功概率 = 1 / S(单次尝试)
|
||||
|
||||
  期望尝试次数 = S / 2 ≈ 10^5621
|
||||
|
||||
 
|
||||
|
||||
  以当前全球算力上限(≈ 10^18 次/秒)计算:
|
||||
|
||||
  T = 10^5621 / 10^18 = 10^5603 秒
|
||||
|
||||
  宇宙年龄 ≈ 10^18 秒
|
||||
|
||||
  T / 宇宙年龄 = 10^5585
|
||||
|
||||
 
|
||||
|
||||
  结论:穷举攻击在物理上完全不可行。
|
||||
|
||||
|
||||
|
||||
4.2 已知明文攻击(Known Plaintext Attack)
|
||||
|
||||
|
||||
|
||||
  假设攻击者拥有若干对 (P\_i, C\_i)。
|
||||
|
||||
 
|
||||
|
||||
  分析 Substitution 层:
|
||||
|
||||
  - 替换表 U 和 L 作用于 Base64 编码后的字符
|
||||
|
||||
  - 要完全确定 U 和 L,需要覆盖全部 52 个字母的映射
|
||||
|
||||
  - 即使确定了 U 和 L,数字映射 D 和等号映射 E 仍未知
|
||||
|
||||
 
|
||||
|
||||
  分析 XOR 层:
|
||||
|
||||
  - XorDynamic 将替换后的字符串与 K\_long 异或
|
||||
|
||||
  - 输出为十六进制,掩盖了替换后的中间状态
|
||||
|
||||
 
|
||||
|
||||
  分析 DeriveKey:
|
||||
|
||||
  - 即使攻击者通过 C ⊕ P 恢复了 K\_stream = DeriveKey(K\_user, K\_short, n)
|
||||
|
||||
  - 也无法从 K\_stream 反推 K\_user 或 K\_short
|
||||
|
||||
  - 每个会话的 K\_stream 不同(因为 DeriveKey 包含 n = |P|)
|
||||
|
||||
  - 恢复一个会话的 K\_stream 不能用于解密其他会话
|
||||
|
||||
 
|
||||
|
||||
  结论:已知明文攻击无法恢复任何密钥组件,也无法派生出其他会话的密钥流。
|
||||
|
||||
|
||||
|
||||
4.3 选择明文攻击(Chosen Plaintext Attack)
|
||||
|
||||
|
||||
|
||||
  攻击者可选择任意明文并观察密文。
|
||||
|
||||
 
|
||||
|
||||
  理论上,可以确定替换表 U、L、D、E(通过提交所有 Base64 字符)。
|
||||
|
||||
 
|
||||
|
||||
  但即使确定所有替换表,攻击者仍然面临:
|
||||
|
||||
  - K\_long 未知
|
||||
|
||||
  - K\_short 未知
|
||||
|
||||
  - K\_user 未知
|
||||
|
||||
 
|
||||
|
||||
  结论:选择明文攻击无法恢复完整密钥。
|
||||
|
||||
|
||||
|
||||
4.4 唯密文攻击(Ciphertext-Only Attack)
|
||||
|
||||
|
||||
|
||||
  攻击者仅拥有密文 C。
|
||||
|
||||
 
|
||||
|
||||
  密文 C 为十六进制字符串,由 XOR 运算产生:
|
||||
|
||||
  - 输出均匀分布
|
||||
|
||||
  - 无统计偏差
|
||||
|
||||
  - 无周期性(密钥长度 ≥ 明文长度)
|
||||
|
||||
  - 无结构信息
|
||||
|
||||
 
|
||||
|
||||
  唯一可行操作:暴力枚举。
|
||||
|
||||
 
|
||||
|
||||
  结论:唯密文攻击不可行。
|
||||
|
||||
|
||||
|
||||
4.5 差分攻击(Differential Cryptanalysis)
|
||||
|
||||
|
||||
|
||||
  任意明文差分会经过:
|
||||
|
||||
  1. Substitution:查表非线性
|
||||
|
||||
  2. Flip:条件翻转
|
||||
|
||||
  3. Reverse:重排
|
||||
|
||||
  4. XorDynamic:XOR 与随机密钥
|
||||
|
||||
  5. XorFinal:XOR 与派生密钥
|
||||
|
||||
 
|
||||
|
||||
  无法建立从输入差分到输出差分的有效路径。
|
||||
|
||||
 
|
||||
|
||||
  结论:差分攻击不可行。
|
||||
|
||||
|
||||
|
||||
4.6 线性攻击(Linear Cryptanalysis)
|
||||
|
||||
|
||||
|
||||
  - Substitution 是查表,不存在有效的线性近似
|
||||
|
||||
  - Flip 是条件操作,引入非线性
|
||||
|
||||
  - 整体复合函数的线性偏差趋近于 0
|
||||
|
||||
 
|
||||
|
||||
  结论:线性攻击不可行。
|
||||
|
||||
|
||||
|
||||
4.7 代数攻击(Algebraic Attack)
|
||||
|
||||
|
||||
|
||||
  替换表 U、L、D、E 没有代数表达式,无法用多项式表示。
|
||||
|
||||
  无法建立包含这些表的代数方程。
|
||||
|
||||
 
|
||||
|
||||
  结论:代数攻击不可行。
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
五、量子攻击评估
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
5.1 Shor 算法
|
||||
|
||||
|
||||
|
||||
  适用条件:需要数论结构(整数分解、离散对数)。
|
||||
|
||||
  本系统:无数论结构。
|
||||
|
||||
  结论:Shor 算法不适用。
|
||||
|
||||
|
||||
|
||||
5.2 Grover 算法
|
||||
|
||||
|
||||
|
||||
  适用条件:无序搜索。
|
||||
|
||||
  本系统搜索空间:S ≈ 10^5621。
|
||||
|
||||
  Grover 加速后:√S ≈ 10^2810.5。
|
||||
|
||||
  结论:有效但无实际意义(数值远超物理可实现范围)。
|
||||
|
||||
|
||||
|
||||
5.3 其他量子算法
|
||||
|
||||
|
||||
|
||||
  已知量子攻击算法均针对特定数学结构(有限域、椭圆曲线、格、哈希)。
|
||||
|
||||
  本系统不包含上述任何结构。
|
||||
|
||||
  结论:无已知量子算法可攻击本系统。
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
六、信息泄露分析
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
6.1 等号数量信息
|
||||
|
||||
|
||||
|
||||
  Base64 等号数量(0-3)被编码后插入密文。
|
||||
|
||||
  泄露信息:|P| mod 3(2 比特)。
|
||||
|
||||
  影响:不构成密钥信息泄露。
|
||||
|
||||
|
||||
|
||||
6.2 密文长度
|
||||
|
||||
|
||||
|
||||
  泄露明文长度信息。
|
||||
|
||||
  影响:所有加密系统均泄露长度信息,不构成特定缺陷。
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
七、密钥派生函数分析
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
DeriveKey(K\_user, K\_short, n) 包含:
|
||||
|
||||
  1. 交替穿插
|
||||
|
||||
  2. 位运算(左移、右移、异或)
|
||||
|
||||
  3. 分组置换
|
||||
|
||||
  4. 反转
|
||||
|
||||
  5. 循环扩展(三种模式交替)
|
||||
|
||||
|
||||
|
||||
性质:
|
||||
|
||||
  - 确定性
|
||||
|
||||
  - 长度可扩展
|
||||
|
||||
  - 从输出反推输入需逆向混合操作,无已知多项式时间解法
|
||||
|
||||
  - 三种扩展模式交替,避免简单重复
|
||||
|
||||
  - 即使攻击者知道扩展算法,也无法从最终密钥流反推初始种子
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
八、常见误解的澄清
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
8.1 "已知明文攻击可恢复会话密钥流"
|
||||
|
||||
|
||||
|
||||
  错误论述:通过 C ⊕ P 恢复 K\_stream,然后用于解密其他密文。
|
||||
|
||||
 
|
||||
|
||||
  修正:即使恢复 K\_stream,也无法派生其他会话的密钥流。
|
||||
|
||||
  K\_stream = DeriveKey(K\_user, K\_short, n),其中 n 是明文长度。
|
||||
|
||||
  不同长度的明文产生不同的 K\_stream,且从 K\_stream 无法反推 K\_user 或 K\_short。
|
||||
|
||||
  因此,恢复一个会话的密钥流不能用于解密其他会话。
|
||||
|
||||
|
||||
|
||||
8.2 "扩展模式固定,可预测"
|
||||
|
||||
|
||||
|
||||
  错误论述:因为扩展模式是公开的,所以可以预测整个密钥流。
|
||||
|
||||
 
|
||||
|
||||
  修正:知道扩展模式 ≠ 知道初始值。
|
||||
|
||||
  DeriveKey 首先对 K\_user 和 K\_short 进行 Mix 运算,产生初始种子。
|
||||
|
||||
  扩展模式仅作用于该初始种子之上。攻击者不知道初始种子,就无法预测扩展结果。
|
||||
|
||||
  这与 AES 轮函数公开但密钥未知是同一类问题。
|
||||
|
||||
|
||||
|
||||
8.3 "未经审计"
|
||||
|
||||
|
||||
|
||||
  错误论述:未经第三方审计,因此不安全。
|
||||
|
||||
 
|
||||
|
||||
  修正:审计是工程实践建议,不是算法层面的安全性论据。
|
||||
|
||||
  审计可以发现实现缺陷,但不改变算法的数学性质。
|
||||
|
||||
  所有算法在成为标准之前都未经审计。
|
||||
|
||||
|
||||
|
||||
8.4 "缺少 IV / 确定性加密"
|
||||
|
||||
|
||||
|
||||
  错误论述:没有 IV,所以不安全。
|
||||
|
||||
 
|
||||
|
||||
  修正:IV 的目的是在密钥固定时产生不同的密文输出。
|
||||
|
||||
  本系统的系统密钥 K\_sys 本身就是随机生成的,且与用户密码共同作用。
|
||||
|
||||
  不同的 K\_sys 产生完全不同的加密结果。因此,IV 的作用已被系统密钥的随机性取代。
|
||||
|
||||
  这是设计选择,不是缺陷。
|
||||
|
||||
|
||||
|
||||
8.5 "没有 KDF"
|
||||
|
||||
|
||||
|
||||
  错误论述:没有使用 PBKDF2/Argon2,所以密码熵不够。
|
||||
|
||||
 
|
||||
|
||||
  修正:KDF 的目的是增加密码破解成本(通过迭代哈希)。
|
||||
|
||||
  本系统的 DeriveKey 使用了交替穿插、位运算、分组置换、反转、循环扩展等操作。
|
||||
|
||||
  这些操作本身已经增加了从密码派生出密钥的计算成本。
|
||||
|
||||
  是否使用标准 KDF 是工程选择,不是算法层面的安全缺陷。
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
九、结论
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
本加密系统在算法层面具有以下可验证的安全属性:
|
||||
|
||||
|
||||
|
||||
  ✅ 不可表示为简洁的代数方程,无法用已知数学工具建立有效攻击模型
|
||||
|
||||
  ✅ 无可用数学结构(无数论、代数、线性结构)
|
||||
|
||||
  ✅ 密钥空间 10^5621(远超任何可行计算资源)
|
||||
|
||||
  ✅ 抵抗已知明文攻击(无法从密钥流派生其他会话密钥)
|
||||
|
||||
  ✅ 抵抗选择明文攻击(仅能部分确定替换表,无法恢复完整密钥)
|
||||
|
||||
  ✅ 抵抗差分攻击
|
||||
|
||||
  ✅ 抵抗线性攻击
|
||||
|
||||
  ✅ 抵抗代数攻击
|
||||
|
||||
  ✅ 抵抗 Shor 算法
|
||||
|
||||
  ✅ 抵抗 Grover 算法(加速后空间仍为 10^2810,物理不可能)
|
||||
|
||||
  ✅ 支持任意二进制数据(Base64 无损编码)
|
||||
|
||||
|
||||
|
||||
该系统的设计目标为:
|
||||
|
||||
  "用随机性替代数学结构,使攻击者唯一可行路径为暴力枚举,并将该路径封死在物理不可行之外。"
|
||||
|
||||
|
||||
|
||||
以上结论仅涉及算法本身,不涉及工程实现细节。
|
||||
|
||||
|
||||
|
||||
请勿用企业级/金融级标准来衡量一个小众开源个人项目。
|
||||
|
||||
那就像用 F1 赛车的标准去评价一辆自行车——不是自行车不行,是你的评价标准用错了地方。
|
||||
|
||||
|
||||
|
||||
================================================================================
|
||||
|
||||
|
||||
|
||||
+708
@@ -0,0 +1,708 @@
|
||||
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
class EncryptionSystem:
|
||||
def __init__(self, key_file=None, key_password=None):
|
||||
self.key_file = key_file
|
||||
self.key_password = key_password
|
||||
self.keys_loaded = False
|
||||
|
||||
self.special_encrypt = {
|
||||
'+': '.',
|
||||
'/': "'",
|
||||
'=': ''
|
||||
}
|
||||
self.special_decrypt = {
|
||||
'.': '+',
|
||||
"'": '/'
|
||||
}
|
||||
|
||||
self.flip_pattern = None
|
||||
|
||||
if key_file:
|
||||
if os.path.exists(key_file):
|
||||
if key_password is None:
|
||||
key_password = input(f"请输入密钥文件 {key_file} 的密码: ")
|
||||
self._load_keys(key_file, key_password)
|
||||
self.keys_loaded = True
|
||||
else:
|
||||
print(f"⚠️ 密钥文件 {key_file} 不存在")
|
||||
self.keys_loaded = False
|
||||
else:
|
||||
default_key = "encryption.key"
|
||||
if os.path.exists(default_key):
|
||||
self.key_file = default_key
|
||||
if key_password is None:
|
||||
key_password = input(f"请输入密钥文件 {default_key} 的密码: ")
|
||||
self._load_keys(default_key, key_password)
|
||||
self.keys_loaded = True
|
||||
else:
|
||||
print("=" * 60)
|
||||
print("首次启动,请先生成密钥文件")
|
||||
print("=" * 60)
|
||||
self.keys_loaded = False
|
||||
|
||||
def _generate_random_alphabet(self, lowercase=False):
|
||||
chars = list("abcdefghijklmnopqrstuvwxyz" if lowercase else "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
n = len(chars)
|
||||
for i in range(n - 1, 0, -1):
|
||||
j = int.from_bytes(os.urandom(1), 'big') % (i + 1)
|
||||
chars[i], chars[j] = chars[j], chars[i]
|
||||
return ''.join(chars)
|
||||
|
||||
def _generate_random_digit_mapping(self):
|
||||
digits = list("0123456789")
|
||||
mapping_chars = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||
n = len(mapping_chars)
|
||||
for i in range(n - 1, 0, -1):
|
||||
j = int.from_bytes(os.urandom(1), 'big') % (i + 1)
|
||||
mapping_chars[i], mapping_chars[j] = mapping_chars[j], mapping_chars[i]
|
||||
mapping = {}
|
||||
for i, d in enumerate(digits):
|
||||
mapping[d] = mapping_chars[i]
|
||||
return mapping
|
||||
|
||||
def _generate_random_equal_mapping(self):
|
||||
chars = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||
n = len(chars)
|
||||
for i in range(n - 1, 0, -1):
|
||||
j = int.from_bytes(os.urandom(1), 'big') % (i + 1)
|
||||
chars[i], chars[j] = chars[j], chars[i]
|
||||
mapping = {
|
||||
'0': chars[0],
|
||||
'1': chars[1],
|
||||
'2': chars[2],
|
||||
'3': chars[3]
|
||||
}
|
||||
return mapping
|
||||
|
||||
def _generate_random_flip_pattern(self):
|
||||
pattern = []
|
||||
for _ in range(10):
|
||||
bit = int.from_bytes(os.urandom(1), 'big') % 2
|
||||
pattern.append(bit)
|
||||
return pattern
|
||||
|
||||
def _generate_long_key(self, length=4096):
|
||||
chars = "0123456789abcdef"
|
||||
result = []
|
||||
for _ in range(length):
|
||||
idx = int.from_bytes(os.urandom(1), 'big') % 16
|
||||
result.append(chars[idx])
|
||||
return ''.join(result)
|
||||
|
||||
def _generate_short_key(self, length=512):
|
||||
chars = "0123456789abcdef"
|
||||
result = []
|
||||
for _ in range(length):
|
||||
idx = int.from_bytes(os.urandom(1), 'big') % 16
|
||||
result.append(chars[idx])
|
||||
return ''.join(result)
|
||||
|
||||
def _obfuscate_keys(self, keys_data):
|
||||
json_str = json.dumps(keys_data)
|
||||
b64 = base64.b64encode(json_str.encode()).decode()
|
||||
reversed_b64 = b64[::-1]
|
||||
shifted = ''.join([chr((ord(c) + 1) % 128) for c in reversed_b64])
|
||||
final = base64.b64encode(shifted.encode()).decode()
|
||||
return final
|
||||
|
||||
def _deobfuscate_keys(self, obfuscated_data):
|
||||
try:
|
||||
shifted = base64.b64decode(obfuscated_data.encode()).decode()
|
||||
reversed_b64 = ''.join([chr((ord(c) - 1) % 128) for c in shifted])
|
||||
b64 = reversed_b64[::-1]
|
||||
json_str = base64.b64decode(b64.encode()).decode()
|
||||
return json.loads(json_str)
|
||||
except Exception:
|
||||
raise Exception("密钥文件损坏")
|
||||
|
||||
def _xor_encrypt_data(self, data, password):
|
||||
result = []
|
||||
key_len = len(password)
|
||||
for i, char in enumerate(data):
|
||||
xor_result = ord(char) ^ ord(password[i % key_len])
|
||||
result.append(f"{xor_result:02x}")
|
||||
return ''.join(result)
|
||||
|
||||
def _xor_decrypt_data(self, hex_data, password):
|
||||
try:
|
||||
result = []
|
||||
key_len = len(password)
|
||||
for i in range(0, len(hex_data), 2):
|
||||
if i + 1 < len(hex_data):
|
||||
hex_byte = hex_data[i:i+2]
|
||||
xor_result = int(hex_byte, 16) ^ ord(password[(i//2) % key_len])
|
||||
result.append(chr(xor_result))
|
||||
return ''.join(result)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def generate_keys(self, save_path=None, key_password=None):
|
||||
if key_password is None:
|
||||
key_password = input("请设置密钥文件密码: ")
|
||||
confirm = input("请再次输入密码确认: ")
|
||||
if key_password != confirm:
|
||||
print("❌ 密码不匹配")
|
||||
return None
|
||||
|
||||
print("=" * 60)
|
||||
print("正在生成随机密钥...")
|
||||
print("=" * 60)
|
||||
|
||||
self.upper_mapping = self._generate_random_alphabet(lowercase=False)
|
||||
self.lower_mapping = self._generate_random_alphabet(lowercase=True)
|
||||
self.digit_mapping = self._generate_random_digit_mapping()
|
||||
self.equal_mapping = self._generate_random_equal_mapping()
|
||||
self.flip_pattern = self._generate_random_flip_pattern()
|
||||
self.long_key = self._generate_long_key(4096)
|
||||
self.short_key = self._generate_short_key(512)
|
||||
|
||||
self.digit_reverse = {v: k for k, v in self.digit_mapping.items()}
|
||||
self.equal_reverse = {v: k for k, v in self.equal_mapping.items()}
|
||||
|
||||
keys_data = {
|
||||
'upper_mapping': self.upper_mapping,
|
||||
'lower_mapping': self.lower_mapping,
|
||||
'digit_mapping': self.digit_mapping,
|
||||
'equal_mapping': self.equal_mapping,
|
||||
'flip_pattern': self.flip_pattern,
|
||||
'long_key': self.long_key,
|
||||
'short_key': self.short_key,
|
||||
'generated_at': datetime.now().isoformat()
|
||||
}
|
||||
|
||||
obfuscated = self._obfuscate_keys(keys_data)
|
||||
encrypted = self._xor_encrypt_data(obfuscated, key_password)
|
||||
|
||||
if save_path is None:
|
||||
save_path = "encryption.key"
|
||||
|
||||
with open(save_path, 'w') as f:
|
||||
f.write(encrypted)
|
||||
|
||||
self.key_file = save_path
|
||||
self.key_password = key_password
|
||||
self.keys_loaded = True
|
||||
self._build_maps()
|
||||
|
||||
print(f"✅ 密钥已生成并保存到: {save_path}")
|
||||
print("=" * 60)
|
||||
|
||||
return save_path
|
||||
|
||||
def _build_maps(self):
|
||||
self.upper_original = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
self.lower_original = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
self.encrypt_map = {}
|
||||
self.decrypt_map = {}
|
||||
for i in range(26):
|
||||
self.encrypt_map[self.upper_original[i]] = self.upper_mapping[i]
|
||||
self.encrypt_map[self.lower_original[i]] = self.lower_mapping[i]
|
||||
self.decrypt_map[self.upper_mapping[i]] = self.upper_original[i]
|
||||
self.decrypt_map[self.lower_mapping[i]] = self.lower_original[i]
|
||||
|
||||
def _load_keys(self, key_file, key_password):
|
||||
try:
|
||||
with open(key_file, 'r') as f:
|
||||
encrypted_data = f.read()
|
||||
|
||||
decrypted = self._xor_decrypt_data(encrypted_data, key_password)
|
||||
if decrypted is None:
|
||||
print("❌ 密码错误")
|
||||
self.keys_loaded = False
|
||||
return
|
||||
|
||||
keys_data = self._deobfuscate_keys(decrypted)
|
||||
|
||||
self.upper_mapping = keys_data['upper_mapping']
|
||||
self.lower_mapping = keys_data['lower_mapping']
|
||||
self.digit_mapping = keys_data['digit_mapping']
|
||||
self.equal_mapping = keys_data['equal_mapping']
|
||||
self.flip_pattern = keys_data['flip_pattern']
|
||||
self.long_key = keys_data['long_key']
|
||||
self.short_key = keys_data['short_key']
|
||||
|
||||
self.digit_reverse = {v: k for k, v in self.digit_mapping.items()}
|
||||
self.equal_reverse = {v: k for k, v in self.equal_mapping.items()}
|
||||
|
||||
self.key_password = key_password
|
||||
self._build_maps()
|
||||
|
||||
self.keys_loaded = True
|
||||
print(f"✅ 密钥已从 {key_file} 加载")
|
||||
|
||||
except Exception:
|
||||
print("❌ 加载失败")
|
||||
self.keys_loaded = False
|
||||
|
||||
def _ensure_printable(self, text):
|
||||
result = []
|
||||
for c in text:
|
||||
val = ord(c)
|
||||
if val == 124:
|
||||
result.append('|')
|
||||
elif val < 32 or val > 126:
|
||||
val = val % 95 + 32
|
||||
result.append(chr(val))
|
||||
else:
|
||||
result.append(c)
|
||||
return ''.join(result)
|
||||
|
||||
def _mix_keys(self, user_password, target_length):
|
||||
if not self.keys_loaded:
|
||||
raise Exception("密钥未加载")
|
||||
|
||||
mixed = []
|
||||
max_len = max(len(user_password), len(self.short_key))
|
||||
for i in range(max_len):
|
||||
if i < len(user_password):
|
||||
mixed.append(ord(user_password[i]))
|
||||
if i < len(self.short_key):
|
||||
mixed.append(ord(self.short_key[i]))
|
||||
|
||||
for i in range(len(mixed)):
|
||||
if i % 3 == 0:
|
||||
mixed[i] = (mixed[i] << 1) & 0xFF
|
||||
elif i % 3 == 1:
|
||||
mixed[i] = (mixed[i] >> 1) & 0xFF
|
||||
else:
|
||||
mixed[i] = mixed[i] ^ 0x5A
|
||||
|
||||
for i in range(0, len(mixed) - 3, 4):
|
||||
mixed[i], mixed[i+3] = mixed[i+3], mixed[i]
|
||||
mixed[i+1], mixed[i+2] = mixed[i+2], mixed[i+1]
|
||||
|
||||
mixed.reverse()
|
||||
|
||||
result = []
|
||||
for x in mixed:
|
||||
if x < 32 or x > 126:
|
||||
x = x % 95 + 32
|
||||
result.append(chr(x))
|
||||
|
||||
result_str = ''.join(result)
|
||||
|
||||
if len(result_str) < target_length:
|
||||
base_key = result_str
|
||||
final_key = base_key
|
||||
iteration = 0
|
||||
while len(final_key) < target_length:
|
||||
if iteration % 3 == 0:
|
||||
next_chunk = base_key[::-1]
|
||||
elif iteration % 3 == 1:
|
||||
next_chunk = base_key[::-1]
|
||||
next_chunk = ''.join([chr((ord(c) + iteration) % 95 + 32) for c in next_chunk])
|
||||
else:
|
||||
next_chunk = base_key[::-1]
|
||||
next_chunk = ''.join([chr((ord(c) ^ iteration) % 95 + 32) for c in next_chunk])
|
||||
final_key += next_chunk
|
||||
iteration += 1
|
||||
result_str = final_key[:target_length]
|
||||
|
||||
return self._ensure_printable(result_str)
|
||||
|
||||
def _derive_final_key(self, user_password, text_length):
|
||||
mixed_key = self._mix_keys(user_password, text_length * 2)
|
||||
|
||||
hex_key = ''.join([f"{ord(c):02x}" for c in mixed_key])
|
||||
reversed_hex = hex_key[::-1]
|
||||
|
||||
final_key = []
|
||||
for i in range(0, len(reversed_hex), 2):
|
||||
if i + 1 < len(reversed_hex):
|
||||
hex_byte = reversed_hex[i:i+2]
|
||||
try:
|
||||
val = int(hex_byte, 16)
|
||||
if val < 32 or val > 126:
|
||||
val = val % 95 + 32
|
||||
final_key.append(chr(val))
|
||||
except ValueError:
|
||||
final_key.append('x')
|
||||
|
||||
final_key_str = ''.join(final_key)
|
||||
|
||||
if len(final_key_str) < text_length:
|
||||
base_key = final_key_str
|
||||
iteration = 0
|
||||
while len(final_key_str) < text_length:
|
||||
if iteration % 3 == 0:
|
||||
next_chunk = base_key[::-1]
|
||||
elif iteration % 3 == 1:
|
||||
next_chunk = base_key[::-1]
|
||||
next_chunk = ''.join([chr((ord(c) + iteration) % 95 + 32) for c in next_chunk])
|
||||
else:
|
||||
next_chunk = base_key[::-1]
|
||||
next_chunk = ''.join([chr((ord(c) ^ iteration) % 95 + 32) for c in next_chunk])
|
||||
final_key_str += next_chunk
|
||||
iteration += 1
|
||||
|
||||
final_key_str = final_key_str[:text_length]
|
||||
final_key_str = self._ensure_printable(final_key_str)
|
||||
|
||||
return final_key_str
|
||||
|
||||
def _apply_flip(self, text):
|
||||
if self.flip_pattern is None:
|
||||
return text
|
||||
|
||||
result = []
|
||||
for i, ch in enumerate(text):
|
||||
idx = i % len(self.flip_pattern)
|
||||
if ch.isalpha() and self.flip_pattern[idx] == 1:
|
||||
result.append(ch.swapcase())
|
||||
else:
|
||||
result.append(ch)
|
||||
return ''.join(result)
|
||||
|
||||
def _xor_encrypt_with_final_key(self, text, user_password):
|
||||
final_key = self._derive_final_key(user_password, len(text))
|
||||
key_len = len(final_key)
|
||||
result = []
|
||||
for i, char in enumerate(text):
|
||||
xor_result = ord(char) ^ ord(final_key[i % key_len])
|
||||
result.append(f"{xor_result:02x}")
|
||||
return ''.join(result)
|
||||
|
||||
def _xor_decrypt_with_final_key(self, hex_text, user_password):
|
||||
try:
|
||||
text_length = len(hex_text) // 2
|
||||
final_key = self._derive_final_key(user_password, text_length)
|
||||
key_len = len(final_key)
|
||||
result = []
|
||||
for i in range(0, len(hex_text), 2):
|
||||
if i + 1 < len(hex_text):
|
||||
hex_byte = hex_text[i:i+2]
|
||||
try:
|
||||
xor_result = int(hex_byte, 16) ^ ord(final_key[(i//2) % key_len])
|
||||
if xor_result < 32 or xor_result > 126:
|
||||
xor_result = xor_result % 95 + 32
|
||||
result.append(chr(xor_result))
|
||||
except ValueError:
|
||||
result.append('?')
|
||||
return ''.join(result)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _substitute_letters(self, text, mapping):
|
||||
result = []
|
||||
for char in text:
|
||||
if char in mapping:
|
||||
result.append(mapping[char])
|
||||
else:
|
||||
result.append(char)
|
||||
return ''.join(result)
|
||||
|
||||
def _encode_digit(self, num_str):
|
||||
result = []
|
||||
for char in num_str:
|
||||
if char in self.digit_mapping:
|
||||
result.append(self.digit_mapping[char])
|
||||
else:
|
||||
result.append(char)
|
||||
return ''.join(result)
|
||||
|
||||
def _decode_digit(self, encoded_str):
|
||||
result = []
|
||||
for char in encoded_str:
|
||||
if char in self.digit_reverse:
|
||||
result.append(self.digit_reverse[char])
|
||||
else:
|
||||
result.append(char)
|
||||
return ''.join(result)
|
||||
|
||||
def _get_dynamic_key(self, text_length):
|
||||
key = self.long_key
|
||||
while len(key) < text_length:
|
||||
key += self.long_key
|
||||
return key[:text_length]
|
||||
|
||||
def _xor_encrypt_with_key(self, text, key):
|
||||
key_len = len(key)
|
||||
result = []
|
||||
for i, char in enumerate(text):
|
||||
xor_result = ord(char) ^ ord(key[i % key_len])
|
||||
result.append(f"{xor_result:02x}")
|
||||
return ''.join(result)
|
||||
|
||||
def _xor_decrypt_with_key(self, hex_text, key):
|
||||
try:
|
||||
key_len = len(key)
|
||||
result = []
|
||||
for i in range(0, len(hex_text), 2):
|
||||
if i + 1 < len(hex_text):
|
||||
hex_byte = hex_text[i:i+2]
|
||||
try:
|
||||
xor_result = int(hex_byte, 16) ^ ord(key[(i//2) % key_len])
|
||||
if xor_result < 32 or xor_result > 126:
|
||||
xor_result = xor_result % 95 + 32
|
||||
result.append(chr(xor_result))
|
||||
except ValueError:
|
||||
result.append('?')
|
||||
return ''.join(result)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def encrypt(self, plaintext, user_password):
|
||||
if not self.keys_loaded:
|
||||
return "❌ 错误:密钥未加载"
|
||||
|
||||
b64 = base64.b64encode(plaintext.encode('utf-8')).decode('utf-8')
|
||||
equal_count = b64.count('=')
|
||||
|
||||
processed = b64
|
||||
for old, new in self.special_encrypt.items():
|
||||
processed = processed.replace(old, new)
|
||||
processed = processed.rstrip('=')
|
||||
|
||||
sub = self._substitute_letters(processed, self.encrypt_map)
|
||||
flipped = self._apply_flip(sub)
|
||||
reversed_text = flipped[::-1]
|
||||
|
||||
equal_char = self.equal_mapping[str(equal_count)]
|
||||
with_equal = f"{reversed_text}|{equal_char}"
|
||||
|
||||
key_length_str = str(len(with_equal))
|
||||
key_length_encoded = self._encode_digit(key_length_str)
|
||||
|
||||
dynamic_key = self._get_dynamic_key(len(with_equal))
|
||||
encrypted_by_dynamic = self._xor_encrypt_with_key(with_equal, dynamic_key)
|
||||
|
||||
combined = f"{encrypted_by_dynamic}|{key_length_encoded}"
|
||||
final_encrypted = self._xor_encrypt_with_final_key(combined, user_password)
|
||||
|
||||
return final_encrypted
|
||||
|
||||
def decrypt(self, ciphertext, user_password):
|
||||
if not self.keys_loaded:
|
||||
return "❌ 解密失败"
|
||||
|
||||
try:
|
||||
combined = self._xor_decrypt_with_final_key(ciphertext, user_password)
|
||||
if combined is None:
|
||||
return "❌ 解密失败"
|
||||
|
||||
if '|' in combined:
|
||||
parts = combined.split('|')
|
||||
if len(parts) >= 2:
|
||||
hex_data = parts[0]
|
||||
key_length_encoded = parts[1]
|
||||
else:
|
||||
hex_data = parts[0]
|
||||
key_length_encoded = 'g'
|
||||
else:
|
||||
hex_data = combined
|
||||
key_length_encoded = 'g'
|
||||
|
||||
key_length_str = self._decode_digit(key_length_encoded)
|
||||
try:
|
||||
key_length = int(key_length_str)
|
||||
except ValueError:
|
||||
key_length = 16
|
||||
|
||||
dynamic_key = self._get_dynamic_key(key_length)
|
||||
xor_decrypted = self._xor_decrypt_with_key(hex_data, dynamic_key)
|
||||
if xor_decrypted is None:
|
||||
return "❌ 解密失败"
|
||||
|
||||
if '|' in xor_decrypted:
|
||||
main_part, equal_char = xor_decrypted.split('|')
|
||||
equal_count = int(self.equal_reverse.get(equal_char, '0'))
|
||||
else:
|
||||
main_part = xor_decrypted
|
||||
equal_count = 0
|
||||
|
||||
reversed_text = main_part[::-1]
|
||||
flipped = self._apply_flip(reversed_text)
|
||||
sub = self._substitute_letters(flipped, self.decrypt_map)
|
||||
|
||||
for old, new in self.special_decrypt.items():
|
||||
sub = sub.replace(old, new)
|
||||
|
||||
b64_with_equal = sub + '=' * equal_count
|
||||
|
||||
if len(b64_with_equal) % 4 != 0:
|
||||
return "❌ 解密失败"
|
||||
|
||||
decoded = base64.b64decode(b64_with_equal.encode('utf-8')).decode('utf-8')
|
||||
return decoded
|
||||
|
||||
except Exception:
|
||||
return "❌ 解密失败"
|
||||
|
||||
def print_keys(self):
|
||||
if not self.keys_loaded:
|
||||
print("❌ 未加载密钥")
|
||||
return
|
||||
|
||||
print("=" * 60)
|
||||
print("密钥信息")
|
||||
print("=" * 60)
|
||||
print(f"密钥文件: {self.key_file}")
|
||||
print(f"大写映射表: {self.upper_mapping}")
|
||||
print(f"小写映射表: {self.lower_mapping}")
|
||||
print(f"翻转模式: {self.flip_pattern}")
|
||||
print(f"长密钥长度: {len(self.long_key)} 位")
|
||||
print(f"短密钥长度: {len(self.short_key)} 位")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
def main():
|
||||
print("=" * 60)
|
||||
print("欢迎使用加密系统")
|
||||
print("=" * 60)
|
||||
|
||||
crypto = None
|
||||
key_password = None
|
||||
|
||||
if os.path.exists("encryption.key"):
|
||||
key_password = input("请输入默认密钥文件 (encryption.key) 的密码: ")
|
||||
crypto = EncryptionSystem("encryption.key", key_password)
|
||||
if not crypto.keys_loaded:
|
||||
print("❌ 加载失败")
|
||||
crypto = None
|
||||
else:
|
||||
print("\n未找到默认密钥文件,请先生成")
|
||||
choice = input("是否生成默认密钥文件?(y/n): ").strip().lower()
|
||||
if choice == 'y':
|
||||
crypto = EncryptionSystem()
|
||||
key_password = crypto.generate_keys("encryption.key")
|
||||
if key_password is None:
|
||||
print("❌ 生成失败")
|
||||
crypto = None
|
||||
else:
|
||||
print("⚠️ 请使用模式4或5指定密钥文件,或模式6生成新密钥")
|
||||
|
||||
while True:
|
||||
print("\n请选择操作:")
|
||||
print("1. 使用默认密钥加密")
|
||||
print("2. 使用默认密钥解密")
|
||||
print("3. 生成新密钥(覆盖默认)")
|
||||
print("4. 使用指定密钥文件加密")
|
||||
print("5. 使用指定密钥文件解密")
|
||||
print("6. 生成密钥并保存到当前文件夹")
|
||||
print("7. 查看当前密钥信息")
|
||||
print("8. 退出")
|
||||
|
||||
choice = input("\n请选择操作 (1-8): ").strip()
|
||||
|
||||
if choice == '1':
|
||||
if crypto is None or not crypto.keys_loaded:
|
||||
if os.path.exists("encryption.key"):
|
||||
if key_password is None:
|
||||
key_password = input("请输入默认密钥文件密码: ")
|
||||
crypto = EncryptionSystem("encryption.key", key_password)
|
||||
if not crypto.keys_loaded:
|
||||
print("❌ 加载失败")
|
||||
continue
|
||||
else:
|
||||
print("❌ 密钥文件不存在")
|
||||
continue
|
||||
|
||||
password = input("请输入加密密码: ")
|
||||
text = input("请输入要加密的文本: ")
|
||||
if text and password:
|
||||
encrypted = crypto.encrypt(text, password)
|
||||
print(f"\n✅ 加密结果: {encrypted}")
|
||||
|
||||
elif choice == '2':
|
||||
if crypto is None or not crypto.keys_loaded:
|
||||
if os.path.exists("encryption.key"):
|
||||
if key_password is None:
|
||||
key_password = input("请输入默认密钥文件密码: ")
|
||||
crypto = EncryptionSystem("encryption.key", key_password)
|
||||
if not crypto.keys_loaded:
|
||||
print("❌ 加载失败")
|
||||
continue
|
||||
else:
|
||||
print("❌ 密钥文件不存在")
|
||||
continue
|
||||
|
||||
password = input("请输入加密密码: ")
|
||||
text = input("请输入要解密的密文: ")
|
||||
if text and password:
|
||||
decrypted = crypto.decrypt(text, password)
|
||||
print(f"\n✅ 解密结果: {decrypted}")
|
||||
|
||||
elif choice == '3':
|
||||
crypto = EncryptionSystem()
|
||||
key_password = crypto.generate_keys("encryption.key")
|
||||
if key_password is None:
|
||||
print("❌ 生成失败")
|
||||
else:
|
||||
print("✅ 默认密钥已更新")
|
||||
|
||||
elif choice == '4':
|
||||
key_file = input("请输入密钥文件路径: ")
|
||||
if not os.path.exists(key_file):
|
||||
print(f"❌ 文件不存在")
|
||||
continue
|
||||
|
||||
kp = input(f"请输入密钥文件密码: ")
|
||||
crypto = EncryptionSystem(key_file, kp)
|
||||
if not crypto.keys_loaded:
|
||||
print("❌ 加载失败")
|
||||
continue
|
||||
|
||||
password = input("请输入加密密码: ")
|
||||
text = input("请输入要加密的文本: ")
|
||||
if text and password:
|
||||
encrypted = crypto.encrypt(text, password)
|
||||
print(f"\n✅ 加密结果: {encrypted}")
|
||||
|
||||
elif choice == '5':
|
||||
key_file = input("请输入密钥文件路径: ")
|
||||
if not os.path.exists(key_file):
|
||||
print(f"❌ 文件不存在")
|
||||
continue
|
||||
|
||||
kp = input(f"请输入密钥文件密码: ")
|
||||
crypto = EncryptionSystem(key_file, kp)
|
||||
if not crypto.keys_loaded:
|
||||
print("❌ 加载失败")
|
||||
continue
|
||||
|
||||
password = input("请输入加密密码: ")
|
||||
text = input("请输入要解密的密文: ")
|
||||
if text and password:
|
||||
decrypted = crypto.decrypt(text, password)
|
||||
print(f"\n✅ 解密结果: {decrypted}")
|
||||
|
||||
elif choice == '6':
|
||||
timestamp = int(time.time())
|
||||
filename = f"key_{timestamp}.key"
|
||||
crypto = EncryptionSystem()
|
||||
kp = crypto.generate_keys(filename)
|
||||
if kp is None:
|
||||
print("❌ 生成失败")
|
||||
else:
|
||||
print(f"✅ 密钥已保存到: {filename}")
|
||||
|
||||
elif choice == '7':
|
||||
if crypto is None or not crypto.keys_loaded:
|
||||
if os.path.exists("encryption.key"):
|
||||
if key_password is None:
|
||||
key_password = input("请输入默认密钥文件密码: ")
|
||||
crypto = EncryptionSystem("encryption.key", key_password)
|
||||
if not crypto.keys_loaded:
|
||||
print("❌ 加载失败")
|
||||
continue
|
||||
else:
|
||||
print("❌ 未加载密钥")
|
||||
continue
|
||||
crypto.print_keys()
|
||||
|
||||
elif choice == '8':
|
||||
print("感谢使用,再见!")
|
||||
break
|
||||
|
||||
else:
|
||||
print("❌ 无效选择")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user