Metadata-Version: 2.4
Name: shisuo
Version: 1.0.0
Summary: ShiSuo (诗锁): A cross-platform, poetry-based high-security encryption system.
Home-page: https://github.com/yourusername/shisuo
Author: Your Name
Author-email: your.email@example.com
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: pynacl>=1.5.0
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# 诗锁 (ShiSuo) 加密系统 - 最终文档

> 最后审核: 2026-07-11 17:42
> 状态: Phase 1 完成，三端跨平台验证通过

---

## 一、项目概述

个人专属加密系统，以中国古诗词(沁园春·雪)为密钥码表基础，
四层纵深防御，跨全平台兼容。

| 项 | 值 |
|----|-----|
| 使用者 | 仅本人 |
| 密钥形式 | 中国古诗词 (先经码表转换为hex字节) |
| 平台 | macOS/Linux/Windows/iOS/Android/浏览器/Node.js |
| 核心依赖 | libsodium (全平台统一) |
| 编码体系 | 8-bit 单字节，16进制，无字节序依赖 |

---

## 二、算法选型 (已验证)

| 功能 | 算法 | 理由 |
|------|------|------|
| KDF | Argon2id | memory-hard，抗GPU/ASIC |
| 对称加密 | **XSalsa20-Poly1305** | libsodium SecretBox原生方案，24字节nonce |
| 哈希/MAC | BLAKE2b | libsodium原生，快于SHA-3 |
| 密钥混合 | HMAC-SHA512 | 标准MAC |

> **坑点记录**: 原始设计文档写的是 XChaCha20-Poly1305，但 PyNaCl 的
> `nacl.secret.SecretBox` 实际使用的是 **XSalsa20-Poly1305**
> (即 libsodium 的 `crypto_secretbox`)。两者都使用 24 字节 nonce，
> 安全性等级相当。C 端的 `crypto_secretbox_easy` 和 JS 端的
> `crypto_secretbox_easy` 与 Python 端一致，三端已通过向量验证。
> **这不是 XChaCha20。**

---

## 三、诗锁码表

来源: 《沁园春·雪》全词(含标点)，按首次出现顺序提取。

- **总数**: 106 个唯一字符 (103 CJK + 3 标点)
- **编码范围**: 0x00 ~ 0x69，单字节，无字节序依赖
- **转义机制**: 0xFF + 4字节 Unicode 码点 (big-endian)，处理码表外字符
- **保留区间**: 0x6A ~ 0xFE 未使用

3个标点:
| 字符 | 编码 | Unicode |
|------|------|---------|
| ， | 0x04 | U+FF0C |
| 。 | 0x0C | U+3002 |
| ； | 0x15 | U+FF1B |

```
16x 矩阵 (row=高4位, col=低4位):

       .0  .1  .2  .3  .4  .5  .6  .7  .8  .9  .A  .B  .C  .D  .E  .F
  0.    北  国  风  光  ，  千  里  冰  封  万  雪  飘  。  望  长  城
  1.    内  外  惟  余  莽  ；  大  河  上  下  顿  失  滔  山  舞  银
  2.    蛇  原  驰  蜡  象  欲  与  天  公  试  比  高  须  晴  日  看
  3.    红  装  素  裹  分  妖  娆  江  如  此  多  娇  引  无  数  英
  4.    雄  竞  折  腰  惜  秦  皇  汉  武  略  输  文  采  唐  宗  宋
  5.    祖  稍  逊  骚  一  代  骄  成  吉  思  汗  只  识  弯  弓  射
  6.    雕  俱  往  矣  流  人  物  还  今  朝  --  --  --  --  --  --
```

---

## 四、架构: 四层防御 (经审核后的准确描述)

