GTK4 / gtkmm-4 · C++23 · CMake · SQLite · libsodium
lsPass 将 登录凭据、安全笔记和 API 密钥 存储在本地加密保险库中。无网络、无云、无遥测。任何机密内容都不会以明文形式写入磁盘。
sudo apt install libgtkmm-4.0-dev libsqlite3-dev libsodium-dev nlohmann-json3-dev
cmake -B build
cmake --build build -j
ctest --test-dir build --output-on-failure # 41 unit tests
./build/lspass
保险库文件位于 ~/.local/share/lspass/vault.db(权限 0600)。
cmake -B build-rel -DCMAKE_BUILD_TYPE=Release
cmake --build build-rel -j
cd build-rel && cpack -G DEB # requires: dpkg-dev, file
sudo dpkg -i ../packages/deb/lspass_1.0.0_amd64.deb
.deb 文件生成于 packages/deb/ 目录,包含二进制文件、com.lspass.App.desktop 启动器条目以及应用图标(packaging/com.lspass.App.svg,安装到 hicolor 主题中)。
不使用 CPack 时,cmake --install 使用默认的 /usr/local 前缀。运行时依赖(libgtkmm-4.0、libsodium、libsqlite3 等)由 dpkg-shlibdeps 自动解析,因此 apt --fix-broken install 或 sudo apt install ./lspass_1.0.0_amd64.deb 会自动拉取所有必需的依赖。
基于 OWASP 密码存储速查表(Password Storage Cheat Sheet)、libsodium 文档以及成熟密码管理器(Bitwarden、KeePassXC 风格的密钥封装)所采用的信封加密模式:
master password
│ Argon2id (memory-hard KDF, random 128-bit salt,
▼ opslimit/memlimit = libsodium "moderate",
KEK (32 B) parameters stored in vault for future upgrades)
│ XChaCha20-Poly1305 (key wrap)
▼
DEK (32 B, random) ── wraps nothing else, RAM only, never on disk
│ XChaCha20-Poly1305 AEAD per field
▼
SQLite: entries(title, username, url [plaintext metadata],
secret, notes [sealed blobs: nonce‖ct‖poly1305 tag])
为什么做出这些选择:
坦诚的权衡: title、username 和 url 以明文存储,这样列表/搜索无需解密每一行即可工作。机密本身(密码、笔记、API 密钥)始终是密封的数据块。单元测试 secrets_not_stored_in_plaintext 会逐字节扫描保险库文件(包括 WAL),查找一个 canary 机密来证明这一点。
ctest 针对与 GUI 无关的核心库运行三个测试套件(41 个用例)。整个套件还会在 AddressSanitizer + UBSan 下运行:
cmake -B build-san -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
cmake --build build-san -j && ctest --test-dir build-san
发布构建会添加 -fstack-protector-strong、-D_FORTIFY_SOURCE=2、PIE 和完整 RELRO(-Wl,-z,relro,-z,now)。
src/core/crypto.{hpp,cpp} SecureBytes, Argon2id KDF, XChaCha20-Poly1305, key wrap
src/core/vault.{hpp,cpp} SQLite vault, envelope encryption, CRUD
src/core/generator.{hpp,cpp} CSPRNG password/passphrase generator
src/ui/ gtkmm-4 UI (unlock screen, list, editor dialogs)
tests/ ctest suites (no external framework needed)
MIT — 参见 LICENSE。
| 决策 | 理由 |
|---|
| Argon2id KDF | OWASP 对密码派生密钥的首选;内存密集型,抗 GPU/ASIC 破解。参数超过 OWASP 最低要求(m ≥ 19 MiB, t = 2)。 |
| 信封加密(随机 DEK 由 KEK 封装) | 更改主密码只需重新封装 32 字节,而无需重新加密整个保险库;没有 KEK 就不可能攻破 DEK。 |
| XChaCha20-Poly1305 AEAD | 192 位随机 nonce 使 nonce 重用不成问题;Poly1305 对每个密文进行认证,因此错误的主密码会因认证失败而被检测到——任何地方都不会存储密码哈希或验证器。 |
AAD 绑定(lspass:v1:entry:<id>:<field>) | 拥有数据库文件写入权限的攻击者无法在条目或字段之间移植密文。 |
| 每次写入使用全新 nonce | 每次保存都会使用新的随机 nonce 重新密封。 |
| 内存卫生 | 密钥存放在 SecureBytes 中,销毁时用 sodium_memzero 清除;UI 在使用后立即清除密码字段;复制后 30 秒自动清除剪贴板(且仅当其中仍保存着我们的机密时)。 |
| 文件权限 | 保险库文件权限为 chmod 0600。 |
| 密码生成器 | 采用带拒绝采样的内核 CSPRNG(无模偏差),保证包含所有启用的字符类别,默认排除易混淆字形;默认 20 个字符时熵约为 128 位。 |