Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bad851f741 | ||
|
|
b311483963 | ||
|
|
ef90efd199 | ||
|
|
587ef2140b |
@@ -1,345 +1,347 @@
|
|||||||
# 🔐 ChaosCrypt - 混沌加密系统(v2.0)
|
|
||||||
|
|
||||||
**一个完全自主设计的、抗量子、抗数学攻击的对称加密系统**
|
# 🔐 ChaosCrypt - Chaos Encryption System (v2.0)
|
||||||
|
|
||||||
*不依赖 NIST、不依赖椭圆曲线、不依赖质数分解——只依赖随机性本身*
|
**A fully self-designed, quantum-resistant, math-attack-resistant symmetric encryption system**
|
||||||
|
|
||||||
**v2.0 新增 💬 ChaosCryptChat:基于混沌加密的端到端加密聊天系统(文本/图片/文件/语音)**
|
*No NIST, no elliptic curves, no prime factorization—only randomness itself*
|
||||||
|
|
||||||
|
**v2.0 New Addition 💬 ChaosCryptChat: End-to-end encrypted chat system (text/images/files/voice) built on ChaosCrypt**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📖 目录
|
## 📖 Table of Contents
|
||||||
|
|
||||||
1. [项目简介](#项目简介)
|
1. [Project Overview](#project-overview)
|
||||||
2. [设计哲学](#设计哲学)
|
2. [Design Philosophy](#design-philosophy)
|
||||||
3. [核心特性](#核心特性)
|
3. [Core Features](#core-features)
|
||||||
4. [加密流程详解](#加密流程详解)
|
4. [Encryption Workflow](#encryption-workflow)
|
||||||
5. [安全性分析](#安全性分析)
|
5. [Security Analysis](#security-analysis)
|
||||||
6. [为什么这玩意儿真的安全?(不服来辩版)](#为什么这玩意儿真的安全不服来辩版)
|
6. [Why This Is Actually Secure (No-BS Edition)](#why-this-is-actually-secure-no-bs-edition)
|
||||||
7. [快速开始](#快速开始)
|
7. [Quick Start](#quick-start)
|
||||||
8. [使用指南](#使用指南)
|
8. [Usage Guide](#usage-guide)
|
||||||
9. [API 参考](#api-参考)
|
9. [API Reference](#api-reference)
|
||||||
10. [常见问题](#常见问题)
|
10. [FAQ](#faq)
|
||||||
11. [💬 ChaosCryptChat 混沌加密聊天](#-chaoscryptchat-混沌加密聊天)
|
11. [💬 ChaosCryptChat](#-chaoscryptchat-chaos-encrypted-chat)
|
||||||
12. [项目结构](#项目结构)
|
12. [Project Structure](#project-structure)
|
||||||
13. [免责声明](#免责声明)
|
13. [Disclaimer](#disclaimer)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 项目简介
|
## Project Overview
|
||||||
|
|
||||||
**ChaosCrypt** 是一个完全自主设计的对称加密系统。它不依赖任何第三方加密库(仅使用 `base64` 做数据编码),全部加密逻辑均为原创。
|
**ChaosCrypt** is a fully self-designed symmetric encryption system. It relies on no third-party crypto libraries (only `base64` for encoding)—all encryption logic is original.
|
||||||
|
|
||||||
**核心思想**:用**随机性**替代**数学结构**,用**多层乱序**替代**代数方程**,用**超大密钥空间**彻底扼杀暴力破解。
|
**Core idea**: Replace **mathematical structure** with **randomness**, replace **algebraic equations** with **multi-layer obfuscation**, and use an **immense key space** to completely shut down brute force.
|
||||||
|
|
||||||
> 这不是对现有加密算法的改进,而是对"安全"这个概念的重新定义。
|
> This is not an improvement on existing algorithms—it's a redefinition of what "secure" means.
|
||||||
|
|
||||||
**v2.0 新增**:在混沌加密内核之上构建了 **ChaosCryptChat** 端到端加密聊天系统,让混沌加密真正走进实时通信场景。
|
**v2.0 New**: Built **ChaosCryptChat**, an end-to-end encrypted chat system on top of the ChaosCrypt kernel, bringing chaos encryption to real-time communication.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 设计哲学
|
## Design Philosophy
|
||||||
|
|
||||||
当今加密世界有一个默认共识:**"只有 NIST 认证的、数学优美的、学术界验证过的算法才算安全"**。
|
There's a consensus in the crypto world: *"Only NIST-certified, mathematically elegant, academically vetted algorithms are secure."*
|
||||||
|
|
||||||
ChaosCrypt 对此表示:
|
ChaosCrypt says:
|
||||||
|
|
||||||
> **"你们说的都对,但我不信。"**
|
> **"You're not wrong, but I don't buy it."**
|
||||||
|
|
||||||
- **Dual_EC_DRBG** 事件还历历在目——NIST 标准,NSA 后门,全世界被蒙在鼓里好几年。
|
- **Dual_EC_DRBG** is still fresh—NIST standard, NSA backdoor, the whole world fooled for years.
|
||||||
- **RSA** 数学优美吧?标准吧?**Shor 一来直接秒死。**
|
- **RSA** is mathematically beautiful, right? Standard, right? **Shor kills it instantly.**
|
||||||
- **AES** 结构清晰吧?S-Box 有理有据吧?**Grover 直接给你开根号加速。**
|
- **AES** has a clean structure, a well-reasoned S-Box, right? **Grover gives you a square-root speedup.**
|
||||||
|
|
||||||
**ChaosCrypt 选择另一条路:**
|
**ChaosCrypt takes another path:**
|
||||||
|
|
||||||
> **不要数学结构,不要可解释性,不要任何人给你背书。**
|
> **No math structure. No explainability. No one's stamp of approval.**
|
||||||
> **你唯一能做的只有暴力枚举——而枚举空间大到宇宙都装不下。**
|
> **Your only move is brute force—and the space is so large the universe can't hold it.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 核心特性
|
## Core Features
|
||||||
|
|
||||||
| 特性 | 说明 |
|
| Feature | Description |
|
||||||
|------|------|
|
|---------|-------------|
|
||||||
| 🔑 **双因素保护** | 系统密钥文件 (`.key`) + 用户密码 |
|
| 🔑 **Two-factor protection** | System key file (`.key`) + user password |
|
||||||
| 🧩 **完全随机密钥** | 替换表、翻转模式、长密钥、短密钥全部随机生成 |
|
| 🧩 **Fully random keys** | Substitution tables, flip patterns, long key, short key all randomly generated |
|
||||||
| 📁 **密钥持久化** | 密钥文件经过混淆存储(Base64 + 反转 + 移位),防止直接读取 |
|
| 📁 **Key persistence** | Keys stored obfuscated (Base64 + reversal + shift) to prevent casual reading |
|
||||||
| 🔁 **可重用 OTP** | 密钥长度 ≥ 明文长度,消除周期规律,实现 OTP 级别的安全性 |
|
| 🔁 **Reusable OTP** | Key length ≥ plaintext length, eliminating periodic patterns—OTP-level security |
|
||||||
| 🛡️ **抗量子攻击** | 无数学结构,Shor/Grover 均无法加速暴力破解 |
|
| 🛡️ **Quantum-resistant** | No math structure, so Shor/Grover can't speed up brute force |
|
||||||
| 🚫 **无第三方依赖** | 不依赖 OpenSSL、Crypto 等任何加密库 |
|
| 🚫 **Zero third-party deps** | No OpenSSL, no Crypto, no nothing |
|
||||||
| 📦 **即开即用** | 交互式菜单,支持多密钥文件切换 |
|
| 📦 **Ready to use** | Interactive menu, multiple key file support |
|
||||||
| 🐍 **纯 Python** | 仅需 Python 3.6+,零额外依赖 |
|
| 🐍 **Pure Python** | Just Python 3.6+, no extra dependencies |
|
||||||
| 💬 **加密聊天(v2.0)** | ChaosCryptChat 端到端加密聊天:文本/图片/文件/语音,P2P + 中央服务器双模式 |
|
| 💬 **Encrypted Chat (v2.0)** | ChaosCryptChat: E2E text/images/files/voice, P2P + central server modes |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 加密流程详解
|
## Encryption Workflow
|
||||||
|
|
||||||
```
|
```
|
||||||
明文
|
Plaintext
|
||||||
↓
|
↓
|
||||||
① Base64 编码
|
① Base64 encode
|
||||||
↓
|
↓
|
||||||
② 随机替换表(大小写各26字母完全打乱)
|
② Random substitution (26 uppercase + 26 lowercase fully shuffled)
|
||||||
↓
|
↓
|
||||||
③ 大小写翻转(10位随机模式)
|
③ Case flip (10‑bit random pattern)
|
||||||
↓
|
↓
|
||||||
④ 字符串反转
|
④ String reversal
|
||||||
↓
|
↓
|
||||||
⑤ 动态异或(4096位长密钥)
|
⑤ Dynamic XOR (4096‑bit long key)
|
||||||
↓
|
↓
|
||||||
⑥ 最终异或(用户密码 + 512位短密钥 派生)
|
⑥ Final XOR (user password + 512‑bit short key derived)
|
||||||
↓
|
↓
|
||||||
密文(十六进制)
|
Ciphertext (hex)
|
||||||
```
|
```
|
||||||
|
|
||||||
每一步使用的随机参数都来自 `.key` 文件,用户密码仅参与最后一步的密钥派生。
|
Every random parameter comes from the `.key` file. The user password is only used in the final key derivation step.
|
||||||
|
|
||||||
### 密钥派生流程
|
### Key Derivation Flow
|
||||||
|
|
||||||
```
|
```
|
||||||
用户密码 + short_key (512位)
|
User password + short_key (512 bits)
|
||||||
↓
|
↓
|
||||||
交替穿插 → 位运算混合 → 分组置换 → 反转
|
Interleave → bitwise mixing → block permutation → reversal
|
||||||
↓
|
↓
|
||||||
扩展至目标长度(三种变换模式循环)
|
Expand to target length (three transformation modes cycled)
|
||||||
↓
|
↓
|
||||||
最终密钥(长度 >= 明文)
|
Final key (length ≥ plaintext)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 安全性分析
|
## Security Analysis
|
||||||
|
|
||||||
### 1. 无法建立数学方程
|
### 1. No Mathematical Equations to Write
|
||||||
|
|
||||||
| 传统算法 | 方程形式 | 攻击方式 |
|
| Traditional Alg | Equation Form | Attack Vector |
|
||||||
|----------|----------|----------|
|
|-----------------|---------------|---------------|
|
||||||
| RSA | c = m^e mod n | 数域筛法、Shor |
|
| RSA | c = m^e mod n | Number field sieve, Shor |
|
||||||
| AES | State = SBox ∘ ShiftRow ∘ MixCol ∘ AddRoundKey | 差分分析、Grover |
|
| AES | State = SBox ∘ ShiftRow ∘ MixCol ∘ AddRoundKey | Differential, Grover |
|
||||||
| ECC | Q = kP | 离散对数、Shor |
|
| ECC | Q = kP | Discrete log, Shor |
|
||||||
| **ChaosCrypt** | **无法写出任何有意义的方程** | **只能暴力枚举** |
|
| **ChaosCrypt** | **No meaningful equation can be written** | **Brute force only** |
|
||||||
|
|
||||||
> 原因:替换表是查表操作,翻转模式是硬编码数组,密钥派生是黑盒混合——每一步都是"随机查表",没有可解析的代数结构。
|
> Why: substitution is table lookup, flip pattern is a hardcoded array, key derivation is a black-box mix—every step is "random table lookup" with no parseable algebraic structure.
|
||||||
|
|
||||||
### 2. 密钥空间(暴力破解难度)
|
### 2. Key Space (Brute‑Force Difficulty)
|
||||||
|
|
||||||
| 组件 | 空间大小 | 数值 |
|
| Component | Space Size | Approx. Value |
|
||||||
|------|----------|------|
|
|-----------|------------|---------------|
|
||||||
| `upper_mapping` | 26! | ~10²⁶ |
|
| `upper_mapping` | 26! | ~10²⁶ |
|
||||||
| `lower_mapping` | 26! | ~10²⁶ |
|
| `lower_mapping` | 26! | ~10²⁶ |
|
||||||
| `digit_mapping` | ~10! × C(62,10) | ~10¹⁴ |
|
| `digit_mapping` | ~10! × C(62,10) | ~10¹⁴ |
|
||||||
| `equal_mapping` | 62×61×60×59 | ~10⁷ |
|
| `equal_mapping` | 62×61×60×59 | ~10⁷ |
|
||||||
| `long_key` (4096位hex) | 16⁴⁰⁹⁶ | ~10⁴⁹³² |
|
| `long_key` (4096‑bit hex) | 16⁴⁰⁹⁶ | ~10⁴⁹³² |
|
||||||
| `short_key` (512位hex) | 16⁵¹² | ~10⁶¹⁶ |
|
| `short_key` (512‑bit hex) | 16⁵¹² | ~10⁶¹⁶ |
|
||||||
| `flip_pattern` | 2¹⁰ | ~10³ |
|
| `flip_pattern` | 2¹⁰ | ~10³ |
|
||||||
| 用户密码(最低8位) | ~10⁸ | |
|
| User password (min 8 chars) | ~10⁸ | |
|
||||||
|
|
||||||
**总搜索空间 ≈ 10⁵⁶³²**
|
**Total search space ≈ 10⁵⁶³²**
|
||||||
|
|
||||||
**对比数据**:
|
**Comparisons**:
|
||||||
|
|
||||||
- 宇宙原子总数:≈ 10⁸⁰
|
- Atoms in the observable universe: ≈ 10⁸⁰
|
||||||
- AES-256 密钥空间:≈ 10⁷⁷
|
- AES‑256 key space: ≈ 10⁷⁷
|
||||||
- RSA-2048 密钥空间:≈ 10⁶¹⁶
|
- RSA‑2048 key space: ≈ 10⁶¹⁶
|
||||||
- **ChaosCrypt:≈ 10⁵⁶³²**(是 AES 的 10⁵⁵⁵⁵ 倍)
|
- **ChaosCrypt: ≈ 10⁵⁶³²** (10⁵⁵⁵⁵ × AES)
|
||||||
|
|
||||||
> **即使全宇宙原子都变成量子计算机,也无法在宇宙生命周期内枚举完。**
|
> **Even if every atom in the universe were a quantum computer, they couldn't exhaust this space before the heat death of the cosmos.**
|
||||||
|
|
||||||
### 3. 量子安全性
|
### 3. Quantum Resistance
|
||||||
|
|
||||||
| 量子算法 | 目标 | 对 ChaosCrypt 的效果 |
|
| Quantum Alg | Target | Effect on ChaosCrypt |
|
||||||
|----------|------|------------------------|
|
|-------------|--------|----------------------|
|
||||||
| **Shor** | 分解质数、离散对数 | ❌ **无效** – 没有数论结构 |
|
| **Shor** | Integer factorization, discrete log | ❌ **Ineffective** – no number‑theoretic structure |
|
||||||
| **Grover** | 对称加密加速 | ❌ **无效** – 空间 10⁵⁶³²,开根号后 10²⁸¹⁶,依然远大于 10⁸⁰ |
|
| **Grover** | Symmetric encryption speedup | ❌ **Ineffective** – space 10⁵⁶³², sqrt gives 10²⁸¹⁶, still >> 10⁸⁰ |
|
||||||
|
|
||||||
**结论:ChaosCrypt 对抗已知量子攻击完全免疫。**
|
**Conclusion: ChaosCrypt is fully immune to known quantum attacks.**
|
||||||
|
|
||||||
### 4. 经典攻击方式评估
|
### 4. Classical Attack Vectors
|
||||||
|
|
||||||
| 攻击方式 | 是否可行 | 原因 |
|
| Attack | Feasible? | Reason |
|
||||||
|----------|----------|------|
|
|--------|-----------|--------|
|
||||||
| 频率分析 | ❌ | 随机替换表破坏频率分布 |
|
| Frequency analysis | ❌ | Random substitution destroys frequency patterns |
|
||||||
| 周期分析 | ❌ | 密钥长度 ≥ 明文,无循环 |
|
| Periodicity analysis | ❌ | Key length ≥ plaintext, no cycles |
|
||||||
| 已知明文攻击 | ❌ | 非线性操作 → 超定方程组无解 |
|
| Known‑plaintext attack | ❌ | Nonlinear ops → overdetermined system with no solution |
|
||||||
| 选择明文攻击 | ❌ | 即使可控输入也无法反推黑盒映射 |
|
| Chosen‑plaintext attack | ❌ | Even controllable input can't invert the black‑box mapping |
|
||||||
| 差分/线性攻击 | ❌ | 无代数结构,无法建立差分链 |
|
| Differential/linear | ❌ | No algebraic structure to build differential chains |
|
||||||
| 暴力枚举 | ❌ | 空间 10⁵⁶³²,物理上不可能 |
|
| Brute force | ❌ | Space 10⁵⁶³², physically impossible |
|
||||||
|
|
||||||
**唯一现实威胁**:盗取 `.key` 文件 + 窃取用户密码(端侧攻击,与算法无关)。
|
**The only real threat**: Theft of `.key` file + password (client‑side compromise, unrelated to the algorithm).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 为什么这玩意儿真的安全?(不服来辩版)
|
## Why This Is Actually Secure (No‑BS Edition)
|
||||||
|
|
||||||
**总之就是安全——真·安全。** 🤷♂️
|
**Bottom line: It's secure — genuinely secure.** 🤷♂️
|
||||||
|
|
||||||
我寻思着,总不能所有加密算法都得围着椭圆曲线和质数分解转,然后等 NIST 给你盖个戳才算"安全"吧?那算什么东西?**垄断啊?** 🤣
|
Look, not every encryption algorithm has to revolve around elliptic curves and prime factorization, waiting for NIST to stamp it "secure." That's not security—that's **a monopoly.** 🤣
|
||||||
|
|
||||||
再说了,美国政府什么心思你猜不透。**Dual_EC_DRBG 的事儿这么快就忘了?** NIST 认证的、标准化的、全世界用了好几年的算法——结果里面养着 NSA 的后门。标准管个屁用。
|
And let's not forget **Dual_EC_DRBG** — NIST‑certified, standardized, used worldwide for years… and it had an NSA backdoor baked in. So much for standards.
|
||||||
|
|
||||||
所以别跟我扯什么"学术界验证"、"第三方审计"、"算法标准认证"。我就问一句:
|
So don't give me "academic verification," "third‑party audit," or "standard certification." I'll ask you one question:
|
||||||
|
|
||||||
**只有这些"标准"算法才能叫安全?**
|
**Are only those "standard" algorithms allowed to be secure?**
|
||||||
|
|
||||||
- **安全 ≠ 数学复杂**
|
- **Secure ≠ mathematically complex**
|
||||||
- **安全 ≠ NIST 认证**
|
- **Secure ≠ NIST‑approved**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
来,咱们看看所谓的"标准算法"都什么下场:
|
Let's see how those "standard" algorithms fare:
|
||||||
|
|
||||||
| 算法 | 密钥空间 | 量子下场 |
|
| Algorithm | Key Space | Quantum Fate |
|
||||||
|------|----------|----------|
|
|-----------|-----------|--------------|
|
||||||
| AES-256 | 10⁷⁷ | Grover 减半到 10³⁸ → 理论上可破 |
|
| AES‑256 | 10⁷⁷ | Grover halves it to 10³⁸ → theoretically breakable |
|
||||||
| RSA-2048 | 10⁶¹⁶ | Shor 一来直接秒死 🔥 |
|
| RSA‑2048 | 10⁶¹⁶ | Shor kills it instantly 🔥 |
|
||||||
| ECC | 10⁶¹⁶ | 同上,Shor 直接扼杀 |
|
| ECC | 10⁶¹⁶ | Same, Shor shuts it down |
|
||||||
|
|
||||||
再看看我这个:
|
Now look at this:
|
||||||
|
|
||||||
| 算法 | 密钥空间 | 量子下场 |
|
| Algorithm | Key Space | Quantum Fate |
|
||||||
|------|----------|----------|
|
|-----------|-----------|--------------|
|
||||||
| **ChaosCrypt** | **10⁵⁶³²** | **Shor 无从下手,Grover 打了等于没打** ✅ |
|
| **ChaosCrypt** | **10⁵⁶³²** | **Shor has nothing to attack, Grover barely scratches it** ✅ |
|
||||||
|
|
||||||
**10⁵⁶³² 什么概念?**
|
**10⁵⁶³² — what does that mean?**
|
||||||
|
|
||||||
全宇宙原子总数才 10⁸⁰。就算把全宇宙每个原子都变成一台量子计算机,从宇宙大爆炸算到今天,**也算不完这个空间的一个零头。**
|
The universe has ~10⁸⁰ atoms. Even if every atom were a quantum computer running from the Big Bang to now, they wouldn't finish a fraction of this space.
|
||||||
|
|
||||||
AES 的 10⁷⁷ 在它面前就像一粒沙子对比整个银河系。
|
AES's 10⁷⁷ is a grain of sand compared to the Milky Way.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**RSA 美丽吧?标准吧?数学优美吧?**
|
**RSA is beautiful, right? Standard? Mathematically elegant?**
|
||||||
|
|
||||||
但恰恰因为**太数学了**,所以 Shor 一发入魂,直接物理超度。
|
But precisely because it's **too mathematical**, Shor one‑shots it.
|
||||||
|
|
||||||
**数学上越好看,结构越清晰,攻击者就越开心**——因为你有方程,他就能解;你有规律,他就能抓;你有结构,他就能拆。
|
**The prettier the math, the clearer the structure, the happier the attacker** — because you have equations they can solve, patterns they can exploit, structure they can dismantle.
|
||||||
|
|
||||||
我的算法呢?
|
My algorithm?
|
||||||
|
|
||||||
- 替换表?随机打的,没有规律。
|
- Substitution? Randomly shuffled — no pattern.
|
||||||
- 翻转模式?硬编码数组,没有方程。
|
- Flip pattern? Hardcoded array — no equation.
|
||||||
- 密钥派生?黑盒操作,解不出来。
|
- Key derivation? Black‑box mix — unsolvable.
|
||||||
|
|
||||||
**攻击者想写个方程都写不出来,想用代数工具都找不到切入点。**
|
**An attacker can't even write an equation. There's no algebraic handle to grab.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**所以这算法有什么问题?**
|
**So what's wrong with this algorithm?**
|
||||||
|
|
||||||
- ❌ 没有"第三方安全审计"
|
- ❌ No "third‑party security audit"
|
||||||
- ❌ 没有"算法标准认证"
|
- ❌ No "algorithm standard certification"
|
||||||
- ❌ 没有"学术界验证"
|
- ❌ No "academic validation"
|
||||||
- ❌ 并且"看起来肥肠初级"
|
- ❌ And it "looks pretty amateur"
|
||||||
|
|
||||||
**除此之外,没有任何问题。** 🤷♂️
|
**Other than that, absolutely nothing.** 🤷♂️
|
||||||
|
|
||||||
看起来初级就初级,**你能攻破么?不能!**
|
Looks amateur? Fine. **Can you break it? No.**
|
||||||
|
|
||||||
安全这两个字,只关心**实战**,不关心**评价**和**认证**。
|
Security is about **real‑world results**, not **reviews** or **certifications**.
|
||||||
|
|
||||||
- Dual_EC_DRBG 有认证有标准有审计——结果呢?后门。
|
- Dual_EC_DRBG had certs, standards, audits — and a backdoor.
|
||||||
- 我这个啥都没有——结果呢?**你破不了。**
|
- This has none of that — and **you can't break it.**
|
||||||
|
|
||||||
**能被黑客破解的就是垃圾,破解不了的就是真神。**
|
**If hackers can crack it, it's garbage. If they can't, it's the real deal.**
|
||||||
|
|
||||||
这玩意儿你实说,**你找不出来毛病!** 😏🔥
|
Seriously — **find a flaw. I dare you.** 😏🔥
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 💬 ChaosCryptChat 混沌加密聊天(v2.0 新增)
|
## 💬 ChaosCryptChat (v2.0 New)
|
||||||
|
|
||||||
**ChaosCryptChat** 是基于 ChaosCrypt 混沌加密内核构建的端到端加密聊天系统。所有聊天内容(文本、图片、文件、语音)在发送前均经混沌加密,服务器与中间节点无法读取任何消息。
|
**ChaosCryptChat** is an end‑to‑end encrypted chat system built on the ChaosCrypt kernel. All content (text, images, files, voice) is chaos‑encrypted before sending—servers and middlemen cannot read any messages.
|
||||||
|
|
||||||
### 核心特性
|
### Core Features
|
||||||
|
|
||||||
| 特性 | 说明 |
|
| Feature | Description |
|
||||||
|------|------|
|
|---------|-------------|
|
||||||
| 🔗 **端到端加密** | 所有消息客户端本地加密,服务器只做中继,不持有群密钥 |
|
| 🔗 **End‑to‑end encryption** | All messages encrypted client‑side; server only relays, holds no group keys |
|
||||||
| ☁️ **双群模式** | 🔗 端到端 P2P 直连 + ☁️ 中央服务器(解决 NAT 穿透) |
|
| ☁️ **Two group modes** | 🔗 P2P direct + ☁️ Central server (NAT traversal) |
|
||||||
| 🎤 **语音消息** | 录音 → 混沌加密 → 发送 → 解密播放 |
|
| 🎤 **Voice messages** | Record → chaos encrypt → send → decrypt & play |
|
||||||
| 🖼️ **图片/文件** | 二进制数据混沌加密传输,支持任意文件类型 |
|
| 🖼️ **Images / Files** | Binary data encrypted with ChaosCrypt, supports any file type |
|
||||||
| 👥 **群管理** | 创建群、加入群、群名、公告、踢人、群主审批 |
|
| 👥 **Group management** | Create, join, group name, announcements, kick, owner approval |
|
||||||
| 🚫 **消息撤回** | 2 分钟内可撤回自己的消息 |
|
| 🚫 **Message recall** | Recall within 2 minutes of sending |
|
||||||
| 🔑 **每用户密钥** | 每用户独立密钥认证,防止冒充他人 |
|
| 🔑 **Per‑user keys** | Each user has an independent authentication key to prevent impersonation |
|
||||||
| 📜 **历史记录** | SQLite 本地存储聊天历史(重启不丢) |
|
| 📜 **History** | SQLite local storage (persists across restarts) |
|
||||||
| 🛡️ **HMAC 校验** | 每条消息带 HMAC 签名,防篡改、防伪造 |
|
| 🛡️ **HMAC verification** | Every message carries an HMAC signature to prevent tampering and forgery |
|
||||||
| 📱 **密钥分享** | 群密钥支持复制 / 二维码 / 文件三种方式分享 |
|
| 📱 **Key sharing** | Group key can be shared via copy / QR code / file |
|
||||||
|
|
||||||
### 两种群模式
|
### Two Group Modes
|
||||||
|
|
||||||
**① 端到端(P2P)群聊**:群主即服务器,成员直连群主主机,适合局域网或公网 IP 场景。群密钥由群主生成并分享给成员。
|
**① End‑to‑End (P2P) Group**: The group owner acts as the server; members connect directly to the owner's host. Ideal for LAN or public‑IP environments. The owner generates the group key and shares it with members.
|
||||||
|
|
||||||
**② 中央服务器群聊**:运行 `server.py`(公网 IP)解决 NAT 穿透。服务器只负责用户认证、群成员管理、消息中继——**不持有群密钥,无法解密任何消息**。
|
**② Central Server Group**: Run `server.py` (public IP) to handle NAT traversal. The server only handles user authentication, group membership, and message relaying—**it does not hold group keys and cannot decrypt any messages.**
|
||||||
|
|
||||||
### 快速启动
|
### Quick Start
|
||||||
|
|
||||||
#### 启动聊天客户端
|
#### Launch the Chat Client
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ChaosCryptChat
|
cd ChaosCryptChat
|
||||||
python qtmain.py
|
python qtmain.py
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 启动中央服务器(可选,公网/NAT 场景)
|
#### Launch the Central Server (optional, for public/NAT scenarios)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ChaosCryptChat
|
cd ChaosCryptChat
|
||||||
python server.py 8666
|
python server.py 8666
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 安装依赖
|
#### Install Dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install PyQt5 # 必需,GUI 界面
|
pip install PyQt5 # Required, GUI
|
||||||
pip install pygame # 语音播放(可选)
|
pip install pygame # Audio playback (optional)
|
||||||
pip install sounddevice numpy # 录音(可选,或 pyaudio)
|
pip install sounddevice numpy # Recording (optional, or pyaudio)
|
||||||
pip install Pillow # 图片显示(可选)
|
pip install Pillow # Image display (optional)
|
||||||
pip install qrcode # 群密钥二维码(可选)
|
pip install qrcode # Group key QR codes (optional)
|
||||||
```
|
```
|
||||||
|
|
||||||
> 除 PyQt5 外均为可选依赖,未安装时对应功能自动禁用。
|
> Only PyQt5 is required; all others are optional. Missing dependencies disable their respective features gracefully.
|
||||||
|
|
||||||
### 使用流程
|
### Usage Workflow
|
||||||
|
|
||||||
1. **注册/登录**:启动后创建本地账户(PBKDF2 密码哈希,支持自动登录)
|
1. **Register / Login**: Create a local account on startup (PBKDF2 password hash, auto‑login supported)
|
||||||
2. **创建群**:点击「📡 创建群」,将群密钥复制/生成二维码分享给好友
|
2. **Create a Group**: Click 「📡 Create Group」, copy the group key or generate a QR code to share with friends
|
||||||
3. **加入群**:点击「📥 加入群」,粘贴群密钥或扫码加入
|
3. **Join a Group**: Click 「📥 Join Group」, paste the group key or scan the QR code
|
||||||
4. **开始聊天**:发送文本/图片/文件/语音;右键消息可撤回、分享、下载;群主可踢人、设公告、改群名
|
4. **Start Chatting**: Send text, images, files, voice messages; right‑click to recall, share, or download; group owners can kick, set announcements, and change group names
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 快速开始
|
## Quick Start
|
||||||
|
|
||||||
### 安装
|
### Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 克隆仓库
|
# Clone the repository
|
||||||
git clone https://gitcode.com/dvsxt/chaoscrypt.git
|
git clone https://gitcode.com/dvsxt/chaoscrypt.git
|
||||||
git clone https://github.com/dvs-dvsxt/ChaosCrypt.git
|
git clone https://github.com/dvs-dvsxt/ChaosCrypt.git
|
||||||
cd chaoscrypt
|
cd chaoscrypt
|
||||||
|
|
||||||
# 核心模块零依赖,Python 3.6+ 即可;ChaosCryptChat 需 PyQt5
|
# Core module has zero dependencies — Python 3.6+ only
|
||||||
|
# ChaosCryptChat requires PyQt5
|
||||||
```
|
```
|
||||||
|
|
||||||
### 五分钟上手
|
### Five‑Minute Example
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from chaoscrypt import EncryptionSystem
|
from chaoscrypt import EncryptionSystem
|
||||||
|
|
||||||
# 初始化(自动加载默认密钥,不存在则生成)
|
# Initialize (auto‑loads default key; generates one if missing)
|
||||||
crypto = EncryptionSystem()
|
crypto = EncryptionSystem()
|
||||||
|
|
||||||
# 加密
|
# Encrypt
|
||||||
cipher = crypto.encrypt("Hello World", user_password="MyP@ssw0rd2024!")
|
cipher = crypto.encrypt("Hello World", user_password="MyP@ssw0rd2024!")
|
||||||
print(cipher)
|
print(cipher)
|
||||||
|
|
||||||
# 解密
|
# Decrypt
|
||||||
plain = crypto.decrypt(cipher, user_password="MyP@ssw0rd2024!")
|
plain = crypto.decrypt(cipher, user_password="MyP@ssw0rd2024!")
|
||||||
print(plain) # Hello World
|
print(plain) # Hello World
|
||||||
```
|
```
|
||||||
|
|
||||||
### 命令行交互
|
### Command‑Line Interactive Mode
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python chaoscrypt.py
|
python chaoscrypt.py
|
||||||
@@ -347,51 +349,51 @@ python chaoscrypt.py
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 使用指南
|
## Usage Guide
|
||||||
|
|
||||||
### 交互菜单
|
### Interactive Menu
|
||||||
|
|
||||||
```
|
```
|
||||||
请选择操作:
|
Please select an action:
|
||||||
1. 使用默认密钥加密
|
1. Encrypt using the default key
|
||||||
2. 使用默认密钥解密
|
2. Decrypt using the default key
|
||||||
3. 生成新密钥(覆盖默认)
|
3. Generate a new key (overwrite default)
|
||||||
4. 使用指定密钥文件加密
|
4. Encrypt using a specified key file
|
||||||
5. 使用指定密钥文件解密
|
5. Decrypt using a specified key file
|
||||||
6. 生成密钥并保存到当前文件夹
|
6. Generate a key and save to current folder
|
||||||
7. 查看当前密钥信息
|
7. View current key info
|
||||||
8. 退出
|
8. Exit
|
||||||
```
|
```
|
||||||
|
|
||||||
### 密钥文件
|
### Key File
|
||||||
|
|
||||||
密钥文件以混淆形式存储,防止普通用户直接阅读。内容包括:
|
Keys are stored in an obfuscated format to prevent casual reading. Contents include:
|
||||||
|
|
||||||
- `upper_mapping` – 大写字母随机替换表
|
- `upper_mapping` – random substitution for uppercase letters
|
||||||
- `lower_mapping` – 小写字母随机替换表
|
- `lower_mapping` – random substitution for lowercase letters
|
||||||
- `digit_mapping` – 数字→字符映射
|
- `digit_mapping` – digit‑to‑character mapping
|
||||||
- `equal_mapping` – 等号映射
|
- `equal_mapping` – equal‑sign mapping
|
||||||
- `long_key` – 4096位十六进制密钥
|
- `long_key` – 4096‑bit hexadecimal key
|
||||||
- `short_key` – 512位十六进制密钥
|
- `short_key` – 512‑bit hexadecimal key
|
||||||
- `generated_at` – 生成时间戳
|
- `generated_at` – timestamp
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## API 参考
|
## API Reference
|
||||||
|
|
||||||
### `EncryptionSystem(key_file=None)`
|
### `EncryptionSystem(key_file=None)`
|
||||||
|
|
||||||
初始化加密系统。
|
Initialize the encryption system.
|
||||||
|
|
||||||
**参数:**
|
**Parameters:**
|
||||||
- `key_file` (str, optional) – 密钥文件路径。若为 None,自动加载 `encryption.key`;若不存在则生成。
|
- `key_file` (str, optional) – path to the key file. If `None`, loads `encryption.key`; generates one if missing.
|
||||||
|
|
||||||
**示例:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
# 使用默认密钥
|
# Use default key
|
||||||
crypto = EncryptionSystem()
|
crypto = EncryptionSystem()
|
||||||
|
|
||||||
# 使用指定密钥
|
# Use a custom key file
|
||||||
crypto = EncryptionSystem("my_key.key")
|
crypto = EncryptionSystem("my_key.key")
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -399,16 +401,16 @@ crypto = EncryptionSystem("my_key.key")
|
|||||||
|
|
||||||
### `encrypt(plaintext, user_password)`
|
### `encrypt(plaintext, user_password)`
|
||||||
|
|
||||||
加密明文。
|
Encrypt plaintext.
|
||||||
|
|
||||||
**参数:**
|
**Parameters:**
|
||||||
- `plaintext` (str) – 待加密文本
|
- `plaintext` (str) – text to encrypt
|
||||||
- `user_password` (str) – 用户密码
|
- `user_password` (str) – user password
|
||||||
|
|
||||||
**返回:**
|
**Returns:**
|
||||||
- `str` – 十六进制密文
|
- `str` – hexadecimal ciphertext
|
||||||
|
|
||||||
**示例:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
cipher = crypto.encrypt("Hello", "myPass123")
|
cipher = crypto.encrypt("Hello", "myPass123")
|
||||||
```
|
```
|
||||||
@@ -417,16 +419,16 @@ cipher = crypto.encrypt("Hello", "myPass123")
|
|||||||
|
|
||||||
### `decrypt(ciphertext, user_password)`
|
### `decrypt(ciphertext, user_password)`
|
||||||
|
|
||||||
解密密文。
|
Decrypt ciphertext.
|
||||||
|
|
||||||
**参数:**
|
**Parameters:**
|
||||||
- `ciphertext` (str) – 十六进制密文
|
- `ciphertext` (str) – hexadecimal ciphertext
|
||||||
- `user_password` (str) – 用户密码
|
- `user_password` (str) – user password
|
||||||
|
|
||||||
**返回:**
|
**Returns:**
|
||||||
- `str` – 解密后的明文,失败时返回错误信息
|
- `str` – decrypted plaintext, or an error message on failure
|
||||||
|
|
||||||
**示例:**
|
**Example:**
|
||||||
```python
|
```python
|
||||||
plain = crypto.decrypt("a1b2c3...", "myPass123")
|
plain = crypto.decrypt("a1b2c3...", "myPass123")
|
||||||
```
|
```
|
||||||
@@ -435,99 +437,99 @@ plain = crypto.decrypt("a1b2c3...", "myPass123")
|
|||||||
|
|
||||||
### `generate_keys(save_path=None)`
|
### `generate_keys(save_path=None)`
|
||||||
|
|
||||||
生成新的随机密钥并保存。
|
Generate new random keys and save them.
|
||||||
|
|
||||||
**参数:**
|
**Parameters:**
|
||||||
- `save_path` (str, optional) – 保存路径,默认 `key_{timestamp}.key`
|
- `save_path` (str, optional) – save path; defaults to `key_{timestamp}.key`
|
||||||
|
|
||||||
**返回:**
|
**Returns:**
|
||||||
- `str` – 保存的文件路径
|
- `str` – the saved file path
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `print_keys()`
|
### `print_keys()`
|
||||||
|
|
||||||
打印当前密钥信息。
|
Print the current key information.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 常见问题
|
## FAQ
|
||||||
|
|
||||||
**Q:这算法经过审计吗?**
|
**Q: Has this algorithm been audited?**
|
||||||
A:没有。但我们认为**没有审计 ≠ 不安全**,Dual_EC_DRBG 经过审计却是后门。审计只是参考,不是真理。
|
A: No. But we believe **no audit ≠ insecure** — Dual_EC_DRBG was audited and backdoored. Audits are references, not truth.
|
||||||
|
|
||||||
**Q:为什么不直接用 AES?**
|
**Q: Why not just use AES?**
|
||||||
A:AES 很好,但它是"标准"算法,有代数结构,Grover 可以加速。我们选择另一条路——**完全随机、无结构、超大空间**。
|
A: AES is great, but it's a "standard" algorithm with algebraic structure, and Grover can speed it up. We chose a different path — **fully random, structure‑free, and enormous.**
|
||||||
|
|
||||||
**Q:如果黑客拿到了 `.key` 文件和密文,但不知道密码呢?**
|
**Q: What if an attacker gets the `.key` file and the ciphertext, but not the password?**
|
||||||
A:那他就只能暴力破解密码。如果密码是 12 位以上强密码,破解时间以年为单位。
|
A: Then they're left with brute‑forcing the password. If the password is 12+ characters strong, that's years of work.
|
||||||
|
|
||||||
**Q:如果黑客同时拿到了 `.key`、密文、密码呢?**
|
**Q: What if the attacker gets the `.key`, ciphertext, and password?**
|
||||||
A:那你的系统已经不属于"加密被攻破",而是"钥匙被偷"——这是端侧安全问题,任何加密算法都防不住。
|
A: Then your system isn't "crypto broken" — it's "keys stolen." That's a client‑side security issue, which no encryption algorithm can prevent.
|
||||||
|
|
||||||
**Q:这算法有数学证明吗?**
|
**Q: Is there a mathematical proof for this?**
|
||||||
A:有。证明如下:
|
A: Yes. The proof is:
|
||||||
- 无法建立数学模型 → 无代数攻击路径
|
- No mathematical model can be constructed → no algebraic attacks
|
||||||
- 密钥空间 10⁵⁶³² → 暴力不可能
|
- Key space 10⁵⁶³² → brute force impossible
|
||||||
- 量子加速无效 → 抗量子
|
- Quantum speedups don't help → quantum‑resistant
|
||||||
|
|
||||||
这个证明比任何"归约到难问题"都更硬——因为**没有结构可归约,只能枚举**。
|
This proof is stronger than any "reduction to a hard problem" — because **there's no structure to reduce, only exhaustive search.**
|
||||||
|
|
||||||
**Q:看起来好初级,真能用?**
|
**Q: It looks so amateurish — is it actually usable?**
|
||||||
A:初级和安全没有半毛钱关系。你长得好看能挡子弹吗?能破就是能破,不能破就是不能破。**你破一个试试?**
|
A: Looking amateur and being secure have nothing to do with each other. Can you break it or not? **Try it.**
|
||||||
|
|
||||||
**Q:ChaosCryptChat 聊天安全吗?**
|
**Q: Is ChaosCryptChat secure?**
|
||||||
A:端到端加密——消息在客户端用群密钥混沌加密,服务器只转发密文、不持有密钥。即使服务器被入侵也拿不到聊天内容。
|
A: End‑to‑end — messages are encrypted client‑side with the group key; the server forwards only ciphertext and holds no keys. Even if the server is breached, chat contents remain private.
|
||||||
|
|
||||||
**Q:聊天密钥怎么分享?**
|
**Q: How do I share the group key?**
|
||||||
A:群主创建群后生成群密钥,可通过复制文本、二维码、密钥文件三种方式分享。请走可信渠道传递,避免被中间人截获。
|
A: After creating a group, the owner can share the key via copied text, QR code, or key file. Use a trusted channel to avoid MITM interception.
|
||||||
|
|
||||||
**Q:ChaosCryptChat 需要公网 IP 吗?**
|
**Q: Does ChaosCryptChat require a public IP?**
|
||||||
A:不需要。局域网用 P2P 直连即可;跨网络用中央服务器(server.py)中继,解决 NAT 穿透。
|
A: No. Use P2P for LAN; for cross‑network, the central server (`server.py`) relays traffic to handle NAT.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 项目结构
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
chaoscrypt/
|
chaoscrypt/
|
||||||
├── chaoscrypt.py # 主程序(加密/解密/密钥管理)
|
├── chaoscrypt.py # Main program (encrypt/decrypt/key management)
|
||||||
├── README.md # 本文档
|
├── README.md # This document
|
||||||
├── SECURITY.md # 安全说明文档
|
├── SECURITY.md # Security details
|
||||||
└── ChaosCryptChat/ # 💬 混沌加密聊天(v2.0 新增)
|
└── ChaosCryptChat/ # 💬 Encrypted Chat (v2.0 new)
|
||||||
├── qtmain.py # PyQt5 聊天客户端(端到端加密)
|
├── qtmain.py # PyQt5 chat client (E2E encrypted)
|
||||||
└── server.py # ☁️ 中央服务器(NAT 穿透 / 消息中继)
|
└── server.py # ☁️ Central server (NAT traversal / message relay)
|
||||||
```
|
```
|
||||||
|
|
||||||
核心就三个文件,零依赖;ChaosCryptChat 是 v2.0 新增的加密聊天模块。
|
The core is just three files with zero dependencies; ChaosCryptChat is the v2.0 addition.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 免责声明
|
## Disclaimer
|
||||||
|
|
||||||
> **本系统仅供学习研究使用。**
|
> **This system is for educational and research purposes only.**
|
||||||
> 作者不承担因密钥文件泄露、密码失窃、端侧入侵等导致的任何数据损失责任。
|
> The author assumes no liability for data loss due to key file leakage, password theft, or client‑side compromise.
|
||||||
> 生产环境请确保 `.key` 文件和用户密码均安全存储,并考虑强制用户使用强密码策略。
|
> In production, ensure the `.key` file and user password are stored securely, and enforce strong password policies.
|
||||||
> **ChaosCryptChat** 服务器不持有群密钥,但会记录用户登录信息与消息中继日志,请谨慎选择信任的服务器。
|
> **ChaosCryptChat** servers do not hold group keys, but they do log login information and relay metadata—choose your server wisely.
|
||||||
> 聊天密钥由群主分享,请通过可信渠道传递;即使服务器被攻陷也不会泄露历史聊天内容。
|
> Group keys are shared by the group owner; transmit them over trusted channels. Even if the server is compromised, historical chat content remains private.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📜 许可证
|
## 📜 License
|
||||||
|
|
||||||
MIT License — 你可以自由使用、修改、分发,但请保留原作者声明。
|
MIT License — you are free to use, modify, and distribute, but please retain the original attribution.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🙏 致谢
|
## 🙏 Acknowledgments
|
||||||
|
|
||||||
感谢所有认真看完这份文档的人。
|
Thank you to everyone who read this document carefully.
|
||||||
你是极少数愿意**用逻辑判断安全,而不是用头衔判断安全**的人。
|
You are among the few who judge security by **logic**, not by **credentials**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**"安全应该由攻击难度定义,而不是由某个机构盖章定义。"**
|
**"Security should be defined by the difficulty of attack, not by a stamp from an institution."**
|
||||||
—— ChaosCrypt 设计哲学
|
— ChaosCrypt Design Philosophy
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+272
-160
@@ -1,3 +1,7 @@
|
|||||||
|
"""
|
||||||
|
A multi-layer encryption system with key management, substitution ciphers,
|
||||||
|
XOR operations, and dynamic key derivation.
|
||||||
|
"""
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
@@ -5,12 +9,23 @@ import os
|
|||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class EncryptionSystem:
|
class EncryptionSystem:
|
||||||
|
"""Main encryption engine with key-based transformation layers."""
|
||||||
|
|
||||||
def __init__(self, key_file=None, key_password=None):
|
def __init__(self, key_file=None, key_password=None):
|
||||||
|
"""
|
||||||
|
Initialize the encryption system with an optional key file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key_file: Path to the encryption key file.
|
||||||
|
key_password: Password for decrypting the key file.
|
||||||
|
"""
|
||||||
self.key_file = key_file
|
self.key_file = key_file
|
||||||
self.key_password = key_password
|
self.key_password = key_password
|
||||||
self.keys_loaded = False
|
self.keys_loaded = False
|
||||||
|
|
||||||
|
# Base64 special character mappings for safe transport
|
||||||
self.special_encrypt = {
|
self.special_encrypt = {
|
||||||
'+': '.',
|
'+': '.',
|
||||||
'/': "'",
|
'/': "'",
|
||||||
@@ -23,38 +38,46 @@ class EncryptionSystem:
|
|||||||
|
|
||||||
self.flip_pattern = None
|
self.flip_pattern = None
|
||||||
|
|
||||||
|
# Try loading the key file if provided or find default
|
||||||
if key_file:
|
if key_file:
|
||||||
if os.path.exists(key_file):
|
if os.path.exists(key_file):
|
||||||
if key_password is None:
|
if key_password is None:
|
||||||
key_password = input(f"请输入密钥文件 {key_file} 的密码: ")
|
key_password = input(f"Enter password for key file {key_file}: ")
|
||||||
self._load_keys(key_file, key_password)
|
self._load_keys(key_file, key_password)
|
||||||
self.keys_loaded = True
|
self.keys_loaded = True
|
||||||
else:
|
else:
|
||||||
print(f"⚠️ 密钥文件 {key_file} 不存在")
|
print(f"⚠️ Key file {key_file} not found")
|
||||||
self.keys_loaded = False
|
self.keys_loaded = False
|
||||||
else:
|
else:
|
||||||
default_key = "encryption.key"
|
default_key = "encryption.key"
|
||||||
if os.path.exists(default_key):
|
if os.path.exists(default_key):
|
||||||
self.key_file = default_key
|
self.key_file = default_key
|
||||||
if key_password is None:
|
if key_password is None:
|
||||||
key_password = input(f"请输入密钥文件 {default_key} 的密码: ")
|
key_password = input(f"Enter password for key file {default_key}: ")
|
||||||
self._load_keys(default_key, key_password)
|
self._load_keys(default_key, key_password)
|
||||||
self.keys_loaded = True
|
self.keys_loaded = True
|
||||||
else:
|
else:
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("首次启动,请先生成密钥文件")
|
print("First launch detected. Please generate a key file first.")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
self.keys_loaded = False
|
self.keys_loaded = False
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Key generation utilities
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
def _generate_random_alphabet(self, lowercase=False):
|
def _generate_random_alphabet(self, lowercase=False):
|
||||||
|
"""Generate a shuffled alphabet string."""
|
||||||
chars = list("abcdefghijklmnopqrstuvwxyz" if lowercase else "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
chars = list("abcdefghijklmnopqrstuvwxyz" if lowercase else "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
n = len(chars)
|
n = len(chars)
|
||||||
|
# Fisher-Yates shuffle using secure random bytes
|
||||||
for i in range(n - 1, 0, -1):
|
for i in range(n - 1, 0, -1):
|
||||||
j = int.from_bytes(os.urandom(1), 'big') % (i + 1)
|
j = int.from_bytes(os.urandom(1), 'big') % (i + 1)
|
||||||
chars[i], chars[j] = chars[j], chars[i]
|
chars[i], chars[j] = chars[j], chars[i]
|
||||||
return ''.join(chars)
|
return ''.join(chars)
|
||||||
|
|
||||||
def _generate_random_digit_mapping(self):
|
def _generate_random_digit_mapping(self):
|
||||||
|
"""Create a random mapping for digits 0-9 to alphabet characters."""
|
||||||
digits = list("0123456789")
|
digits = list("0123456789")
|
||||||
mapping_chars = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
mapping_chars = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||||
n = len(mapping_chars)
|
n = len(mapping_chars)
|
||||||
@@ -67,72 +90,69 @@ class EncryptionSystem:
|
|||||||
return mapping
|
return mapping
|
||||||
|
|
||||||
def _generate_random_equal_mapping(self):
|
def _generate_random_equal_mapping(self):
|
||||||
|
"""Generate mapping for Base64 padding count (0-3)."""
|
||||||
chars = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
chars = list("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||||
n = len(chars)
|
n = len(chars)
|
||||||
for i in range(n - 1, 0, -1):
|
for i in range(n - 1, 0, -1):
|
||||||
j = int.from_bytes(os.urandom(1), 'big') % (i + 1)
|
j = int.from_bytes(os.urandom(1), 'big') % (i + 1)
|
||||||
chars[i], chars[j] = chars[j], chars[i]
|
chars[i], chars[j] = chars[j], chars[i]
|
||||||
mapping = {
|
return {
|
||||||
'0': chars[0],
|
'0': chars[0],
|
||||||
'1': chars[1],
|
'1': chars[1],
|
||||||
'2': chars[2],
|
'2': chars[2],
|
||||||
'3': chars[3]
|
'3': chars[3]
|
||||||
}
|
}
|
||||||
return mapping
|
|
||||||
|
|
||||||
def _generate_random_flip_pattern(self):
|
def _generate_random_flip_pattern(self):
|
||||||
pattern = []
|
"""Generate a 10-bit pattern for case-flipping."""
|
||||||
for _ in range(10):
|
return [int.from_bytes(os.urandom(1), 'big') % 2 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):
|
def _generate_long_key(self, length=4096):
|
||||||
|
"""Generate a long hex key (4096 chars by default)."""
|
||||||
chars = "0123456789abcdef"
|
chars = "0123456789abcdef"
|
||||||
result = []
|
return ''.join(chars[int.from_bytes(os.urandom(1), 'big') % 16] for _ in range(length))
|
||||||
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):
|
def _generate_short_key(self, length=512):
|
||||||
|
"""Generate a short hex key (512 chars by default)."""
|
||||||
chars = "0123456789abcdef"
|
chars = "0123456789abcdef"
|
||||||
result = []
|
return ''.join(chars[int.from_bytes(os.urandom(1), 'big') % 16] for _ in range(length))
|
||||||
for _ in range(length):
|
|
||||||
idx = int.from_bytes(os.urandom(1), 'big') % 16
|
# ----------------------------------------------------------------------
|
||||||
result.append(chars[idx])
|
# Key obfuscation and persistence
|
||||||
return ''.join(result)
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
def _obfuscate_keys(self, keys_data):
|
def _obfuscate_keys(self, keys_data):
|
||||||
|
"""Obfuscate key data using base64 + reversal + Caesar shift."""
|
||||||
json_str = json.dumps(keys_data)
|
json_str = json.dumps(keys_data)
|
||||||
b64 = base64.b64encode(json_str.encode()).decode()
|
b64 = base64.b64encode(json_str.encode()).decode()
|
||||||
reversed_b64 = b64[::-1]
|
reversed_b64 = b64[::-1]
|
||||||
shifted = ''.join([chr((ord(c) + 1) % 128) for c in reversed_b64])
|
shifted = ''.join(chr((ord(c) + 1) % 128) for c in reversed_b64)
|
||||||
final = base64.b64encode(shifted.encode()).decode()
|
return base64.b64encode(shifted.encode()).decode()
|
||||||
return final
|
|
||||||
|
|
||||||
def _deobfuscate_keys(self, obfuscated_data):
|
def _deobfuscate_keys(self, obfuscated_data):
|
||||||
|
"""Reverse the obfuscation to recover original key data."""
|
||||||
try:
|
try:
|
||||||
shifted = base64.b64decode(obfuscated_data.encode()).decode()
|
shifted = base64.b64decode(obfuscated_data.encode()).decode()
|
||||||
reversed_b64 = ''.join([chr((ord(c) - 1) % 128) for c in shifted])
|
reversed_b64 = ''.join(chr((ord(c) - 1) % 128) for c in shifted)
|
||||||
b64 = reversed_b64[::-1]
|
b64 = reversed_b64[::-1]
|
||||||
json_str = base64.b64decode(b64.encode()).decode()
|
json_str = base64.b64decode(b64.encode()).decode()
|
||||||
return json.loads(json_str)
|
return json.loads(json_str)
|
||||||
except Exception:
|
except Exception as exc:
|
||||||
raise Exception("密钥文件损坏")
|
raise Exception("Key file corrupted") from exc
|
||||||
|
|
||||||
def _xor_encrypt_data(self, data, password):
|
def _xor_encrypt_data(self, data, password):
|
||||||
result = []
|
"""XOR encrypt data with a password, returning hex string."""
|
||||||
key_len = len(password)
|
key_len = len(password)
|
||||||
for i, char in enumerate(data):
|
return ''.join(
|
||||||
xor_result = ord(char) ^ ord(password[i % key_len])
|
f"{ord(char) ^ ord(password[i % key_len]):02x}"
|
||||||
result.append(f"{xor_result:02x}")
|
for i, char in enumerate(data)
|
||||||
return ''.join(result)
|
)
|
||||||
|
|
||||||
def _xor_decrypt_data(self, hex_data, password):
|
def _xor_decrypt_data(self, hex_data, password):
|
||||||
|
"""XOR decrypt hex data with a password."""
|
||||||
try:
|
try:
|
||||||
result = []
|
|
||||||
key_len = len(password)
|
key_len = len(password)
|
||||||
|
result = []
|
||||||
for i in range(0, len(hex_data), 2):
|
for i in range(0, len(hex_data), 2):
|
||||||
if i + 1 < len(hex_data):
|
if i + 1 < len(hex_data):
|
||||||
hex_byte = hex_data[i:i+2]
|
hex_byte = hex_data[i:i+2]
|
||||||
@@ -143,17 +163,28 @@ class EncryptionSystem:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def generate_keys(self, save_path=None, key_password=None):
|
def generate_keys(self, save_path=None, key_password=None):
|
||||||
|
"""
|
||||||
|
Generate a fresh set of encryption keys and save to a key file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
save_path: Path to save the key file (default: encryption.key).
|
||||||
|
key_password: Password to protect the key file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The password used, or None if generation failed.
|
||||||
|
"""
|
||||||
if key_password is None:
|
if key_password is None:
|
||||||
key_password = input("请设置密钥文件密码: ")
|
key_password = input("Set key file password: ")
|
||||||
confirm = input("请再次输入密码确认: ")
|
confirm = input("Confirm password: ")
|
||||||
if key_password != confirm:
|
if key_password != confirm:
|
||||||
print("❌ 密码不匹配")
|
print("❌ Passwords do not match")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("正在生成随机密钥...")
|
print("Generating random keys...")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
|
# Generate all key components
|
||||||
self.upper_mapping = self._generate_random_alphabet(lowercase=False)
|
self.upper_mapping = self._generate_random_alphabet(lowercase=False)
|
||||||
self.lower_mapping = self._generate_random_alphabet(lowercase=True)
|
self.lower_mapping = self._generate_random_alphabet(lowercase=True)
|
||||||
self.digit_mapping = self._generate_random_digit_mapping()
|
self.digit_mapping = self._generate_random_digit_mapping()
|
||||||
@@ -162,9 +193,11 @@ class EncryptionSystem:
|
|||||||
self.long_key = self._generate_long_key(4096)
|
self.long_key = self._generate_long_key(4096)
|
||||||
self.short_key = self._generate_short_key(512)
|
self.short_key = self._generate_short_key(512)
|
||||||
|
|
||||||
|
# Build reverse mappings
|
||||||
self.digit_reverse = {v: k for k, v in self.digit_mapping.items()}
|
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.equal_reverse = {v: k for k, v in self.equal_mapping.items()}
|
||||||
|
|
||||||
|
# Bundle keys into a dictionary
|
||||||
keys_data = {
|
keys_data = {
|
||||||
'upper_mapping': self.upper_mapping,
|
'upper_mapping': self.upper_mapping,
|
||||||
'lower_mapping': self.lower_mapping,
|
'lower_mapping': self.lower_mapping,
|
||||||
@@ -176,6 +209,7 @@ class EncryptionSystem:
|
|||||||
'generated_at': datetime.now().isoformat()
|
'generated_at': datetime.now().isoformat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Obfuscate and encrypt the key data
|
||||||
obfuscated = self._obfuscate_keys(keys_data)
|
obfuscated = self._obfuscate_keys(keys_data)
|
||||||
encrypted = self._xor_encrypt_data(obfuscated, key_password)
|
encrypted = self._xor_encrypt_data(obfuscated, key_password)
|
||||||
|
|
||||||
@@ -190,12 +224,17 @@ class EncryptionSystem:
|
|||||||
self.keys_loaded = True
|
self.keys_loaded = True
|
||||||
self._build_maps()
|
self._build_maps()
|
||||||
|
|
||||||
print(f"✅ 密钥已生成并保存到: {save_path}")
|
print(f"✅ Keys generated and saved to: {save_path}")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
return save_path
|
return save_path
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# Internal helpers
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
def _build_maps(self):
|
def _build_maps(self):
|
||||||
|
"""Build encryption and decryption maps from shuffled alphabets."""
|
||||||
self.upper_original = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
self.upper_original = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
self.lower_original = "abcdefghijklmnopqrstuvwxyz"
|
self.lower_original = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
@@ -208,13 +247,14 @@ class EncryptionSystem:
|
|||||||
self.decrypt_map[self.lower_mapping[i]] = self.lower_original[i]
|
self.decrypt_map[self.lower_mapping[i]] = self.lower_original[i]
|
||||||
|
|
||||||
def _load_keys(self, key_file, key_password):
|
def _load_keys(self, key_file, key_password):
|
||||||
|
"""Load and decrypt keys from a key file."""
|
||||||
try:
|
try:
|
||||||
with open(key_file, 'r') as f:
|
with open(key_file, 'r') as f:
|
||||||
encrypted_data = f.read()
|
encrypted_data = f.read()
|
||||||
|
|
||||||
decrypted = self._xor_decrypt_data(encrypted_data, key_password)
|
decrypted = self._xor_decrypt_data(encrypted_data, key_password)
|
||||||
if decrypted is None:
|
if decrypted is None:
|
||||||
print("❌ 密码错误")
|
print("❌ Incorrect password")
|
||||||
self.keys_loaded = False
|
self.keys_loaded = False
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -235,17 +275,18 @@ class EncryptionSystem:
|
|||||||
self._build_maps()
|
self._build_maps()
|
||||||
|
|
||||||
self.keys_loaded = True
|
self.keys_loaded = True
|
||||||
print(f"✅ 密钥已从 {key_file} 加载")
|
print(f"✅ Keys loaded from {key_file}")
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
print("❌ 加载失败")
|
print("❌ Loading failed")
|
||||||
self.keys_loaded = False
|
self.keys_loaded = False
|
||||||
|
|
||||||
def _ensure_printable(self, text):
|
def _ensure_printable(self, text):
|
||||||
|
"""Force all characters into printable ASCII range (32-126)."""
|
||||||
result = []
|
result = []
|
||||||
for c in text:
|
for c in text:
|
||||||
val = ord(c)
|
val = ord(c)
|
||||||
if val == 124:
|
if val == 124: # '|' is used as a separator, keep it
|
||||||
result.append('|')
|
result.append('|')
|
||||||
elif val < 32 or val > 126:
|
elif val < 32 or val > 126:
|
||||||
val = val % 95 + 32
|
val = val % 95 + 32
|
||||||
@@ -254,10 +295,25 @@ class EncryptionSystem:
|
|||||||
result.append(c)
|
result.append(c)
|
||||||
return ''.join(result)
|
return ''.join(result)
|
||||||
|
|
||||||
def _mix_keys(self, user_password, target_length):
|
# ----------------------------------------------------------------------
|
||||||
if not self.keys_loaded:
|
# Key derivation
|
||||||
raise Exception("密钥未加载")
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _mix_keys(self, user_password, target_length):
|
||||||
|
"""
|
||||||
|
Mix the user password with the short key using bit operations and swaps.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_password: User-provided password.
|
||||||
|
target_length: Desired output length.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A mixed printable string.
|
||||||
|
"""
|
||||||
|
if not self.keys_loaded:
|
||||||
|
raise Exception("Keys not loaded")
|
||||||
|
|
||||||
|
# Interleave user password and short key
|
||||||
mixed = []
|
mixed = []
|
||||||
max_len = max(len(user_password), len(self.short_key))
|
max_len = max(len(user_password), len(self.short_key))
|
||||||
for i in range(max_len):
|
for i in range(max_len):
|
||||||
@@ -266,6 +322,7 @@ class EncryptionSystem:
|
|||||||
if i < len(self.short_key):
|
if i < len(self.short_key):
|
||||||
mixed.append(ord(self.short_key[i]))
|
mixed.append(ord(self.short_key[i]))
|
||||||
|
|
||||||
|
# Apply bit transformations
|
||||||
for i in range(len(mixed)):
|
for i in range(len(mixed)):
|
||||||
if i % 3 == 0:
|
if i % 3 == 0:
|
||||||
mixed[i] = (mixed[i] << 1) & 0xFF
|
mixed[i] = (mixed[i] << 1) & 0xFF
|
||||||
@@ -274,12 +331,14 @@ class EncryptionSystem:
|
|||||||
else:
|
else:
|
||||||
mixed[i] = mixed[i] ^ 0x5A
|
mixed[i] = mixed[i] ^ 0x5A
|
||||||
|
|
||||||
|
# Swap pairs
|
||||||
for i in range(0, len(mixed) - 3, 4):
|
for i in range(0, len(mixed) - 3, 4):
|
||||||
mixed[i], mixed[i+3] = mixed[i+3], mixed[i]
|
mixed[i], mixed[i+3] = mixed[i+3], mixed[i]
|
||||||
mixed[i+1], mixed[i+2] = mixed[i+2], mixed[i+1]
|
mixed[i+1], mixed[i+2] = mixed[i+2], mixed[i+1]
|
||||||
|
|
||||||
mixed.reverse()
|
mixed.reverse()
|
||||||
|
|
||||||
|
# Convert to printable characters
|
||||||
result = []
|
result = []
|
||||||
for x in mixed:
|
for x in mixed:
|
||||||
if x < 32 or x > 126:
|
if x < 32 or x > 126:
|
||||||
@@ -288,6 +347,7 @@ class EncryptionSystem:
|
|||||||
|
|
||||||
result_str = ''.join(result)
|
result_str = ''.join(result)
|
||||||
|
|
||||||
|
# Extend if needed by repeating with variations
|
||||||
if len(result_str) < target_length:
|
if len(result_str) < target_length:
|
||||||
base_key = result_str
|
base_key = result_str
|
||||||
final_key = base_key
|
final_key = base_key
|
||||||
@@ -297,10 +357,10 @@ class EncryptionSystem:
|
|||||||
next_chunk = base_key[::-1]
|
next_chunk = base_key[::-1]
|
||||||
elif iteration % 3 == 1:
|
elif iteration % 3 == 1:
|
||||||
next_chunk = base_key[::-1]
|
next_chunk = base_key[::-1]
|
||||||
next_chunk = ''.join([chr((ord(c) + iteration) % 95 + 32) for c in next_chunk])
|
next_chunk = ''.join(chr((ord(c) + iteration) % 95 + 32) for c in next_chunk)
|
||||||
else:
|
else:
|
||||||
next_chunk = base_key[::-1]
|
next_chunk = base_key[::-1]
|
||||||
next_chunk = ''.join([chr((ord(c) ^ iteration) % 95 + 32) for c in next_chunk])
|
next_chunk = ''.join(chr((ord(c) ^ iteration) % 95 + 32) for c in next_chunk)
|
||||||
final_key += next_chunk
|
final_key += next_chunk
|
||||||
iteration += 1
|
iteration += 1
|
||||||
result_str = final_key[:target_length]
|
result_str = final_key[:target_length]
|
||||||
@@ -308,11 +368,18 @@ class EncryptionSystem:
|
|||||||
return self._ensure_printable(result_str)
|
return self._ensure_printable(result_str)
|
||||||
|
|
||||||
def _derive_final_key(self, user_password, text_length):
|
def _derive_final_key(self, user_password, text_length):
|
||||||
|
"""
|
||||||
|
Derive a final encryption key from the user password and short key.
|
||||||
|
|
||||||
|
The process includes mixing, hex conversion, reversal, and extension.
|
||||||
|
"""
|
||||||
mixed_key = self._mix_keys(user_password, text_length * 2)
|
mixed_key = self._mix_keys(user_password, text_length * 2)
|
||||||
|
|
||||||
hex_key = ''.join([f"{ord(c):02x}" for c in mixed_key])
|
# Convert to hex and reverse
|
||||||
|
hex_key = ''.join(f"{ord(c):02x}" for c in mixed_key)
|
||||||
reversed_hex = hex_key[::-1]
|
reversed_hex = hex_key[::-1]
|
||||||
|
|
||||||
|
# Convert back to printable characters
|
||||||
final_key = []
|
final_key = []
|
||||||
for i in range(0, len(reversed_hex), 2):
|
for i in range(0, len(reversed_hex), 2):
|
||||||
if i + 1 < len(reversed_hex):
|
if i + 1 < len(reversed_hex):
|
||||||
@@ -327,6 +394,7 @@ class EncryptionSystem:
|
|||||||
|
|
||||||
final_key_str = ''.join(final_key)
|
final_key_str = ''.join(final_key)
|
||||||
|
|
||||||
|
# Extend if needed
|
||||||
if len(final_key_str) < text_length:
|
if len(final_key_str) < text_length:
|
||||||
base_key = final_key_str
|
base_key = final_key_str
|
||||||
iteration = 0
|
iteration = 0
|
||||||
@@ -335,19 +403,22 @@ class EncryptionSystem:
|
|||||||
next_chunk = base_key[::-1]
|
next_chunk = base_key[::-1]
|
||||||
elif iteration % 3 == 1:
|
elif iteration % 3 == 1:
|
||||||
next_chunk = base_key[::-1]
|
next_chunk = base_key[::-1]
|
||||||
next_chunk = ''.join([chr((ord(c) + iteration) % 95 + 32) for c in next_chunk])
|
next_chunk = ''.join(chr((ord(c) + iteration) % 95 + 32) for c in next_chunk)
|
||||||
else:
|
else:
|
||||||
next_chunk = base_key[::-1]
|
next_chunk = base_key[::-1]
|
||||||
next_chunk = ''.join([chr((ord(c) ^ iteration) % 95 + 32) for c in next_chunk])
|
next_chunk = ''.join(chr((ord(c) ^ iteration) % 95 + 32) for c in next_chunk)
|
||||||
final_key_str += next_chunk
|
final_key_str += next_chunk
|
||||||
iteration += 1
|
iteration += 1
|
||||||
|
|
||||||
final_key_str = final_key_str[:text_length]
|
final_key_str = final_key_str[:text_length]
|
||||||
final_key_str = self._ensure_printable(final_key_str)
|
return self._ensure_printable(final_key_str)
|
||||||
|
|
||||||
return final_key_str
|
# ----------------------------------------------------------------------
|
||||||
|
# Core encryption operations
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
def _apply_flip(self, text):
|
def _apply_flip(self, text):
|
||||||
|
"""Apply case-flipping based on the flip pattern."""
|
||||||
if self.flip_pattern is None:
|
if self.flip_pattern is None:
|
||||||
return text
|
return text
|
||||||
|
|
||||||
@@ -361,15 +432,16 @@ class EncryptionSystem:
|
|||||||
return ''.join(result)
|
return ''.join(result)
|
||||||
|
|
||||||
def _xor_encrypt_with_final_key(self, text, user_password):
|
def _xor_encrypt_with_final_key(self, text, user_password):
|
||||||
|
"""XOR encrypt with the derived final key, returning hex."""
|
||||||
final_key = self._derive_final_key(user_password, len(text))
|
final_key = self._derive_final_key(user_password, len(text))
|
||||||
key_len = len(final_key)
|
key_len = len(final_key)
|
||||||
result = []
|
return ''.join(
|
||||||
for i, char in enumerate(text):
|
f"{ord(char) ^ ord(final_key[i % key_len]):02x}"
|
||||||
xor_result = ord(char) ^ ord(final_key[i % key_len])
|
for i, char in enumerate(text)
|
||||||
result.append(f"{xor_result:02x}")
|
)
|
||||||
return ''.join(result)
|
|
||||||
|
|
||||||
def _xor_decrypt_with_final_key(self, hex_text, user_password):
|
def _xor_decrypt_with_final_key(self, hex_text, user_password):
|
||||||
|
"""XOR decrypt with the derived final key."""
|
||||||
try:
|
try:
|
||||||
text_length = len(hex_text) // 2
|
text_length = len(hex_text) // 2
|
||||||
final_key = self._derive_final_key(user_password, text_length)
|
final_key = self._derive_final_key(user_password, text_length)
|
||||||
@@ -390,47 +462,35 @@ class EncryptionSystem:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _substitute_letters(self, text, mapping):
|
def _substitute_letters(self, text, mapping):
|
||||||
result = []
|
"""Apply a substitution map to letters."""
|
||||||
for char in text:
|
return ''.join(mapping.get(char, char) 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):
|
def _encode_digit(self, num_str):
|
||||||
result = []
|
"""Encode a digit string using the digit mapping."""
|
||||||
for char in num_str:
|
return ''.join(self.digit_mapping.get(char, char) 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):
|
def _decode_digit(self, encoded_str):
|
||||||
result = []
|
"""Decode a digit string using the reverse digit mapping."""
|
||||||
for char in encoded_str:
|
return ''.join(self.digit_reverse.get(char, char) 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):
|
def _get_dynamic_key(self, text_length):
|
||||||
|
"""Generate a dynamic key from the long key, repeated as needed."""
|
||||||
key = self.long_key
|
key = self.long_key
|
||||||
while len(key) < text_length:
|
if len(key) < text_length:
|
||||||
key += self.long_key
|
repeats = (text_length // len(key)) + 1
|
||||||
|
key = (key * repeats)[:text_length]
|
||||||
return key[:text_length]
|
return key[:text_length]
|
||||||
|
|
||||||
def _xor_encrypt_with_key(self, text, key):
|
def _xor_encrypt_with_key(self, text, key):
|
||||||
|
"""XOR encrypt with a fixed key, returning hex."""
|
||||||
key_len = len(key)
|
key_len = len(key)
|
||||||
result = []
|
return ''.join(
|
||||||
for i, char in enumerate(text):
|
f"{ord(char) ^ ord(key[i % key_len]):02x}"
|
||||||
xor_result = ord(char) ^ ord(key[i % key_len])
|
for i, char in enumerate(text)
|
||||||
result.append(f"{xor_result:02x}")
|
)
|
||||||
return ''.join(result)
|
|
||||||
|
|
||||||
def _xor_decrypt_with_key(self, hex_text, key):
|
def _xor_decrypt_with_key(self, hex_text, key):
|
||||||
|
"""XOR decrypt with a fixed key."""
|
||||||
try:
|
try:
|
||||||
key_len = len(key)
|
key_len = len(key)
|
||||||
result = []
|
result = []
|
||||||
@@ -448,10 +508,28 @@ class EncryptionSystem:
|
|||||||
except Exception:
|
except Exception:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def encrypt(self, plaintext, user_password):
|
# ----------------------------------------------------------------------
|
||||||
if not self.keys_loaded:
|
# Public API
|
||||||
return "❌ 错误:密钥未加载"
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
def encrypt(self, plaintext, user_password):
|
||||||
|
"""
|
||||||
|
Encrypt plaintext with the given password.
|
||||||
|
|
||||||
|
Workflow:
|
||||||
|
1. Base64 encode the plaintext.
|
||||||
|
2. Apply letter substitution and case-flipping.
|
||||||
|
3. Reverse the string and append padding count.
|
||||||
|
4. XOR encrypt with dynamic key (long key).
|
||||||
|
5. XOR encrypt with derived final key (user password + short key).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Encrypted ciphertext as a hex string.
|
||||||
|
"""
|
||||||
|
if not self.keys_loaded:
|
||||||
|
return "❌ Error: Keys not loaded"
|
||||||
|
|
||||||
|
# Step 1: Base64 encode and handle special chars
|
||||||
b64 = base64.b64encode(plaintext.encode('utf-8')).decode('utf-8')
|
b64 = base64.b64encode(plaintext.encode('utf-8')).decode('utf-8')
|
||||||
equal_count = b64.count('=')
|
equal_count = b64.count('=')
|
||||||
|
|
||||||
@@ -460,33 +538,44 @@ class EncryptionSystem:
|
|||||||
processed = processed.replace(old, new)
|
processed = processed.replace(old, new)
|
||||||
processed = processed.rstrip('=')
|
processed = processed.rstrip('=')
|
||||||
|
|
||||||
|
# Step 2: Letter substitution + flip + reverse
|
||||||
sub = self._substitute_letters(processed, self.encrypt_map)
|
sub = self._substitute_letters(processed, self.encrypt_map)
|
||||||
flipped = self._apply_flip(sub)
|
flipped = self._apply_flip(sub)
|
||||||
reversed_text = flipped[::-1]
|
reversed_text = flipped[::-1]
|
||||||
|
|
||||||
|
# Step 3: Append padding count
|
||||||
equal_char = self.equal_mapping[str(equal_count)]
|
equal_char = self.equal_mapping[str(equal_count)]
|
||||||
with_equal = f"{reversed_text}|{equal_char}"
|
with_equal = f"{reversed_text}|{equal_char}"
|
||||||
|
|
||||||
|
# Step 4: Dynamic key (long key) encryption
|
||||||
key_length_str = str(len(with_equal))
|
key_length_str = str(len(with_equal))
|
||||||
key_length_encoded = self._encode_digit(key_length_str)
|
key_length_encoded = self._encode_digit(key_length_str)
|
||||||
|
|
||||||
dynamic_key = self._get_dynamic_key(len(with_equal))
|
dynamic_key = self._get_dynamic_key(len(with_equal))
|
||||||
encrypted_by_dynamic = self._xor_encrypt_with_key(with_equal, dynamic_key)
|
encrypted_by_dynamic = self._xor_encrypt_with_key(with_equal, dynamic_key)
|
||||||
|
|
||||||
|
# Step 5: Final encryption with derived key
|
||||||
combined = f"{encrypted_by_dynamic}|{key_length_encoded}"
|
combined = f"{encrypted_by_dynamic}|{key_length_encoded}"
|
||||||
final_encrypted = self._xor_encrypt_with_final_key(combined, user_password)
|
final_encrypted = self._xor_encrypt_with_final_key(combined, user_password)
|
||||||
|
|
||||||
return final_encrypted
|
return final_encrypted
|
||||||
|
|
||||||
def decrypt(self, ciphertext, user_password):
|
def decrypt(self, ciphertext, user_password):
|
||||||
|
"""
|
||||||
|
Decrypt ciphertext with the given password.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The original plaintext, or an error message on failure.
|
||||||
|
"""
|
||||||
if not self.keys_loaded:
|
if not self.keys_loaded:
|
||||||
return "❌ 解密失败"
|
return "❌ Decryption failed"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# Step 1: Decrypt with derived final key
|
||||||
combined = self._xor_decrypt_with_final_key(ciphertext, user_password)
|
combined = self._xor_decrypt_with_final_key(ciphertext, user_password)
|
||||||
if combined is None:
|
if combined is None:
|
||||||
return "❌ 解密失败"
|
return "❌ Decryption failed"
|
||||||
|
|
||||||
|
# Step 2: Extract hex data and length indicator
|
||||||
if '|' in combined:
|
if '|' in combined:
|
||||||
parts = combined.split('|')
|
parts = combined.split('|')
|
||||||
if len(parts) >= 2:
|
if len(parts) >= 2:
|
||||||
@@ -499,6 +588,7 @@ class EncryptionSystem:
|
|||||||
hex_data = combined
|
hex_data = combined
|
||||||
key_length_encoded = 'g'
|
key_length_encoded = 'g'
|
||||||
|
|
||||||
|
# Step 3: Decode length and get dynamic key
|
||||||
key_length_str = self._decode_digit(key_length_encoded)
|
key_length_str = self._decode_digit(key_length_encoded)
|
||||||
try:
|
try:
|
||||||
key_length = int(key_length_str)
|
key_length = int(key_length_str)
|
||||||
@@ -506,10 +596,13 @@ class EncryptionSystem:
|
|||||||
key_length = 16
|
key_length = 16
|
||||||
|
|
||||||
dynamic_key = self._get_dynamic_key(key_length)
|
dynamic_key = self._get_dynamic_key(key_length)
|
||||||
|
|
||||||
|
# Step 4: Decrypt with dynamic key
|
||||||
xor_decrypted = self._xor_decrypt_with_key(hex_data, dynamic_key)
|
xor_decrypted = self._xor_decrypt_with_key(hex_data, dynamic_key)
|
||||||
if xor_decrypted is None:
|
if xor_decrypted is None:
|
||||||
return "❌ 解密失败"
|
return "❌ Decryption failed"
|
||||||
|
|
||||||
|
# Step 5: Extract main data and padding count
|
||||||
if '|' in xor_decrypted:
|
if '|' in xor_decrypted:
|
||||||
main_part, equal_char = xor_decrypted.split('|')
|
main_part, equal_char = xor_decrypted.split('|')
|
||||||
equal_count = int(self.equal_reverse.get(equal_char, '0'))
|
equal_count = int(self.equal_reverse.get(equal_char, '0'))
|
||||||
@@ -517,192 +610,211 @@ class EncryptionSystem:
|
|||||||
main_part = xor_decrypted
|
main_part = xor_decrypted
|
||||||
equal_count = 0
|
equal_count = 0
|
||||||
|
|
||||||
|
# Step 6: Reverse, flip, substitute
|
||||||
reversed_text = main_part[::-1]
|
reversed_text = main_part[::-1]
|
||||||
flipped = self._apply_flip(reversed_text)
|
flipped = self._apply_flip(reversed_text)
|
||||||
sub = self._substitute_letters(flipped, self.decrypt_map)
|
sub = self._substitute_letters(flipped, self.decrypt_map)
|
||||||
|
|
||||||
|
# Step 7: Restore Base64 special chars and padding
|
||||||
for old, new in self.special_decrypt.items():
|
for old, new in self.special_decrypt.items():
|
||||||
sub = sub.replace(old, new)
|
sub = sub.replace(old, new)
|
||||||
|
|
||||||
b64_with_equal = sub + '=' * equal_count
|
b64_with_equal = sub + '=' * equal_count
|
||||||
|
|
||||||
if len(b64_with_equal) % 4 != 0:
|
if len(b64_with_equal) % 4 != 0:
|
||||||
return "❌ 解密失败"
|
return "❌ Decryption failed"
|
||||||
|
|
||||||
|
# Step 8: Base64 decode
|
||||||
decoded = base64.b64decode(b64_with_equal.encode('utf-8')).decode('utf-8')
|
decoded = base64.b64decode(b64_with_equal.encode('utf-8')).decode('utf-8')
|
||||||
return decoded
|
return decoded
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return "❌ 解密失败"
|
return "❌ Decryption failed"
|
||||||
|
|
||||||
def print_keys(self):
|
def print_keys(self):
|
||||||
|
"""Display information about the currently loaded keys."""
|
||||||
if not self.keys_loaded:
|
if not self.keys_loaded:
|
||||||
print("❌ 未加载密钥")
|
print("❌ Keys not loaded")
|
||||||
return
|
return
|
||||||
|
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("密钥信息")
|
print("Key Information")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print(f"密钥文件: {self.key_file}")
|
print(f"Key file: {self.key_file}")
|
||||||
print(f"大写映射表: {self.upper_mapping}")
|
print(f"Uppercase mapping: {self.upper_mapping}")
|
||||||
print(f"小写映射表: {self.lower_mapping}")
|
print(f"Lowercase mapping: {self.lower_mapping}")
|
||||||
print(f"翻转模式: {self.flip_pattern}")
|
print(f"Flip pattern: {self.flip_pattern}")
|
||||||
print(f"长密钥长度: {len(self.long_key)} 位")
|
print(f"Long key length: {len(self.long_key)} bits")
|
||||||
print(f"短密钥长度: {len(self.short_key)} 位")
|
print(f"Short key length: {len(self.short_key)} bits")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
# CLI Entry Point
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
"""Command-line interface for the encryption system."""
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
print("欢迎使用加密系统")
|
print("Welcome to the Encryption System")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
|
|
||||||
crypto = None
|
crypto = None
|
||||||
key_password = None
|
key_password = None
|
||||||
|
|
||||||
|
# Try loading default key file
|
||||||
if os.path.exists("encryption.key"):
|
if os.path.exists("encryption.key"):
|
||||||
key_password = input("请输入默认密钥文件 (encryption.key) 的密码: ")
|
key_password = input("Enter password for default key file (encryption.key): ")
|
||||||
crypto = EncryptionSystem("encryption.key", key_password)
|
crypto = EncryptionSystem("encryption.key", key_password)
|
||||||
if not crypto.keys_loaded:
|
if not crypto.keys_loaded:
|
||||||
print("❌ 加载失败")
|
print("❌ Loading failed")
|
||||||
crypto = None
|
crypto = None
|
||||||
else:
|
else:
|
||||||
print("\n未找到默认密钥文件,请先生成")
|
print("\nDefault key file not found. Please generate one first.")
|
||||||
choice = input("是否生成默认密钥文件?(y/n): ").strip().lower()
|
choice = input("Generate default key file? (y/n): ").strip().lower()
|
||||||
if choice == 'y':
|
if choice == 'y':
|
||||||
crypto = EncryptionSystem()
|
crypto = EncryptionSystem()
|
||||||
key_password = crypto.generate_keys("encryption.key")
|
result = crypto.generate_keys("encryption.key")
|
||||||
if key_password is None:
|
if result is None:
|
||||||
print("❌ 生成失败")
|
print("❌ Generation failed")
|
||||||
crypto = None
|
crypto = None
|
||||||
else:
|
else:
|
||||||
print("⚠️ 请使用模式4或5指定密钥文件,或模式6生成新密钥")
|
print("⚠️ Use options 4, 5, or 6 to manage key files manually.")
|
||||||
|
|
||||||
|
# Main interaction loop
|
||||||
while True:
|
while True:
|
||||||
print("\n请选择操作:")
|
print("\nSelect an option:")
|
||||||
print("1. 使用默认密钥加密")
|
print("1. Encrypt with default key")
|
||||||
print("2. 使用默认密钥解密")
|
print("2. Decrypt with default key")
|
||||||
print("3. 生成新密钥(覆盖默认)")
|
print("3. Generate new key (overwrite default)")
|
||||||
print("4. 使用指定密钥文件加密")
|
print("4. Encrypt with custom key file")
|
||||||
print("5. 使用指定密钥文件解密")
|
print("5. Decrypt with custom key file")
|
||||||
print("6. 生成密钥并保存到当前文件夹")
|
print("6. Generate key and save to current folder")
|
||||||
print("7. 查看当前密钥信息")
|
print("7. View current key info")
|
||||||
print("8. 退出")
|
print("8. Exit")
|
||||||
|
|
||||||
choice = input("\n请选择操作 (1-8): ").strip()
|
choice = input("\nEnter choice (1-8): ").strip()
|
||||||
|
|
||||||
if choice == '1':
|
if choice == '1':
|
||||||
|
# Encrypt with default key
|
||||||
if crypto is None or not crypto.keys_loaded:
|
if crypto is None or not crypto.keys_loaded:
|
||||||
if os.path.exists("encryption.key"):
|
if os.path.exists("encryption.key"):
|
||||||
if key_password is None:
|
if key_password is None:
|
||||||
key_password = input("请输入默认密钥文件密码: ")
|
key_password = input("Enter default key file password: ")
|
||||||
crypto = EncryptionSystem("encryption.key", key_password)
|
crypto = EncryptionSystem("encryption.key", key_password)
|
||||||
if not crypto.keys_loaded:
|
if not crypto.keys_loaded:
|
||||||
print("❌ 加载失败")
|
print("❌ Loading failed")
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
print("❌ 密钥文件不存在")
|
print("❌ Key file not found")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
password = input("请输入加密密码: ")
|
password = input("Enter encryption password: ")
|
||||||
text = input("请输入要加密的文本: ")
|
text = input("Enter text to encrypt: ")
|
||||||
if text and password:
|
if text and password:
|
||||||
encrypted = crypto.encrypt(text, password)
|
encrypted = crypto.encrypt(text, password)
|
||||||
print(f"\n✅ 加密结果: {encrypted}")
|
print(f"\n✅ Encrypted result: {encrypted}")
|
||||||
|
|
||||||
elif choice == '2':
|
elif choice == '2':
|
||||||
|
# Decrypt with default key
|
||||||
if crypto is None or not crypto.keys_loaded:
|
if crypto is None or not crypto.keys_loaded:
|
||||||
if os.path.exists("encryption.key"):
|
if os.path.exists("encryption.key"):
|
||||||
if key_password is None:
|
if key_password is None:
|
||||||
key_password = input("请输入默认密钥文件密码: ")
|
key_password = input("Enter default key file password: ")
|
||||||
crypto = EncryptionSystem("encryption.key", key_password)
|
crypto = EncryptionSystem("encryption.key", key_password)
|
||||||
if not crypto.keys_loaded:
|
if not crypto.keys_loaded:
|
||||||
print("❌ 加载失败")
|
print("❌ Loading failed")
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
print("❌ 密钥文件不存在")
|
print("❌ Key file not found")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
password = input("请输入加密密码: ")
|
password = input("Enter encryption password: ")
|
||||||
text = input("请输入要解密的密文: ")
|
text = input("Enter ciphertext to decrypt: ")
|
||||||
if text and password:
|
if text and password:
|
||||||
decrypted = crypto.decrypt(text, password)
|
decrypted = crypto.decrypt(text, password)
|
||||||
print(f"\n✅ 解密结果: {decrypted}")
|
print(f"\n✅ Decrypted result: {decrypted}")
|
||||||
|
|
||||||
elif choice == '3':
|
elif choice == '3':
|
||||||
|
# Generate and overwrite default key
|
||||||
crypto = EncryptionSystem()
|
crypto = EncryptionSystem()
|
||||||
key_password = crypto.generate_keys("encryption.key")
|
result = crypto.generate_keys("encryption.key")
|
||||||
if key_password is None:
|
if result is None:
|
||||||
print("❌ 生成失败")
|
print("❌ Generation failed")
|
||||||
else:
|
else:
|
||||||
print("✅ 默认密钥已更新")
|
print("✅ Default key updated")
|
||||||
|
|
||||||
elif choice == '4':
|
elif choice == '4':
|
||||||
key_file = input("请输入密钥文件路径: ")
|
# Encrypt with custom key file
|
||||||
|
key_file = input("Enter key file path: ")
|
||||||
if not os.path.exists(key_file):
|
if not os.path.exists(key_file):
|
||||||
print(f"❌ 文件不存在")
|
print(f"❌ File not found: {key_file}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
kp = input(f"请输入密钥文件密码: ")
|
kp = input("Enter key file password: ")
|
||||||
crypto = EncryptionSystem(key_file, kp)
|
crypto = EncryptionSystem(key_file, kp)
|
||||||
if not crypto.keys_loaded:
|
if not crypto.keys_loaded:
|
||||||
print("❌ 加载失败")
|
print("❌ Loading failed")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
password = input("请输入加密密码: ")
|
password = input("Enter encryption password: ")
|
||||||
text = input("请输入要加密的文本: ")
|
text = input("Enter text to encrypt: ")
|
||||||
if text and password:
|
if text and password:
|
||||||
encrypted = crypto.encrypt(text, password)
|
encrypted = crypto.encrypt(text, password)
|
||||||
print(f"\n✅ 加密结果: {encrypted}")
|
print(f"\n✅ Encrypted result: {encrypted}")
|
||||||
|
|
||||||
elif choice == '5':
|
elif choice == '5':
|
||||||
key_file = input("请输入密钥文件路径: ")
|
# Decrypt with custom key file
|
||||||
|
key_file = input("Enter key file path: ")
|
||||||
if not os.path.exists(key_file):
|
if not os.path.exists(key_file):
|
||||||
print(f"❌ 文件不存在")
|
print(f"❌ File not found: {key_file}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
kp = input(f"请输入密钥文件密码: ")
|
kp = input("Enter key file password: ")
|
||||||
crypto = EncryptionSystem(key_file, kp)
|
crypto = EncryptionSystem(key_file, kp)
|
||||||
if not crypto.keys_loaded:
|
if not crypto.keys_loaded:
|
||||||
print("❌ 加载失败")
|
print("❌ Loading failed")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
password = input("请输入加密密码: ")
|
password = input("Enter encryption password: ")
|
||||||
text = input("请输入要解密的密文: ")
|
text = input("Enter ciphertext to decrypt: ")
|
||||||
if text and password:
|
if text and password:
|
||||||
decrypted = crypto.decrypt(text, password)
|
decrypted = crypto.decrypt(text, password)
|
||||||
print(f"\n✅ 解密结果: {decrypted}")
|
print(f"\n✅ Decrypted result: {decrypted}")
|
||||||
|
|
||||||
elif choice == '6':
|
elif choice == '6':
|
||||||
|
# Generate new key with timestamp
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
filename = f"key_{timestamp}.key"
|
filename = f"key_{timestamp}.key"
|
||||||
crypto = EncryptionSystem()
|
crypto = EncryptionSystem()
|
||||||
kp = crypto.generate_keys(filename)
|
result = crypto.generate_keys(filename)
|
||||||
if kp is None:
|
if result is None:
|
||||||
print("❌ 生成失败")
|
print("❌ Generation failed")
|
||||||
else:
|
else:
|
||||||
print(f"✅ 密钥已保存到: {filename}")
|
print(f"✅ Key saved to: {filename}")
|
||||||
|
|
||||||
elif choice == '7':
|
elif choice == '7':
|
||||||
|
# Show key info
|
||||||
if crypto is None or not crypto.keys_loaded:
|
if crypto is None or not crypto.keys_loaded:
|
||||||
if os.path.exists("encryption.key"):
|
if os.path.exists("encryption.key"):
|
||||||
if key_password is None:
|
if key_password is None:
|
||||||
key_password = input("请输入默认密钥文件密码: ")
|
key_password = input("Enter default key file password: ")
|
||||||
crypto = EncryptionSystem("encryption.key", key_password)
|
crypto = EncryptionSystem("encryption.key", key_password)
|
||||||
if not crypto.keys_loaded:
|
if not crypto.keys_loaded:
|
||||||
print("❌ 加载失败")
|
print("❌ Loading failed")
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
print("❌ 未加载密钥")
|
print("❌ Keys not loaded")
|
||||||
continue
|
continue
|
||||||
crypto.print_keys()
|
crypto.print_keys()
|
||||||
|
|
||||||
elif choice == '8':
|
elif choice == '8':
|
||||||
print("感谢使用,再见!")
|
print("Goodbye!")
|
||||||
break
|
break
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("❌ 无效选择")
|
print("❌ Invalid choice")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
Reference in New Issue
Block a user