```
输入: 古诗词 + 明文
  |
  v
[Layer 0] 诗意炼化 - 码表转换 + BLAKE2b + HMAC-SHA512
  |
  v
[Layer 1] 密钥锻造 - Argon2id 内存硬化派生 (产出3把独立密钥)
  |
  v
[Layer 2] 乾坤挪移 - 密钥S-Box替换 + 块转置
  |
  v
[Layer 3] 双重封印 - 两次 XSalsa20-Poly1305 认证加密
  |
  v
[Layer 4] 龙印验封 - BLAKE2b-256 全局完整性校验
  |
  v
输出: 密文 (统一二进制格式)
```

### Layer 0: 诗意炼化 (实际实现)

```
输入: "北国风光，千里冰封，万里雪飘"
  |
  +-> 码表转换器 poem_to_codebook_bytes()
  |     每个字符查码表 -> 单字节 (0x00~0x69)
  |     码表外字符 -> 0xFF + 4字节Unicode码点
  |     产出: codebook_bytes (本例: 0001020304050607080409060A0B, 14字节)
  |
  +-> BLAKE2b-512(codebook_bytes, key=PERSONAL_PEPPER)
  |     PERSONAL_PEPPER = b"ShiSuo:TianYaGongCiRen:2026" (27字节)
  |     产出: poem_essence (64字节)
  |
  +-> HMAC-SHA512(
  |     key = poem_essence[0:32],
  |     msg = codebook_bytes || poem_essence
  |   )
  |
  输出: twisted_input (64字节)
```

> **坑点**: 原始设计是 "NFC标准化 -> UTF-8编码 -> BLAKE2b"，
> 后改为 "码表转换 -> BLAKE2b"。诗词原文永不以 UTF-8 直接参与密钥派生。
> 这一改动使得密钥材料与码表强绑定，增加了攻击复杂度。

### Layer 1: 密钥锻造

```
salt = 随机 16 字节 (每次加密独立生成)

master_key = Argon2id(
    password  = twisted_input (64字节),
    salt      = salt,
    opslimit  = 级别相关,
    memlimit  = 级别相关,
    output    = 96 字节 (0x60)
)

密钥分割:
  key_transform = master_key[0x00:0x20]   // Layer 2 置换密钥
  key_inner     = master_key[0x20:0x40]   // 内层加密密钥
  key_outer     = master_key[0x40:0x60]   // 外层加密密钥
```

安全级别:

| 级别 | opslimit | memlimit | 存储编码(ops,mem) | 适用场景 |
|------|----------|----------|-------------------|---------|
| fast | 2 | 64 MB (2^26) | 0x02, 0x1A | 开发测试 |
| normal | 4 | 256 MB (2^28) | 0x04, 0x1C | 日常使用 |
| paranoid | 6 | 1 GB (2^30) | 0x06, 0x1E | 高安全需求 |

### Layer 2: 乾坤挪移

```
步骤1: S-Box 生成
  table_fingerprint = 码表106字符的Unicode码点序列 (各4字节big-endian, 共424字节)
  seed = BLAKE2b-256(table_fingerprint || key_transform)  // 无key参数
  通过 Fisher-Yates 洗牌 + BLAKE2b链式RNG 生成 256 字节 S-Box

步骤2: 字节替换
  每字节通过 S-Box 查表替换

步骤3: 块转置
  seed = BLAKE2b-256(key_transform || b"block_perm")
  Fisher-Yates 洗牌确定 16 字节块重排顺序
  尾部不足16字节的块保持原位
```

> **坑点**: 原始设计写的是 "使用 key_transform 的后16字节决定块重排顺序"，
> 实际代码用 BLAKE2b(key_transform + b"block_perm") 做 Fisher-Yates 洗牌。
> 这比直接截取字节更安全(均匀分布)。

### Layer 3: 双重封印

```
nonce1 = 随机 24 字节
nonce2 = 随机 24 字节

// 内层: XSalsa20-Poly1305 (SecretBox)
ct1 = SecretBox(key_inner).encrypt(obfuscated_data, nonce1)
// ct1 包含 16字节 Poly1305 tag

// 外层: XSalsa20-Poly1305 (SecretBox)
ct2 = SecretBox(key_outer).encrypt(ct1, nonce2)
// ct2 再加 16字节 Poly1305 tag
```

