Skip to content

Commit 01a860b

Browse files
author
Z User
committed
feat: 实现六层安全防御体系与云端配置拉取
- 新增 HardcodedConfig:所有敏感值以 XOR+LCG 流密码编码为 int[] 存储,JAR 中无明文泄露 - 新增 CloudConfigFetcher:云端配置拉取器,实现 HMAC 签名、GCM 解密、RSA-PSS 验证 - 新增 CloudCrypto:AES-256-GCM 解密与 RSA-PSS 签名验证 - 新增 SecureAesHelper:安全密钥还原(方法作用域内临时存在,完成后清零) - 新增 KeySharding:三碎片 XOR 密钥组装 - 新增 FragmentStore:Fragment3 本地存储(.minecraft/assets/indexes/vXXXX 伪装) - 新增 BuildInfo:Fragment1 伪装为构建签名 - 新增 ThemeConfig:Fragment2 伪装为主题色值数组 - 新增 CloudConfigException:云端配置异常类 - 修改 AppConfig:云端配置敏感值从 HardcodedConfig 读取,YAML 中仅保留 enabled 开关 - 修改 Main:Fragment3 自动初始化 + 密钥轮换检测(指纹不匹配时自动重新初始化) - 修改 CloudConfigFetcher:兼容 GCM auth tag 在响应头和响应体末尾两种格式 - 新增 README.md:项目文档、安全架构说明、配置指南、部署步骤
1 parent 8bd0638 commit 01a860b

12 files changed

Lines changed: 2582 additions & 41 deletions

File tree

