pike00/coldkey
GitHub: pike00/coldkey
coldkey 为 age 加密用户提供后量子密钥生成和纸质备份解决方案,解决私钥丢失导致数据永久丢失的问题。
Stars: 64 | Forks: 1
# 冷密钥
[](https://github.com/pike00/coldkey/actions/workflows/ci.yml)
[](https://github.com/pike00/coldkey/releases/latest)
[](https://go.dev/)
[](LICENSE)
**您的 age 加密密钥距离永久丢失仅一步之遥。** 如果您使用 [age](https://age-encryption.org/) 或 [sops](https://github.com/getsops/sops) 加密机密数据,那么丢失私钥就意味着永远失去所有受其保护的数据。
coldkey 生成 [后量子(ML-KEM-768 + X25519)](https://words.filippo.io/post-quantum-age/) age 密钥,并生成带二维码的单页可打印 HTML 备份。将其打印出来,覆膜保存,放入防火保险箱。即使所有数字副本都消失,您的机密数据也能幸存。
[](https://asciinema.org/a/MitZvLXcwYdBXkeF)

## 快速开始
```
# 安装 — Homebrew (macOS/Linux)
brew install --cask pike00/tap/coldkey
# 或使用 Go
go install github.com/pike00/coldkey/cmd/coldkey@latest
# 生成密钥与纸质备份
coldkey generate -o ~/.config/sops/age/keys.txt
```
关于密钥生成期间的纵深防御,请参阅下方的[强化模式(Docker)](#hardened-mode-docker)。
## 命令
### `coldkey`(无参数)— 交互模式
显示菜单以生成新密钥或根据现有密钥创建备份。在覆盖文件前会提示文件路径并要求确认。
### `coldkey generate`
生成一个新的后量子 age 密钥对。
```
coldkey generate [flags]
-o PATH Key file output path (default: stdout)
-f Overwrite existing file
--no-backup Skip HTML backup generation
```
### `coldkey backup`
从现有密钥文件创建可打印的 HTML 纸质备份。
```
coldkey backup [flags] KEYFILE
-o PATH HTML output path (default: KEYFILE-backup.html)
```
### `coldkey version`
打印版本字符串。
## 安全模型
| 层级 | 措施 |
|-------|---------|
| 内存 | `mlockall(MCL_CURRENT\|MCL_FUTURE)` 防止密钥材料被交换到磁盘 |
| 文件 | 以 `0600` 权限写入,执行 fsync;临时文件已被安全擦除(3 次覆写) |
| 进程 | 机密数据仅通过 stdin/文件传递,绝不作为进程参数 |
| 容器 | `--network none --read-only --cap-drop ALL --security-opt no-new-privileges:true` |
| 镜像 | `distroless/static:nonroot` — 无 shell,非 root UID 65534 |
| 内存清零 | 在垃圾回收前对密钥缓冲区尽力执行 `secure.Zero()`(参见[限制](#limitations)) |
### 强化模式(Docker)
可选的 distroless Docker 镜像在网络隔离、只读根文件系统和移除所有 Linux 能力的环境下运行密钥生成。请注意,生成的 `keys.txt` 文件会写入主机挂载的卷,因此容器仅强化生成步骤——静态存储的密钥与其他文件一样位于主机上。
```
docker pull ghcr.io/pike00/coldkey:latest
# 交互式 — 生成密钥与纸质备份
just docker-run
# 备份现有密钥
just docker-backup ~/.config/sops/age/keys.txt
```
输出将写入 `./output/`。`just docker-run` 和 `just docker-backup` 命令会自动应用这些标志:
| 标志 | 目的 |
|------|---------|
| `--network none` | 无网络访问 — 密钥生成完全在本地进行 |
| `--read-only` | 不可变的根文件系统 |
| `--cap-drop ALL` | 移除所有 Linux 能力 |
| `--security-opt no-new-privileges:true` | 防止权限提升 |
| `--tmpfs /tmp:rw,noexec,nosuid,size=10m` | 基于 RAM 的临时目录 |
| `--cap-add IPC_LOCK` | (可选)启用 `mlockall` 以提供交换保护 |
## QR 码编码
PQ age 仅存储 32 字节的种子(而非扩展后的 ML-KEM-768 私钥),因此完整的 `keys.txt` 文件通常约 2,089 字节 — 可容纳在单个 QR 码中(版本 40,EC-L 级支持 2,953 字节)。
如果密钥文件超过单个 QR 码的容量,coldkey 会使用简单的分帧协议自动将其拆分到多个 QR 码中:
```
COLDKEY:/:
```
恢复:按顺序扫描所有 QR 码,去除每个码的 `COLDKEY:N/M:` 前缀,拼接后验证 SHA-256 校验和。
## 纸质备份内容
生成的 HTML 文档包含:
- 标题和元数据(日期、主机名、用户名、源文件路径)
- 等宽字体显示的原始密钥文本(用于手动转录)
- 带容量标注的 QR 码(一个或多个)
- 用于验证的 SHA-256 校验和
- 分步恢复说明
- 打印按钮(在打印媒体中隐藏)
## 恢复步骤
1. 扫描 QR 码(或手动输入原始密钥文本)
2. 保存至 `~/.config/sops/age/keys.txt`
3. 验证:`sha256sum keys.txt` 的输出应与打印的校验和匹配
4. 测试:`sops -d <任意 .sops 文件>`
## 构建
```
just build # Local binary
just docker # Docker image (ghcr.io/pike00/coldkey)
just test # Run tests
just ci # Full CI: vet → test → build → docker
```
## 限制
- **Go 的垃圾回收与安全内存**:Go 的垃圾回收器可能会在内存中复制对象,并且 Go 字符串是不可变的,这意味着作为 `string` 类型持有的密钥材料(例如来自 `identity.String()`)无法被可靠地覆写。`secure.Zero()` 使用 Go 内置的 `clear()` 函数来擦除 `[]byte` 缓冲区,但先前的字符串副本可能在堆中持续存在,直到被垃圾回收。`mlockall` 防止任何数据被交换到磁盘;这些措施共同提供纵深防御,但并非保证密钥材料立即从 RAM 中擦除的加密保证。
- **`mlockall` 需要 `CAP_IPC_LOCK`**:在 Docker 运行命令中添加 `--cap-add IPC_LOCK` 以获得完整的交换保护。若不添加,coldkey 会向 stderr 打印警告并继续执行。
- **QR 码扫描**:非常密集的 QR 码(版本 40)可能难以从纸质上扫描。原始密钥文本始终作为手动备用方案包含在内。
## 许可证
MIT
标签:Age加密, EVTX分析, Go语言, HTML生成, ML-KEM-768, ProjectDiscovery, QR码备份, Sops兼容, X25519, 冷存储, 加密工具, 后量子加密, 后量子密钥管理, 备份策略, 安全备份, 安全存储, 密码学, 密钥生成, 手动系统调用, 操作系统检测, 数据保护, 日志审计, 灾难恢复, 物理备份, 程序破解, 纸质备份, 请求拦截