> **坑点**: SecretBox 不支持 AAD (附加认证数据)。
> 原始设计写了 `aad=header_bytes` 和 `aad=nonce1`，
> 但实际代码未使用 AAD。cipher.py 中有一段已废弃的 Aead 尝试代码。
> 全局 MAC (Layer 4) 覆盖了 header 完整性保护。

### Layer 4: 龙印验封

```
mac_key = BLAKE2b-256(key_inner || key_outer, key=key_transform)
mac = BLAKE2b-256(header || ciphertext, key=mac_key)
```

---

## 五、密文二进制格式

```
偏移(hex)  大小(hex)  字段
0x00       0x06       Magic "SHISUO" (ASCII)
0x06       0x01       Version: 0x01
0x07       0x01       Argon2 opslimit (原值)
0x08       0x01       Argon2 memlimit (2的幂次编码)
0x09       0x10       Salt (16 bytes)
0x19       0x18       Nonce1 (24 bytes, 内层加密)
0x31       0x18       Nonce2 (24 bytes, 外层加密)
0x49       N          双重加密密文体 (含2个Poly1305 tag, 各0x10)
0x49+N     0x20       BLAKE2b-256 全局MAC (32 bytes)

固定开销: 0x49 + 0x20 + 0x20 = 0x89 (137 bytes)
  = 头部73 + 两个Poly1305 tag 32 + 全局MAC 32
```

---

## 六、踩坑记录

| 坑 | 描述 | 解决方案 |
|----|------|---------|
| XChaCha20 vs XSalsa20 | PyNaCl SecretBox用XSalsa20不是XChaCha20 | 统一认知为XSalsa20，三端代码已一致 |
| AAD不可用 | SecretBox不支持AAD参数 | 靠Layer 4全局MAC保护header完整性 |
| 码表链路重构 | 原始方案诗词直接UTF-8进KDF | 改为先经码表转换再进KDF |
| libsodium-wrappers缺HMAC | JS基础版无hmacsha512 API | 改用libsodium-wrappers-sumo |
| ESM导入问题 | libsodium-wrappers的ESM路径不存在 | 用createRequire做CJS导入 |
| brew路径 | macOS编译C库找不到sodium.h | 加 -I/opt/homebrew/include -L/opt/homebrew/lib |
| cipher.py死代码 | 残留Aead尝试代码(47-50行) | 已知问题，不影响功能 |

---

## 七、文件结构与功能说明

项目根目录: `/Users/t/bdesuanfa/`

### Python 参考实现 (`shisuo/`)

| 文件 | 功能 | 关键函数/类 |
|------|------|------------|
| `__init__.py` | 包入口 | - |
| `__main__.py` | `python -m shisuo` 入口 | - |
| `codebook.py` | 码表生成器 | `build_code_table(poem)` -> 106字符列表 |
| | | `export_table_dict(table)` -> 双向映射字典 |
| | | `print_hex_table(table)` -> 打印完整码表 |
| `passphrase.py` | Layer 0 诗意炼化 | `poem_to_codebook_bytes(poem)` -> 码表hex字节 |
| | | `compute_poem_essence(cb_bytes)` -> 64字节指纹 |
| | | `twist_passphrase(poem)` -> 64字节密钥材料 |
| `kdf.py` | Layer 1 密钥锻造 | `derive_keys(twisted, salt, level)` -> 3把密钥 |
| | | `encode_argon2_params()` / `decode_argon2_params()` |
| `transform.py` | Layer 2 S-Box+块转置 | `generate_sbox(key)` -> (sbox, inv_sbox) |
| | | `transform(data, key)` / `inverse_transform(data, key)` |
| | | `encode_with_codebook(text)` / `decode_with_codebook(data)` |
| `cipher.py` | Layer 3+4 双重加密+MAC | `double_encrypt(data, ki, ko, header)` -> (n1, n2, ct) |
| | | `double_decrypt(ct, n1, n2, ki, ko)` -> plaintext |
| | | `compute_mac()` / `verify_mac()` |
| `format.py` | 密文二进制格式 | `ShiSuoHeader` 类 |
| | | `serialize(header, ct, mac)` / `deserialize(data)` |
| | | `hex_dump(data)` |
| `core.py` | 加解密主流程编排 | `encrypt(plaintext, poem, level)` -> 密文bytes |
| | | `decrypt(ciphertext, poem)` -> 明文bytes |
| `cli.py` | 命令行工具 | encrypt/decrypt/table/info/vectors 子命令 |