README.md

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# Mcpatch2JavaClient
2+
3+
Mcpatch2JavaClient 是一个 Minecraft 客户端自动更新程序,支持从云端服务器拉取配置并管理客户端文件更新。项目实现了完整的六层安全防御体系,确保配置传输和存储的端到端安全。
4+
5+
## 功能特性
6+
7+
- **多云端协议支持**:mcpatch://(私有协议)、HTTP/HTTPS、WebDAV
8+
- **多地址故障转移**:可配置多个更新服务器地址,自动依次尝试
9+
- **六层安全防御**:RSA-PSS 签名验证、HMAC-SHA256 请求签名、密钥碎片化 XOR 还原、AES-256-GCM 加密传输、时间戳防重放、HTTPS 证书锁定
10+
- **云端配置管理**:从远程服务器拉取加密配置,支持「云端 → 缓存 → 本地」三级降级
11+
- **密钥自动轮换**:AES 密钥更换时自动检测并重新初始化本地碎片
12+
- **分片多线程下载**:大文件自动分片并行下载,智能线程数策略
13+
- **防盗链鉴权**:支持阿里云 ESA A 方案鉴权
14+
- **完全硬编码配置**:所有敏感值以 XOR+LCG 流密码编码存储在 JAR 中,无明文泄露风险
15+
16+
## 安全架构
17+
18+
```
19+
┌──────────────────────────────────────────────────────────────┐
20+
│ 六层安全防御体系 │
21+
├──────────────────────────────────────────────────────────────┤
22+
│ Layer 1 │ RSA-PSS 签名验证 │ 防篡改(动态获取公钥) │
23+
│ Layer 2 │ HMAC-SHA256 请求签名 │ 防直接调用(碎片化密钥) │
24+
│ Layer 3 │ 密钥碎片化 XOR 还原 │ 防逆向(3碎片分散存储) │
25+
│ Layer 4 │ AES-256-GCM 加密传输 │ 防窃听(GCM 认证加密) │
26+
│ Layer 5 │ 秒级时间戳防重放 │ 服务端校验 │
27+
│ Layer 6 │ HTTPS 证书锁定 │ 防中间人 │
28+
└──────────────────────────────────────────────────────────────┘
29+
```
30+
31+
### 密钥碎片化存储(Layer 3)
32+
33+
AES-256 密钥被拆分为 3 个 XOR 碎片,分散存储在不同位置,单独获取任意 2 个碎片无法还原密钥:
34+
35+
| 碎片 | 存储位置 | 伪装方式 |
36+
|------|----------|----------|
37+
| Fragment1 | `BuildInfo.BUILD_SIGNATURE` | 构建签名校验值 |
38+
| Fragment2 | `ThemeConfig.THEME_ACCENT_COLORS` | 界面主题色值数组 |
39+
| Fragment3 | `.minecraft/assets/indexes/vXXXX` | Minecraft 资源索引文件 |
40+
41+
还原公式:`AES Key = Fragment1 ⊕ Fragment2 ⊕ Fragment3`
42+
43+
HMAC-SHA256 签名密钥同样采用 3 碎片 XOR 方式,全部以 XOR+LCG 流密码编码存储在 `HardcodedConfig` 中。
44+
45+
### 加密通信流程
46+
47+
```
48+
Client Server
49+
│ │
50+
│ 1. GET /api/client?encrypt=true │
51+
│ Authorization: Bearer <api-key> │
52+
│ X-Timestamp: <unix-seconds> │
53+
│ X-Signature: HMAC-SHA256(timestamp+key+path, hmacSecret)
54+
│ ────────────────────────────────────────────► │
55+
│ │
56+
│ 2. 200 OK │
57+
│ X-Encryption-Algorithm: AES-256-GCM │
58+
│ X-Signature-Algorithm: RSA-SHA256-PSS │
59+
│ X-AES-IV: <12-byte-nonce-hex> │
60+
│ X-AES-Fingerprint: <sha256-of-aes-key> │
61+
│ X-Config-Signature: <RSA-PSS-base64> │
62+
│ Body: <ciphertext + 16-byte-GCM-auth-tag> │
63+
│ ◄──────────────────────────────────────────── │
64+
│ │
65+
│ 3. 验证 AES 指纹 → GCM 解密 → PSS 签名验证 │
66+
│ │
67+
```
68+
69+
### XOR+LCG 流密码编码
70+
71+
所有硬编码敏感字符串(API 地址、密钥、碎片等)均通过 XOR+LCG 流密码编码为 `int[]` 数组存储,运行时动态解码。JAR 反编译后无法直接搜索到任何明文配置值。
72+
73+
编码原理:
74+
1. 种子密钥:`key = K1 ^ K2`(两个 16 位常量异或)
75+
2. 流生成:`key = (key * 1103515245 + 12345) & 0x7FFFFFFF`(LCG 线性同余)
76+
3. 编码:`enc[i] = plain[i] ^ (key & 0xFF)`
77+
78+
## 项目结构
79+
80+
```
81+
src/main/java/com/github/balloonupdate/mcpatch/client/
82+
├── Main.java # 主入口,Fragment3 自动初始化与密钥轮换检测
83+
├── Work.java # 更新任务核心逻辑
84+
├── HardcodedConfig.java # 硬编码配置(XOR+LCG 编码,JAR 无明文泄露)
85+
├── CloudConfigFetcher.java # 云端配置拉取器(六层安全体系实现)
86+
├── CloudCrypto.java # 加解密工具(AES-256-GCM、RSA-PSS)
87+
├── SecureAesHelper.java # 安全加解密助手(密钥安全还原、HMAC 签名)
88+
├── KeySharding.java # 密钥碎片化 XOR 组装
89+
├── FragmentStore.java # Fragment3 本地存储管理
90+
├── BuildInfo.java # 构建信息(伪装存储 Fragment1)
91+
├── ThemeConfig.java # 主题配置(伪装存储 Fragment2)
92+
├── BalloonUpdateMain.java # 兼容入口
93+
├── ChunkedDownloader.java # 分片下载器
94+
├── ParallelDownloader.java # 并行下载器
95+
├── FocusManager.java # 焦点管理器
96+
├── config/
97+
│ └── AppConfig.java # 配置解析(敏感值从 HardcodedConfig 读取)
98+
├── exceptions/
99+
│ └── CloudConfigException.java # 云端配置异常
100+
├── logging/ # 日志系统
101+
├── network/ # 网络层
102+
├── ui/ # 界面
103+
└── utils/ # 工具类
104+
```
105+
106+
## 配置说明
107+
108+
### mcpatch.yml
109+
110+
所有配置项均有默认值,云控场景下仅需极简配置:
111+
112+
```yaml
113+
# 更新服务器地址
114+
urls:
115+
- mcpatch://127.0.0.1:6700
116+
117+
# 版本号文件路径
118+
version-file-path: version-label.txt
119+
120+
# 云端配置(敏感参数已硬编码,此处仅控制开关)
121+
cloud-config:
122+
enabled: true
123+
```
124+
125+
完整配置项参见 [mcpatch.yml 示例](mcpatch.yml)。
126+
127+
### 硬编码配置
128+
129+
云控场景下,所有敏感参数(API 地址、密钥、HMAC 碎片等)以 XOR+LCG 编码存储在 `HardcodedConfig.java` 中,部署时需替换为实际值的编码形式:
130+
131+
| 编号 | 配置项 | 说明 |
132+
|------|--------|------|
133+
| ε1 | URL 列表 | 更新服务器地址 |
134+
| ε4 | API URL | 云控 API 地址 |
135+
| ε5 | API Key | API 访问密钥 |
136+
| ε6 | 缓存文件 | 本地缓存路径 |
137+
| ε7 | HMAC FRAG1 | HMAC 签名碎片 1 |
138+
| ε8 | HMAC FRAG2 | HMAC 签名碎片 2 |
139+
| ε9 | HMAC FRAG3 | HMAC 签名碎片 3 |
140+
| ε10 | Auth API URL | 防盗链鉴权地址 |
141+
| ε12 | AES Key | AES-256 密钥(64 hex = 32 bytes) |
142+
143+
AES 密钥碎片也需同步更新:
144+
- `BuildInfo.BUILD_SIGNATURE` — Fragment1(64 hex 字符串)
145+
- `ThemeConfig.THEME_ACCENT_COLORS` — Fragment2(32 个 int 值)
146+
147+
Fragment3 会在首次启动时自动从 ε12 密钥计算生成,写入本地隐藏文件。
148+
149+
## 构建与部署
150+
151+
### 前置条件
152+
153+
- JDK 21+
154+
- Gradle 8.10+
155+
156+
### 构建
157+
158+
```bash
159+
./gradlew shadowJar
160+
```
161+
162+
产物位于 `build/libs/Mcpatch-0.0.0.jar`。
163+
164+
### 部署步骤
165+
166+
1. 在云控管理后台生成 API 密钥、HMAC 碎片、AES 密钥
167+
2. 使用编码工具将敏感值编码为 XOR+LCG `int[]` 数组
168+
3. 替换 `HardcodedConfig.java`、`BuildInfo.java`、`ThemeConfig.java` 中的编码值
169+
4. 将 AES 密钥导入服务端(POST `/api/security/rotate-aes`)
170+
5. 重新构建 JAR 并分发
171+
172+
## 服务端协议要求
173+
174+
客户端要求服务端支持以下 API 端点和响应格式:
175+
176+
| 端点 | 方法 | 说明 |
177+
|------|------|------|
178+
| `/api/client?encrypt=true` | GET | 获取加密配置 |
179+
| `/api/security/public-key` | GET | 获取 RSA 公钥 |
180+
| `/api/security/rotate-aes` | POST | 导入/轮换 AES 密钥 |
181+
182+
### 加密响应头
183+
184+
| 响应头 | 说明 |
185+
|--------|------|
186+
| `X-Encryption-Algorithm` | 固定 `AES-256-GCM` |
187+
| `X-Signature-Algorithm` | 固定 `RSA-SHA256-PSS` |
188+
| `X-AES-IV` | GCM Nonce(24 hex = 12 bytes) |
189+
| `X-AES-Fingerprint` | AES 密钥 SHA-256 指纹(冒号分隔或纯 hex) |
190+
| `X-Config-Signature` | RSA-PSS 签名(Base64 编码) |
191+
| `X-Config-Version` | 配置版本号 |
192+
193+
### 加密响应体格式
194+
195+
响应体为原始二进制:`ciphertext + auth_tag`(GCM 认证标签 16 字节追加在密文末尾)。
196+
197+
### HMAC 签名算法
198+
199+
```
200+
签名原文 = timestamp + apiKey + requestPath
201+
HMAC 密钥 = hex(frag1 ⊕ frag2 ⊕ frag3) 的 UTF-8 字节
202+
签名结果 = HMAC-SHA256(签名原文, hmacKey).hexdigest()
203+
```
204+
205+
## 降级策略
206+
207+
```
208+
云端服务器 ──成功──► 使用云端配置
209+
210+
失败
211+
212+
213+
本地缓存 ──有效──► 使用缓存配置(AES-256-GCM 解密)
214+
215+
过期/损坏
216+
217+
218+
fallback-local=true ──► 使用本地 mcpatch.yml 配置
219+
fallback-local=false ──► 抛出异常
220+
```
221+
222+
## 缓存文件格式
223+
224+
缓存文件采用二进制格式:
225+
226+
```
227+
┌────────────┬───────────────┬───────────────┬──────────────────┐
228+
│ Magic (4B) │ Nonce (12B) │ AuthTag (16B) │ Ciphertext (变长) │
229+
│ "MCGC" │ GCM Nonce │ GCM 认证标签 │ Base64密文数据 │
230+
└────────────┴───────────────┴───────────────┴──────────────────┘
231+
```
232+
233+
## 许可证
234+
235+
请参阅 [LICENSE](LICENSE) 文件。
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.github.balloonupdate.mcpatch.client;
2+
3+
/**
4+
* 构建信息类(伪装存储 AES 密钥 Fragment1)。
5+
* <p>
6+
* BUILD_SIGNATURE 看似用于构建产物完整性校验的签名值,
7+
* 实际上是 AES-256 密钥的第一个 XOR 碎片(32 字节 = 64 位十六进制)。
8+
* <p>
9+
* 经过 R8/ProGuard 混淆后,类名和字段名都会被缩短为无意义的标识符,
10+
* 进一步增加逆向分析难度。
11+
* <p>
12+
* 部署时需替换为管理面板生成的实际碎片值。
13+
*/
14+
public class BuildInfo {
15+
16+
/**
17+
* 看似构建签名的十六进制字符串,实际是 AES-256 密钥 Fragment1
18+
* <p>
19+
* 部署时替换为实际的 Fragment1 值(64 位 hex = 32 字节,适配 AES-256)
20+
*/
21+
public static final String BUILD_SIGNATURE =
22+
"a3f7c2e8b1d49560a3f7c2e8b1d49560a3f7c2e8b1d49560a3f7c2e8b1d49560";
23+
24+
/**
25+
* 构建版本号(伪装用)
26+
*/
27+
public static final String BUILD_VERSION = "2.1.0";
28+
29+
/**
30+
* 构建编号(伪装用)
31+
*/
32+
public static final int BUILD_NUMBER = 2147483647;
33+
34+
private BuildInfo() {
35+
// 禁止实例化
36+
}
37+
}

0 commit comments

Comments
 (0)