深色模式
凭据加密(KEK → DEK)
Reeve 的凭据库用 AES-256-GCM 加密,密钥(DEK)放在 OS 钥匙串。可选启用「主密码」后,DEK 再被 Argon2id KEK 包装一层 —— 磁盘 + keyring 同时被偷也开不了。
两种模式
模式 A:基础模式(无主密码)
凭据明文
│ AES-256-GCM (key = DEK)
▼
密文 → SQLite 数据库
DEK → 直接存 OS keyring(明文)- 安全等级:SSH 客户端业界平均水平
- 解锁:应用启动自动从 keyring 拉 DEK
- 攻击者拿到磁盘 + keyring 即可开
模式 B:有主密码(推荐)
用户主密码
│ Argon2id(m=19MiB, t=2, p=1, OWASP 推荐)
▼
KEK
│ AES-256-GCM 包装
▼
Wrapped DEK → 存 OS keyring
凭据明文
│ AES-256-GCM (key = DEK)
▼
密文 → SQLite 数据库- 安全等级:完整密码学屏障
- 解锁:应用启动 locked,等用户输主密码 → Argon2 派生 KEK → 解开 Wrapped DEK → DEK 进内存
- 攻击者拿到磁盘 + keyring 还需要爆破主密码,Argon2id 参数让单次尝试 ~2 秒,强密码下不可行
- 空闲超时锁定:DEK 缓存清零,需重新输主密码
AES-256-GCM 细节
每条加密字段(password_enc / privkey_enc / vault.value_enc 等):
base64( nonce[12] || ciphertext+tag[16] )- Nonce 每次加密随机生成(96 位)
- 认证标签 16 字节(防篡改)
- 用
aes-gcm-sivcrate(更抗 nonce 误用)
OS keyring 集成
| 平台 | 后端 |
|---|---|
| Windows | Credential Manager (wincred) |
| macOS | Keychain (security framework) |
| Linux | Secret Service(GNOME Keyring / KWallet)/ libsecret |
存储 key:com.agilefr.reeve.dek(基础模式)或 com.agilefr.reeve.wrapped-dek(主密码模式)。
Linux 注意
Linux 上如果没装 Secret Service(如 SSH 远端裸 server),Reeve 会回落到加密文件(<app data>/secrets.enc),用机器 ID 派生 key。安全等级低于桌面 GUI 环境,仅作 fallback。
主密码设置
启用主密码
- 点 设置主密码
- 输入主密码 + 确认
- 后端:
- 派生 KEK(Argon2id)
- 用 KEK 包装现有 DEK
- Wrapped DEK 覆盖 keyring
- 删除明文 DEK
- 完成 → 应用现在处于
locked-on-startup模式
修改主密码
需要先输入当前主密码 + 新主密码(×2):
- 旧主密码 → 派生旧 KEK → 解出 DEK
- 新主密码 → 派生新 KEK → 重新包装 DEK
- 覆盖 keyring
关闭主密码
需输入主密码:
- 派生 KEK → 解出 DEK
- 直接把明文 DEK 写 keyring(去掉 Wrapped 层)
- 回到基础模式
解锁流程
应用启动时:
1. 读 keyring,得到 DEK 或 Wrapped DEK
2. 如果是 DEK:直接进 unlocked
3. 如果是 Wrapped DEK:进 locked 屏幕
├── 显示 UnlockScreen(输密码框)
├── 用户输主密码
├── 派生 KEK,尝试解开 Wrapped DEK
├── 成功:DEK 进内存,unlocked
└── 失败:限流(3 次错误锁 10s,10 次错误锁 5min)锁定时哪些操作受影响
| 操作 | 锁定时行为 |
|---|---|
| 查看服务器列表(仅元数据) | ✅ 可用 |
| 测试连接 / 终端 / SFTP | ❌ 拒绝(需 DEK 解凭据) |
| 凭据 Reveal / 敏感库 Reveal | ❌ 拒绝 |
| MCP 工具调用(含所有 AI 操作) | ❌ 拒绝 |
| 审计查看 | ✅ 可用 |
| 配置查看 | ✅ 可用 |
| 配置修改(含主密码改) | ❌ 拒绝 |
UnlockScreen 实测覆盖 38 个守护 Command + UI 闸门 + safeInvoke 全局拦截器,确保锁定时凭据相关功能彻底关停。
空闲自动锁定
- 默认关闭
- 可设 5 / 10 / 15 / 30 / 60 分钟
- 鼠标 / 键盘活动重置计时
- 到时间 → DEK 缓存清零 → 显示 UnlockScreen
重置凭据库
设置 → 主密码 → 高级 → 重置凭据库:
| 选项 | 说明 |
|---|---|
| 重新加密 | 生成新 DEK + 用新 DEK 重加密全部凭据(中毒恢复) |
| 彻底清空 | 删除所有凭据 + DEK;服务器 / 敏感库 / 审计保留 |
二次确认 + 主密码验证。
实际安全等级
| 攻击场景 | 基础模式 | 主密码模式 |
|---|---|---|
| 偷磁盘 | DEK 在 keyring 没拿到,密文无用 | 同上 |
| 偷磁盘 + keyring | 暴露(DEK 是明文) | 不暴露(DEK 被 KEK 包装,需爆破主密码) |
| RAM 取证(应用解锁状态) | DEK 在内存 | DEK 在内存 |
| RAM 取证(应用锁定状态) | DEK 在 keyring | KEK 已清零,需重输主密码 |
| 键盘记录 | 主密码捕获即可(但用户没设) | 主密码被记录 → 加上磁盘 + keyring 才能解 |
主密码忘了
没有恢复机制——这是设计:
- 重置凭据库 → 全部凭据丢失(但服务器列表 / 审计保留)
- 你需要重新添加所有服务器的凭据
不允许「邮件找回」「密保问题」等弱机制,因为那些都是潜在攻击面。
不建议的做法
- ❌ 主密码用 123456 / qwerty
- ❌ 主密码写在 sticky notes 贴电脑上
- ❌ 把整个
<app data>/com.agilefr.reeve/同步到 OneDrive / 网盘(密文不算泄漏,但凑全 keyring 就是泄漏) - ❌ 在企业域机器上不设主密码(IT 可读 keyring)