### C 跨平台核心库 (`c/`)

| 文件 | 功能 |
|------|------|
| `shisuo.h` | 公共API头文件 (常量全hex) |
| `shisuo.c` | 完整C99实现 (含码表转换器) |
| `codebook_data.h` | 106个Unicode码点常量数组 |
| `test_shisuo.c` | C端测试 (往返/错误拒绝/篡改检测) |
| `verify_vectors.c` | 跨平台向量验证 (对照Python参考值) |
| `Makefile` | 构建脚本 (lib/static/test) |
| `libshisuo.dylib` | macOS动态库 (35KB) |
| `libshisuo.a` | 静态库 (10KB) |

C API:
```c
int shisuo_init(void);
int shisuo_encrypt(uint8_t *out, size_t *out_len,
                   const uint8_t *pt, size_t pt_len,
                   const char *poem, int level);
int shisuo_decrypt(uint8_t *out, size_t *out_len,
                   const uint8_t *ct, size_t ct_len,
                   const char *poem);
size_t shisuo_encrypted_len(size_t pt_len);
```

### JavaScript/WASM (`js/`)

| 文件 | 功能 |
|------|------|
| `shisuo.mjs` | ES Module实现 (依赖libsodium-wrappers-sumo) |
| `test.mjs` | 功能测试 |
| `verify_vectors.mjs` | 跨平台向量验证 |
| `package.json` | NPM配置 |

JS API:
```javascript
import { encrypt, decrypt, poemToCodebookBytes } from './shisuo.mjs';
const ct = await encrypt(plaintext_uint8array, poem_string, 'fast');
const pt = await decrypt(ct, poem_string);
```

### Swift 封装 (`swift/`)

| 文件 | 功能 |
|------|------|
| `ShiSuo.swift` | Swift封装 (通过FFI调用C库) |

Swift API:
```swift
let encrypted = try ShiSuo.encrypt(data: plainData, poem: "诗词", level: .fast)
let decrypted = try ShiSuo.decrypt(data: encrypted, poem: "诗词")
// 便利方法
let b64 = try ShiSuo.encryptString("明文", poem: "诗词")
let text = try ShiSuo.decryptString(b64, poem: "诗词")
```

### Kotlin 封装 (`kotlin/`)

| 文件 | 功能 |
|------|------|
| `ShiSuo.kt` | Kotlin封装 (JNI调用C库) |
| `shisuo_jni.c` | JNI桥接C代码 |

Kotlin API:
```kotlin
val encrypted = ShiSuo.encrypt(plainBytes, "诗词", ShiSuoLevel.FAST)
val decrypted = ShiSuo.decrypt(encrypted, "诗词")
// 便利方法
val b64 = ShiSuo.encryptString("明文", "诗词")
val text = ShiSuo.decryptString(b64, "诗词")
```

### 测试文件 (`tests/`)

| 文件 | 功能 |
|------|------|
| `test_shisuo.py` | Python完整测试套件 (7项测试) |
| `cross_platform_test.py` | 生成确定性跨平台向量 |
| `cross_platform_vectors.json` | 跨平台参考值 |
| `test_vectors.json` | 详细中间值向量 |
| `demo.py` | 端到端演示脚本 |
| `sample.bin` | 示例密文 |
| `sample.txt` | 示例明文 |

---

## 八、使用指南

### 8.1 Python (macOS/Linux/Windows)

**环境准备:**
```bash
cd /Users/t/bdesuanfa
pip install pynacl
```

**CLI 用法:**
```bash
# 查看码表
python3 -m shisuo table

# 加密文件 (交互式输入诗词)
python3 -m shisuo encrypt -i secret.txt -o secret.bin -l fast
python3 -m shisuo encrypt -i secret.txt -o secret.bin -l normal
python3 -m shisuo encrypt -i secret.txt -o secret.bin -l paranoid

# 解密文件
python3 -m shisuo decrypt -i secret.bin -o result.txt

# 查看密文信息 (不解密)
python3 -m shisuo info -i secret.bin
python3 -m shisuo info -i secret.bin --dump   # 含hex dump

# 生成测试向量
python3 -m shisuo vectors -o vectors.json
```

**代码调用:**
```python
from shisuo.core import encrypt, decrypt

# 加密
plaintext = b"secret data"
poem = "北国风光，千里冰封，万里雪飘"
ciphertext = encrypt(plaintext, poem, level="fast")

# 解密
result = decrypt(ciphertext, poem)
assert result == plaintext

# 码表转换
from shisuo.passphrase import poem_to_codebook_bytes
cb = poem_to_codebook_bytes("北国风光")
# -> bytes([0x00, 0x01, 0x02, 0x03])
```

**手动测试:**
```bash
# 运行全部测试
python3 tests/test_shisuo.py

# 端到端演示
python3 tests/demo.py

# 生成跨平台向量
python3 tests/cross_platform_test.py
```

### 8.2 C 库 (macOS/Linux/Windows)

**环境准备 (macOS):**
```bash
brew install libsodium
cd /Users/t/bdesuanfa/c
```

**编译:**
```bash
# 动态库
make lib CFLAGS="-O2 -Wall -std=c99 -I/opt/homebrew/include" \
         LDFLAGS="-L/opt/homebrew/lib -lsodium"

# 静态库
make static CFLAGS="-O2 -Wall -std=c99 -I/opt/homebrew/include -fPIC"

# 编译并运行测试
make test CFLAGS="-O2 -Wall -std=c99 -I/opt/homebrew/include" \
          LDFLAGS="-L/opt/homebrew/lib -lsodium"

# 输出:
#   libshisuo.dylib  (macOS动态库)
#   libshisuo.a      (静态库)
#   test_shisuo      (测试程序)
```

**Linux 编译:**
```bash
sudo apt install libsodium-dev
make lib    # -> libshisuo.so
make test   # 不需要额外CFLAGS
```

**代码调用:**
```c
#include "shisuo.h"

int main() {
    shisuo_init();

    const uint8_t pt[] = "secret";
    size_t pt_len = 6;
    size_t ct_cap = shisuo_encrypted_len(pt_len);
    uint8_t *ct = malloc(ct_cap);
    size_t ct_len;

    // 加密 (poem是UTF-8字符串)
    shisuo_encrypt(ct, &ct_len, pt, pt_len,
                   "北国风光，千里冰封", SHISUO_LEVEL_FAST);

    // 解密
    uint8_t *out = malloc(ct_len);
    size_t out_len;
    int rc = shisuo_decrypt(out, &out_len, ct, ct_len,
                            "北国风光，千里冰封");
    // rc == SHISUO_OK (0) 表示成功

    free(ct); free(out);
}
```

**手动测试:**
```bash
cd /Users/t/bdesuanfa/c
./test_shisuo          # 加解密往返 + 错误拒绝 + 篡改检测
./verify_vectors       # 对照Python参考向量
```

### 8.3 JavaScript/Node.js

**环境准备:**
```bash
cd /Users/t/bdesuanfa/js
npm install
```

**代码调用:**
```javascript
import { encrypt, decrypt, poemToCodebookBytes } from './shisuo.mjs';

// 加密
const pt = new TextEncoder().encode('secret data');
const ct = await encrypt(pt, '北国风光，千里冰封', 'fast');

// 解密
const result = await decrypt(ct, '北国风光，千里冰封');
const text = new TextDecoder().decode(result);

// 码表转换
const cb = poemToCodebookBytes('北国风光');
// -> Uint8Array([0x00, 0x01, 0x02, 0x03])
```

**手动测试:**
```bash
cd /Users/t/bdesuanfa/js
node test.mjs              # 功能测试
node verify_vectors.mjs    # 跨平台向量验证
```

### 8.4 iOS (Swift)

**集成步骤:**
1. 编译C静态库: `cd c/ && make static` -> `libshisuo.a`
2. 在Xcode中添加 `libshisuo.a` 和 `libsodium.a` 到 Link Binary With Libraries
3. 创建 Bridging Header: `#include "shisuo.h"`
4. 将 `ShiSuo.swift` 加入项目

**代码调用:**
```swift
import Foundation

do {
    let data = "secret".data(using: .utf8)!
    let encrypted = try ShiSuo.encrypt(data: data, poem: "北国风光", level: .fast)
    let decrypted = try ShiSuo.decrypt(data: encrypted, poem: "北国风光")
    let result = String(data: decrypted, encoding: .utf8)!
} catch {
    print("Error: \(error)")
}
```

### 8.5 Android (Kotlin)

**集成步骤:**
1. 在 `app/build.gradle` 中配置 CMake:
   ```
   externalNativeBuild { cmake { path "CMakeLists.txt" } }
   ```
2. CMakeLists.txt 中链接 shisuo.c + libsodium
3. 将 `ShiSuo.kt` 加入 `com.shisuo` 包
4. 将 `shisuo_jni.c` 加入 native sources

**代码调用:**
```kotlin
val data = "secret".toByteArray()
val encrypted = ShiSuo.encrypt(data, "北国风光", ShiSuoLevel.FAST)
val decrypted = ShiSuo.decrypt(encrypted, "北国风光")
val result = String(decrypted)
```

---

## 九、跨平台验证结果

使用固定输入 "北国风光，千里冰封，万里雪飘" 验证三端中间值:

```
码表编码:  0001020304050607080409060A0B (14 bytes)
诗词指纹:  7B8C805D25EB226B8D93180CF5CE6E5D
           1F79C179122C606842BF1FFEE32E66D6
           A3133CE975945295E552491A22BE2799
           82D315C5704A1689D28D50A0318442E8
密钥材料:  8B2A50F974A97A701D653CE669D700F7
           6CC47319E7A98869BD136611E452FD30
           1D4F5D066A020E8EF8040762FDE8E719
           411D5737EA15C1FE7F08754FE144690D
```

| 平台 | 码表 | 指纹 | 密钥 | 加解密 | 错误拒绝 | 篡改检测 |
|------|------|------|------|--------|---------|---------|
| Python | 一致 | 一致 | 一致 | PASS | PASS | PASS |
| C | 一致 | 一致 | 一致 | PASS | PASS | PASS |
| JavaScript | 一致 | 一致 | 一致 | PASS | PASS | PASS |

---

## 十、安全性分析

| 攻击方式 | 防御 |
|----------|------|
| 暴力破解 | Argon2id内存硬化 (64MB~1GB) |
| 彩虹表 | 随机salt + 个人pepper |
| 已知明文 | 双重加密 + 自定义S-Box层 |
| 密文篡改 | 三层MAC (2x Poly1305 + BLAKE2b全局) |
| 侧信道 | XSalsa20是常数时间实现 |
| 量子计算 | 对称加密，Grover仅减半密钥长度(128位仍安全) |

**密钥安全建议:**
- 使用冷门诗词或自创诗句
- 已知诗词约5万首，单机全遍历需 5万 × ~0.3s(fast) ≈ 4小时
- 用 normal/paranoid 级别可大幅提升遍历代价
