抗取证加密保险柜 — 基于 Tauri 2 + Rust 的桌面端加密文件管理系统。
3.0.0 大版本亮点:v6 流式分块格式(单文件上限从 256 MiB 提升至 1 TiB,加解密内存恒定约 4 MiB)、胁迫密码(反胁迫最后防线)、YubiKey 硬件密钥二因子(可选,零格式变更)、Tauri 2 迁移 + 核心库模块化重构、音视频流式预览(按需解密播放、明文不落盘)、读/加密流水线 + 导入提取进度、密钥驻留内存(防换出)、审计链头部锚点、cargo-fuzz 持续模糊测试。
- 加密算法:AES-256-GCM(认证加密,防篡改 + 防窃听)
- 密钥派生:Argon2id (m_cost=65536, t_cost=3, p_cost=1) → HKDF-SHA512 扩展,派生三把独立密钥:
enc_key— 加解密文件数据auth_key— 认证标签验证(防暴力破解)sign_key— 头部签名(HMAC-SHA512,防头部篡改)
- 信封加密(v5 格式,2.8.0):每个分区持有随机 32 字节
data_key承担真正的加密职责,口令只负责「包裹」它(Argon2id → KEK → AES-256-GCM 包裹体存于头部)。修改密码 = 换盐重新包裹 + 重写头部,数据一个字节不动、瞬间完成;包裹体与头部前缀 / 条目别名 / 条目盐绑定(防调包),未使用分区条目整体随机填充、伪装性不破坏。v4 老格式继续兼容打开 - 流式分块加密(v6 格式,3.0.0):文件数据按 4 MiB 明文分块,每块独立
nonce(12)‖密文‖tag(16),块 AAD 绑定「冻结虚拟路径 + 块序号 + 总块数」(防截断、防重排、防跨文件块调包)。导入 / 提取全程恒定内存(与文件大小无关),单文件上限从 256 MiB 提升至 1 TiB。新建保险柜一律 v6;v5 保险柜执行「修改密码」即自动升级 v6(仅头部重写,秒级);v4 保险柜改密码直达 v6(一次性全库重加密)。v6 头部与 v5 逐字节同布局(仅版本字节不同);v4/v5 保险柜继续兼容打开,其存量文件保持 Legacy 整段布局照常读写,v6 中新导入的文件才走分块布局(空文件自动走 Legacy) - 上下文绑定(AAD):每个密文块绑定其导入时冻结的虚拟路径标识(重命名不改写密文,故 AAD 也不再随路径变化),防止密文移动攻击
- 认证方式:
- 纯密码模式
- 密码 + 密钥文件双重认证(密钥文件可存储在 USB 等物理介质)
- 头部结构:v5/v6 为 2048 字节固定头部(v4 为 1024 字节),包含 magic bytes、版本号、salt、分区表、锁定区、认证标签和签名,所有字段均校验完整性
- 文件后缀:默认使用
.lyt
- 单个保险柜最多支持 8 个独立分区,每个分区拥有独立的密码和密钥
- 用不同密码打开保险柜会进入不同分区,分区之间完全隔离
- 未使用的分区条目整体填充随机数据,与真实分区在结构上不可区分;打开时恒定遍历全部 8 个条目(恒定时间)
- 支持动态添加/删除分区;删除分区时按 DoD 7-pass 擦除其索引区
- 已知限制:分区别名以明文存储于头部(分区管理功能需要),真实分区数量可通过解析头部推断;删除分区时该分区的文件密文因无分区密码无法定位,无法一并擦除(详见「已知限制」)
- 可将任一分区指定为胁迫分区(见「胁迫密码」);为任一分区启用YubiKey 硬件密钥二因子(见「硬件密钥二因子」),与其他分区的密码认证互不影响
- 虚拟文件系统:所有文件存储在加密保险柜内部,通过虚拟路径 (
vpath) 访问 - 文件夹导航:树状目录结构,支持路径输入框直接跳转 + 上级目录返回
- 导入文件:选择本地文件导入到当前目录,支持多选批量导入
- 导入文件夹:递归导入整个文件夹,保留目录结构;跳过符号链接,限制目录层级与项目数量
- 提取选中:将选中的文件/文件夹解密导出到本地指定目录;遇到已有同名文件时弹窗确认,确认后覆盖(2.4.1 起与确认语义一致)。2.5.1 变更:只提取单个文件时直接放入目标目录,不再重建其在保险柜内的上级目录(旧行为提取
/docs/readme.txt到D:\out会生成D:\out\docs\readme.txt,现在结果为D:\out\readme.txt);多选批量提取与「提取全部」仍保留完整目录结构,避免不同子目录的同名文件冲突 - 提取全部:一键提取保险柜内所有文件到指定父目录,自动创建以保险柜文件名命名的根文件夹,保留内部目录结构。单次索引加载 O(n) 性能优化
- 流水线加解密与进度(3.0.0):v6 大文件的导入/提取采用「读 / 加解密 / 写」流水线(后台线程预读、有界通道限在途 ≤ 2 块),吞吐较串行明显提升;批量导入 / 文件夹导入 / 提取全程向前端发节流进度事件(状态栏实时显示 x/y)
- 批量操作:支持 Ctrl+多选,批量提取、批量删除(文件夹自动展开为内部所有文件,嵌套选中自动去重)
- 文件名搜索(2.8.0):导航栏搜索框跨全库按文件名/vpath 大小写不敏感匹配,结果平铺显示完整路径,双击跳转/打开,右键菜单全套可用;Esc 或清空恢复目录视图
- 移动文件/文件夹(2.8.0):右键「移动到…」弹出柜内文件夹选择器(支持多选、目标路径预览);只改索引元数据不重加密,同名冲突与「移入自身子目录」明确拒绝
- 全库完整性体检(2.8.0):一键逐文件校验 AES-GCM 认证标签(只读),检出坏块 / 位腐 / 云同步损坏,带进度显示与异常清单
- 新建文件夹:在当前目录下创建子文件夹(2.5.1 起工具栏与右键菜单双入口)
- 重命名:文件/文件夹重命名(右键菜单或选中后操作)
- 删除:从保险柜中安全删除选中的文件/文件夹
- 右键菜单:文件/文件夹右键弹出快捷操作菜单
无需导出即可在应用内预览文件内容,文件始终不解密到磁盘:
- 图片预览:支持 PNG / JPG / GIF / BMP / WebP / TIFF,内置鼠标滚轮缩放
- 文本查看与直接编辑(2.5.1 新功能):支持 TXT / MD / JSON / CSV / XML / INI / YAML 等纯文本格式,以及常见代码文件(.rs / .js / .go / .py / .sh 等)。预览对话框内点击「编辑」即可修改,点击「保存」写回保险柜 —— 全程不解密到磁盘:新内容加密追加到保险柜末尾 → 索引先落盘 → DoD 7-pass 覆写旧密文(与安全删除同序,任何时点崩溃都不损坏文件)。编辑上限 4 MB(超过只读预览);非 UTF-8 编码文本(如 GBK)自动降级为只读,避免保存破坏原编码
- Office 预览:
.docx— 解压 ZIP 解析word/document.xml提取文本.xlsx/.xls— 通过 calamine 读取所有工作表.doc— OLE 复合文档 UTF-16LE 文本流扫描.csv— 直接 UTF-8 渲染- 加密的
.docx/.xlsx(2.7.0):设置过「打开密码」的加密 Office 文档弹出口令输入框后纯内存解密预览,密文与明文全程不落盘,口令用后即清零。支持 Office 2007 的 Standard Encryption(版本 4.2/2.2/3.2 头,SHA-1 迭代派生 + AES-ECB)与 Office 2010+ 的 Agile Encryption(AES-CBC + SHA-1/256/384/512);旧版 RC4 加密(.doc/.xls二进制加密)不支持
- 音视频流式预览(3.0.0):MP4 / WebM / MKV / MOV / MP3 / OGG / WAV / FLAC 等常见音视频容器双击直接播放 —— 基于 v6 分块布局的随机访问解密:播放器通过自定义协议
lynvault-media://发 Range 请求,后端只解密所需片段(每响应窗口 ≤ 16 MiB),明文仅存在于播放器内存、全程不落盘、不完整加载(拖动进度条只解密目标片段);响应携带Cache-Control: no-store禁止 WebView 磁盘缓存。预览凭会话级令牌(关柜即作废);v4/v5 时代的旧版整段布局文件不支持流式,维持「提取后查看」 - 不支持的格式(含
.pptx,2.7.0 起移除预览支持)会提示导出后查看
- 删除保险柜内的文件或文件夹时,先持久化更新加密索引,再对对应密文区域执行 DoD 5220.22-M 7-pass 覆写
- 写入失败时,索引已不再引用该密文,避免出现已擦除但仍被索引指向的数据损坏
- 删除后自动整理(2.7.0):死空间 ≥ 64 MiB 且占文件 ≥ 30% 时自动执行碎片整理回收空间(仅单分区;详见「碎片整理」)
- 为避免 WebView IPC 被滥用,应用不会自动擦除导入来源的本地文件;导入完成后请自行确认并处理源文件
- 二次确认后执行不可逆销毁
- 先关闭保险柜,再对整个
.lyt文件执行 DoD 5220.22-M 7-pass 擦除 - 擦除完成后删除文件
- 对保险柜文件执行碎片整理,压缩冗余空间
- 单分区走紧凑整理:重建只含有效数据的文件布局,物理文件长度直接缩小,真正回收磁盘空间(2.4.1)
- 多分区走保守整理:仅重写活跃分区,其他分区数据原样保留,旧数据区 DoD 7-pass 逻辑擦除
- 整理过程使用临时文件 + 原子替换,崩溃时可自动回滚(含分区偏移回滚)
- 整理后自动重新加载文件列表
- 删除后自动整理(2.7.0):安全删除 / 删除文件夹完成后,当死空间同时满足「≥ 64 MiB」且「占文件大小 ≥ 30%」时自动执行一次紧凑整理,把已擦除区域从文件中物理移除(仅单分区启用;多分区整理不回收空间,自动触发无收益,保持手动)。删除结果返回回收字节数,状态栏提示「已自动整理回收 XX MB」;自动整理失败不影响删除结果,仅记日志
- 保险柜在内部维护关键操作记录(链式 HMAC 防篡改,篡改自动截断)
- 2.8.0 起提供「操作记录」查看器:工具栏入口,倒序展示最近 500 条
- 开锁前失败尝试提示(2.8.0):密码输入框下方显示该保险柜被试错过的次数(头部锁定区数据)——用户能察觉有人动过自己的保险柜
- 空闲自动锁定:无鼠标/键盘操作满 2 分钟自动关闭保险柜并回到启动弹窗;触发时若有未保存的文本编辑,先走正常加密保存流程再关闭(不丢数据)。时长可在设置中调整(0 = 禁用)。2.8.2 起后端兜底:Rust 侧以
GetLastInputInfo做系统级空闲检测(每 5 秒轮询),WebView 被后台节流或渲染进程挂起时前端定时器失效仍能锁定 - 系统事件自动关闭(Windows):锁屏、睡眠(含合盖)、注销时立即关闭保险柜并回到启动弹窗
- 防截屏(Windows):
SetWindowDisplayAffinity(WDA_EXCLUDEFROMCAPTURE)—— 本窗口不出现在截屏、录屏、远程共享画面中(Win10 2004+ 完全隐藏,旧系统显示为黑块;无法阻止物理拍摄)。默认开启,设置中可关 - 剪贴板保护(Windows):保险柜打开期间,任何程序放入剪贴板的内容被即时清空(含 Win10 1809+ 的 Win+V 剪贴板历史);关闭保险柜后剪贴板自动恢复正常。已知副作用:开柜期间在其他软件里复制的内容同样被即时清空(这正是目的 —— 不留明文残留)
- 工具栏「修改密码」入口,要求输入当前密码确认(防他人在已解锁机器上改密锁死主人),新密码 ≥ 12 字符
- v5 保险柜:头部级操作,瞬间完成
- v4 保险柜:自动升级为 v5(一次性全库重加密,复用碎片整理的安全管线:磁盘预检 → 加密备份 → 临时文件重建 → 原子替换 → 失败回滚),升级后旧版本 LynVault 无法打开该文件;多分区 v4 保险柜不支持自动升级(其余分区口令未知,无法生成包裹密钥),明确报错
- 升级时审计日志整链换钥(先用旧密钥硬校验,篡改即中止),历史记录保留
.lyt 文件以任何方式导航到软件,都会被自动识别并直接进入该保险柜的密码输入流程,而不是被误当作待加密文件导入:
- 双击打开(文件关联):程序首次运行时自动注册用户级文件关联(HKCU,无需管理员,便携版同样生效;用户已将
.lyt关联到其他程序时不覆盖)。资源管理器双击.lyt→ 系统以LynVault.exe <文件路径>启动 → 跳过启动弹窗直接进入密码输入 - Linux 文件关联:无需运行时注册,安装
.deb时由 MIME 数据库与桌面项自动建立.lyt→ LynVault 的关联,文件管理器双击同样以参数形式把路径交给lyn-vault启动 - 运行中重复双击(单实例转发):程序已在运行时再次双击
.lyt,第二个进程通过本机 TCP 单实例端口把路径转发给已运行实例后立即退出(不闪窗口);已运行实例自动聚焦窗口并向前端发出vault-file-requested事件打开密码输入 - 拖放识别:把
.lyt拖入窗口 → 自动检测(扩展名 + magic bytes 双重校验)→ 弹出密码输入;普通文件拖放行为不变(正常导入) - 识别防护:仅头部 8 字节为
PYVAULT4的真正 LynVault 文件才会被识别,其他工具(HashiCorp Vault 等)的同后缀文件不会被误判 - 密码错误可原地重试,取消则回到启动弹窗;启动弹窗后台静默预扫描,取消后列表已就绪
应用启动时会自动扫描常见目录(桌面、文档、下载、用户主目录)下的 .lyt / .vault 文件,弹出不可关闭的快速打开对话框:
- 列出所有检测到的保险柜文件(按修改时间倒序,显示名称、时间、大小)
- Magic bytes 校验:仅显示头部 8 字节为
PYVAULT4的真正 LynVault 文件,过滤掉其他工具(如 HashiCorp Vault、1Password)的同后缀文件,避免误识别和元数据泄露 - 点击任一项直接进入密码输入流程,密码错误时内联提示不销毁密码框,支持原地重试
- 提供「新建保险柜」和「打开其他保险柜」按钮,取消任何步骤都会回到启动弹窗(不卡死)
- 弹窗显示期间,主窗口工具栏/文件列表灰显且不可操作(强制用户先选择打开/新建)
- 启动扫描期间禁用「新建/打开」按钮,防止用户在弹窗弹出前操作
- 列表项点击防重入,防止快速双击弹出多个密码框
- 所有密钥材料使用
zeroizecrate 自动清零(ZeroizeOnDrop) - 加解密中间变量(plaintext、master key、derived key)使用后立即
zeroize() - 保险柜全局状态使用
Mutex保护,panic 时自动 catch 防止闪退
模型:将任一分区指定为「胁迫分区」。被胁迫交出密码时,交出胁迫分区的密码 —— 外部看到的是「正常打开了一个柜子」(诱饵文件可经受检查),但在会话建立前的瞬间,其他所有分区的头部条目(别名 / 盐 / 认证标签 / 包裹密钥 / 索引定位)被整体覆写为随机字节,与从未使用的条目在结构上不可区分,其他分区的数据从此永久不可达。
如实声明(3.0.1):触发属元数据级销毁 —— 其他分区的密文本体默认原地残留(不可解密、不可定位,但并未被擦除)。多分区保险柜的碎片整理不回收其他分区死密文;持有旧文件快照者可嫁接旧头部条目(仍需对应分区口令才能解密,全文件回滚窗口见「已知限制」)。需要物理级清理时,管理对话框提供**「物理清理死密文」**(3.0.1 新增):随机化其他分区条目 + 对其密文残留做覆写 —— 显式调用、绝不自动执行(批量 I/O 会放弃不可观测性),需当前分区口令与双重确认。
- 完全不可见:标记只存储于胁迫分区自身的加密索引内 —— 头部、文件布局、分区数量与普通保险柜完全无差异;不持有胁迫分区密码就无法观测标记的存在
- 无痕触发:设置与触发均不写操作记录 —— 诱饵柜的日志必须看起来完全正常
- fail-closed:触发覆写若因 I/O 失败而未完成,开柜直接失败 —— 宁可出现一次可疑报错,也不让隐藏分区完好带出
- 设置流程(任一会话内完成,无需先打开目标分区):管理对话框提供「新建胁迫分区」(别名 + 密码,创建后引导放入诱饵文件)与「标记已有分区」两条路径 —— 标记 / 解除均需验证目标分区的密码(后端解开其加密索引写入 / 移除标记);允许原地标记当前分区(打开诱饵分区放好文件后标记是自然流程),也允许跨分区标记;两次弹窗确认(含「已理解数据不可恢复」);单分区保险柜直接拒绝设置
- 分区别名唯一:添加分区时查重,重名直接拒绝(别名是分区定位的唯一键)
- 演练模式:对保险柜的临时副本执行完整触发流程(真实开柜 + 真实覆写 + 重开验证「仅剩胁迫分区」),副本用后 DoD 擦除(创建失败同样清理,不残留暴露性文件名),原件零接触
⚠️ 红线:触发即其他分区数据永久销毁,无任何找回手段;密文本体默认原地残留(元数据级销毁 —— 不可解密但未被擦除,物理清理或整体销毁可一并擦除)。请务必先用演练模式熟悉机制。任何分区(含主分区)都可被标记 —— 误把主分区标记为胁迫分区后,正常开柜即触发销毁,UI 已显式提醒
- 认证模型:口令(Argon2id)+ YubiKey 挑战-响应(HMAC-SHA1,槽 2)两段独立因子。启用二因子的分区,开柜必须同时持有正确口令与物理钥匙
- 零格式变更设计:挑战从头部保留区的公开「挑战盐」HKDF 派生(64 字节,不落盘、无需存储;3.0.1 起该盐在创建保险柜时随机生成、终生不变 —— 实测证明开柜轮换会使 data_key 的旧响应包裹永久不可解,二因子保险柜砖死);响应经域分离 HKDF 混入 KEK 后再包裹 data_key —— 头部条目结构与普通分区完全一致,无任何「已启用」标志位;打开时对每个条目按「混合优先、普通兜底」双路径解包,二因子分区与普通分区可共存,不启用时行为与历史逐字节一致
- 响应不出后端(3.0.1):20 字节响应只在 open / 改密 / 胁迫命令 / 启停二因子的后端路径内现场挑战硬件获得,WebView 全程不接触响应字节(3.0.0 曾把响应交给前端,构成对文件快照静态可重放的秘密)
- 秒级启停:启用 / 解除均为头部级操作(验证口令 + 钥匙触摸 + 换盐重新包裹),瞬间完成;「修改密码」自动保留二因子状态(不带钥匙触摸将明确拒绝,防误降级)
- 前提配置:YubiKey 槽 2 需配置为 HMAC-SHA1 挑战-响应凭证(
ykman otp chresp -H 2或 Yubico 个人化工具;固定使用槽 2,与 KeePassXC 同一约定) - 设备层:PC/SC(CCID)直连 YubiKey OTP 应用 —— Windows 用系统 winscard,Linux 用 pcsc-lite;仅探测「名称含 YubiKey」的读卡器
⚠️ 丢失风险:钥匙丢失且响应不可复现时,该分区数据永久无法打开(与密钥文件同级风险;其他未启用分区不受影响)。UI 与文档均如实标注
- 开柜提速:Argon2id 并行派生上限 4 → 8(8 核以上机器开柜约减半;瞬时内存峰值 ≤ 512 MB,低配机器按核数自动回落)
- 密钥驻留内存:四把会话密钥装箱到堆上稳定地址并
VirtualLock(Windows)/mlock(Unix)钉住所在页 —— 防止内存压力下密钥被换出到 pagefile(磁盘明文残留面);Drop 时先解锁再清零;锁页失败自动降级为「装箱 + Drop 清零」,不增加失败路径 - 审计链头部锚点:头部保留区新增 8 槽审计条目计数,开柜时与索引实际条目数比对 —— 尾部截断(HMAC 链无法自查的攻击)与索引回滚显式告警;3.0.0 之前落盘的存量分区计数为 0(无锚点),首次落盘后自动生效。3.0.1 如实更正:该锚点位于 auth_tag 前缀的「保留区规范化为全零」范围内、且头部签名在多分区场景下只校验不强制,因此锚点本质是尽力而为的告警提示(随头部签名被当前分区重签,不提供密码学强制性)
LynVault 3.0.0/
├── Cargo.toml # Workspace 根配置
├── Cargo.lock
├── rust-toolchain.toml # 工具链钉死(与 CI 一致,可复现构建)
├── deny.toml # 3.0.0:cargo-deny(依赖漏洞 / 许可证 / 来源)
├── .github/workflows/ci.yml # 3.0.0:CI 门禁(fmt / clippy / 双平台测试 / deny)
├── src-tauri/ # Tauri 2 桌面应用
│ ├── Cargo.toml
│ ├── tauri.conf.json # Tauri 2 配置(capabilities 权限模型)
│ ├── capabilities/
│ │ └── default.json # 3.0.0:细粒度权限声明(core / dialog / opener)
│ ├── build.rs
│ ├── icons/ # 应用图标
│ ├── linux/ # deb 打包资源
│ │ ├── lynvault.desktop # 桌面项模板(含 .lyt MIME 关联)
│ │ └── lynvault-mime.xml # .lyt MIME 类型定义
│ └── src/
│ ├── main.rs # 入口 + 命令注册 + .lyt 启动参数解析 + 防截屏
│ ├── commands.rs # Tauri IPC 命令(3.0.0:胁迫密码 / 硬件密钥命令)
│ ├── yubikey.rs # 3.0.0:YubiKey CCID 直连(HMAC-SHA1 挑战-响应)
│ ├── settings.rs # 设置持久化(便携 / 用户目录二选一)
│ ├── system_events.rs # 锁屏/睡眠/注销监听(Windows)
│ ├── clipboard_guard.rs # 开柜期间剪贴板即时清空(Windows)
│ ├── single_instance.rs # 单实例 + 参数转发 + vault-file-requested 事件
│ └── file_assoc.rs # .lyt 文件关联自注册(Windows HKCU)
├── crates/
│ └── vault-core/ # 核心加密库(纯 Rust,无平台依赖)
│ ├── Cargo.toml
│ ├── src/
│ │ ├── lib.rs # 模块导出
│ │ ├── vault/ # 3.0.0:保险柜主体(模块化拆分)
│ │ │ ├── mod.rs # 结构体定义 + 模块导出
│ │ │ ├── consts.rs # 格式常量(单一来源)
│ │ │ ├── header.rs # 头部读写 / 签名 / 认证标签绑定(v4/v5/v6)
│ │ │ ├── fs_util.rs # 独占打开 / 索引 I/O / 原子替换 / 布局感知读取
│ │ │ ├── session.rs # 创建 / 打开认证(恒定时间)/ 索引缓存
│ │ │ ├── partition.rs # 伪装分区增删
│ │ │ ├── ops_import.rs # 导入与内容写入(v6 分块流式)
│ │ │ ├── ops_extract.rs # 提取与读取(v6 分块流式)
│ │ │ ├── ops_delete.rs # 安全删除与自动整理触发
│ │ │ ├── maintenance.rs # 改密码 / v4→v6 升级 / 体检 / 碎片整理 / 销毁
│ │ │ ├── duress.rs # 3.0.0:胁迫密码(标记 / 触发覆写 / 演练)
│ │ │ └── yubikey.rs # 3.0.0:硬件密钥二因子(启用 / 解除)
│ │ ├── crypto.rs # AES-256-GCM / Argon2id / HKDF / HMAC / 分块 AAD
│ │ ├── index.rs # 加密文件索引(含 v6 块布局字段)
│ │ ├── lock.rs # 防爆破锁定逻辑(错误计数 + 锁定区 HMAC)
│ │ ├── audit.rs # 操作审计日志(链式 HMAC)
│ │ ├── wipe.rs # DoD 安全擦除
│ │ ├── office.rs # Office 文档文本提取
│ │ └── error.rs # 错误类型定义
│ └── tests/
│ ├── fixtures/ # 3.0.0:v4/v5 兼容夹具(格式回归守卫)
│ └── vault_integration.rs # 集成测试(3.0.0:77 项)
└── ui/ # 前端界面(vanilla JS,无构建步骤)
├── index.html # 主界面
├── styles.css # 样式(五主题渐变)
└── app.js # 交互逻辑(3.0.0:Tauri 2 桥接 / 胁迫 / 硬件密钥 UI)
| 命令 | 说明 |
|---|---|
create_vault |
创建新保险柜(加密 + 自动打开) |
open_vault |
打开并认证保险柜 |
close_vault |
关闭当前保险柜 |
list_folder |
列出目录内容 |
import_files_batch |
批量导入(单次索引加密落盘,返回 {ok, fail},失败项不中断整体) |
import_folder |
递归导入文件夹 |
import_dropped_paths |
拖放导入(自动判断文件/文件夹) |
extract_files |
批量提取文件(返回 {ok, fail},失败数不再被静默丢弃,2.7.1) |
extract_all_files |
提取全部文件到指定父目录(自动创建保险柜同名子文件夹,单次索引加载 O(n)) |
check_extract_all_dest |
预检目标子文件夹是否已存在 |
delete_files |
批量安全删除文件/文件夹(展开文件夹 + 去重 + DoD 7-pass,先存索引再擦密文防损坏;返回 {files, folders, reclaimed},死空间达阈值时自动整理,2.7.0) |
delete_folder |
删除文件夹(2.7.0 起返回 {reclaimed},同上自动整理) |
new_folder |
新建文件夹 |
rename_item |
重命名文件/文件夹 |
add_partition |
添加伪装分区 |
remove_partition |
删除伪装分区 |
list_partitions |
列出所有分区 |
defragment_vault |
碎片整理(2.7.0 起删除操作也会按死空间阈值自动触发,仅单分区;2.7.1 起预检磁盘空间并用 ReplaceFileW 保留文件 ACL) |
destroy_vault |
不可逆销毁保险柜(2.7.1 起全程使用会话句柄,修复 Windows 上必然失败的回归) |
get_file_info |
获取文件元信息 |
load_file_content |
安全加载文件内容 |
update_file_content |
文本编辑保存(2.5.1):加密追加新内容 → 索引落盘 → DoD 7-pass 覆写旧密文 |
preview_office_file |
Office 文档预览(2.5.1:64 MiB 大小上限 + 工作表/行数/ZIP 条目数量上限;2.7.0:password 参数支持加密 docx/xlsx 的纯内存解密,未加密时传 null,已加密且无口令时返回 OFFICE_ENCRYPTED 哨兵) |
scan_vault_files |
扫描目录下的 .lyt 文件(启动弹窗用) |
check_vault_file |
校验路径是否为 LynVault 保险柜(扩展名 + magic bytes,拖放识别用) |
get_launch_vault_arg |
读取启动参数中的保险柜路径(双击 .lyt 启动直达密码输入;读取即清除) |
frontend_ready |
前端就绪通知(单实例转发的打开请求等前端注册监听器后再发事件) |
get_file_icon |
按扩展名读取系统文件图标(Windows:系统图标;其他平台返回空串,由前端内置图标兜底;阻塞线程池执行) |
change_password |
修改保险柜密码(2.8.0):v5 头部级秒完成;v4 自动升级为 v5(一次性全库重加密 + 失败回滚),多分区 v4 明确拒绝 |
move_items |
移动文件/文件夹(2.8.0):跨目录移动只改索引(AAD 冻结,不重加密),返回 {ok, fail, errors} |
list_all_folders |
列出当前分区全部文件夹(移动选择器用) |
search_files |
文件名搜索(2.8.0):全库大小写不敏感子串匹配,文件夹优先 |
get_audit_log |
审计日志查看(2.8.0):倒序返回内部操作记录(链式 HMAC 已校验) |
verify_vault_integrity |
全库完整性体检(2.8.0):逐文件 GCM 校验,过程发 integrity-progress 事件 |
get_lock_info |
锁定区信息(2.8.0):读取头部失败尝试计数(公开密钥校验,无需密码) |
get_settings / enable_persistence / disable_persistence / save_settings |
设置持久化(2.8.0):便携目录 / 用户目录二选一,主题 / 自动锁定时长 / 窗口尺寸 / 防截屏开关 |
set_duress_mark / clear_duress_mark |
胁迫分区标记 / 解除(3.0.0):参数为目标分区别名 + 目标分区密码;标记写入目标分区自身的加密索引 |
get_duress_status |
胁迫状态查询(3.0.0):当前分区是否带标记 + 分区总数 |
duress_rehearsal |
胁迫演练(3.0.0):对临时副本执行完整触发并验证,副本用后 DoD 擦除,原件零接触 |
duress_scrub_partitions |
胁迫物理清理(3.0.1):随机化其他分区条目 + 覆写其密文残留(需当前分区口令验证,双重确认,进度经 scrub-progress 事件) |
enable_yubikey_2fa / disable_yubikey_2fa |
硬件密钥二因子启用 / 解除(3.0.0):头部级重新包裹,需口令 + 钥匙触摸 |
yubikey_status |
硬件密钥状态(3.0.0):当前分区是否启用 + 设备是否在位 |
mint_media_token |
媒体流式预览令牌(3.0.0):校验扩展名白名单与分块布局后签发会话级令牌,自定义协议 lynvault-media:// 凭其响应 Range 请求 |
- 工具栏「设置」→ 未启用时仅显示「启动持久化」→ 选择配置位置:当前路径(exe 同目录,配置随程序移动,适配 U 盘)或用户文件夹(
%APPDATA%\LynVault,适配固定安装);程序目录只读时启用便携位置会明确报错 - 启用后设置界面提供:主题(vivid=默认 / 蓝 / 紫 / 金 / 青五款同款透明渐变,切换即时生效)、自动锁定时长(分钟,0=禁用)、窗口尺寸(480-3840 × 360-2160,保存即应用并居中)、防截屏开关
- 配置文件为明文 JSON 且不含任何敏感信息(无密码、无路径、无保险柜历史);启动时 exe 目录优先、其次用户目录,都没有即未启用
- 未启用持久化时以上设置项不可调(全部使用默认值:vivid 主题 / 2 分钟 / 窗口按主显示器自适应(宽 ≤1024、高 ≤ 屏高 80%)/ 防截屏开启)
| 层 | 技术 |
|---|---|
| 前端 | HTML + CSS + JavaScript (vanilla,无构建步骤) |
| 框架 | Tauri 2.x(3.0.0 迁移;capabilities 细粒度权限模型) |
| 后端 | Rust 2021 Edition(工具链经 rust-toolchain.toml 钉死) |
| 加密 | aes-gcm (AES-256-GCM) / argon2 (Argon2id, 64MB/3 iter) / hkdf / hmac / sha2 |
| 硬件密钥 | pcsc(PC/SC CCID 直连 YubiKey OTP 应用,HMAC-SHA1 挑战-响应) |
| 内存安全 | zeroize (ZeroizeOnDrop) |
| Office 解析 | calamine (Excel) / quick-xml (DOCX/PPTX) / zip |
| 打包 | Tauri bundler(Windows .exe / .msi;Linux 单文件 .deb) |
LynVault 采用纵深防御设计,兼顾机密性、完整性和抗取证能力:
主密码 + 密钥文件(可选)
│
▼
Argon2id (64 MB / 3 iter) ← 内存硬函数,抵抗 GPU/ASIC 暴力破解
│
▼
32 字节 master key
│
▼
HKDF-SHA512 扩展(带长度前缀,域分离)
│
├─► enc_key (32B) — AES-256-GCM 加解密,绑定 AAD
├─► auth_key (32B) — GCM 认证标签验证
└─► sign_key (32B) — HMAC-SHA512 头部签名
| 威胁 | 防御措施 |
|---|---|
| 暴力破解密码 | Argon2id 内存硬性 + 认证标签验证 + Tauri 端全局冷却 + 持久化防暴力锁定(2.3.0 起真正生效:5 次错误锁定 30 分钟;跨重启按系统时钟延续,见「已知限制」) |
| 密文篡改 | AES-256-GCM 认证加密(主防线)+ 绑定头部的分区认证标签(头部篡改无条件检出) |
| 密文移动攻击 | AAD 将每个密文块绑定到其导入时冻结的虚拟路径标识,无法在不同 vpath 间移动(重命名后仍可解密) |
| 分区交换攻击 | 每个分区独立密钥,AAD 常量 b"index" 锁定索引数据 |
| 明文残留 | 保险柜内删除先更新加密索引再 DoD 7-pass 覆写密文;导入来源由用户在应用外自行处理 |
| 内存泄露 | zeroize 自动清零密钥材料,错误路径同样清零 |
| 路径遍历 | canonicalize 验证提取目标路径,拒绝跳出基目录的符号链接(Windows 上按大小写不敏感的逐组件比较,匹配其文件系统语义);已有同名文件默认拒绝覆盖 |
| 计时侧信道 | 打开时恒定遍历全部 8 个分区条目(无论真实分区数量),抹平响应时间差异;分区查表比较使用恒定时间实现 |
| 密钥派生歧义 | 密码 + 密钥文件拼接使用长度前缀,防止不同输入派生相同密钥 |
| 符号链接与递归导入 | 导入文件夹跳过符号链接并限制目录深度和项目数量;提取校验规范化输出目录 |
| 锁定机制绕过 | 锁定区 HMAC 使用从 salt 独立派生的公开密钥:任何密码的尝试都能校验并递增计数(锁定真正生效);局限:拥有文件写权限者可伪造「未锁定」记录,见「已知限制」 |
| 系统时钟回拨 | 锁定状态额外使用单调时钟,防止进程内系统时间回拨绕过(跨重启回拨仍需系统时钟,见「已知限制」) |
| 头部篡改 | 单分区严格要求签名匹配;2.6.1 起分区认证标签绑定头部字段(magic/版本/salt/别名/分区 salt),任意分区数下头部被篡改都会导致认证失败,不再有「多分区跳过校验」的降级路径 |
| 删除时数据损坏 | 所有删除路径统一「先 save_index 标记删除,再覆写密文」,覆写失败时密文残留无害(索引已不指向) |
| 恶意文件崩溃 | 索引长度上限 + checked_add 防溢出;Office 预览解压尺寸上限(防 zip 炸弹)+ ZIP 条目数/工作表数/单表行数上限(2.5.1,防元数据 OOM);导入/加载文件大小上限(防 OOM) |
| 销毁路径 TOCTOU | 保险柜销毁全程使用预打开句柄操作目标文件(2.5.1):擦除与删除均作用于句柄而非路径,消除「检查-再删除」竞态窗口;Windows 上句柄关闭时由系统直接删除(delete-on-close,不经路径) |
| 加密路径 panic | 核心加解密 / 密钥派生函数移除 expect/unwrap(2.5.1),错误全部传播返回,不再因单个文件异常导致进程崩溃 |
| 本地 IPC 滥用 | 单实例协议单行读取长度上限 + 每连接独立线程处理并设并发上限(2.6.1,防本地恶意进程超长行耗尽内存、慢连接阻塞转发);系统图标缓存条目上限(2.5.1,防海量扩展名撑爆 WebView 内存) |
| 安全事件不可追溯 | 2.5.1 起日志系统真正初始化:Warn 及以上级别写入临时目录日志文件(%TEMP%\LynVault.log,UTC 时间戳、1 MiB 自动轮转、轮转时先零覆写旧内容);2.6.1 起日志不再记录文件路径/文件名等敏感信息 |
| 分区别名混淆 | 2.6.1 起新录入别名限定 ASCII([A-Za-z0-9_- ]),禁止 Unicode 同形字符;解析旧头部时保留宽松判定以兼容既有非 ASCII 别名 |
| 启动扫描误识别 | 校验文件头部 magic bytes PYVAULT4,过滤其他工具的同后缀文件 |
| 启动扫描元数据泄露 | 仅返回通过 magic 校验的文件,非 LynVault 文件不暴露其存在性 |
| 覆盖误删 | 提取全部前预检目标子文件夹,已存在时弹窗确认 |
| 密钥材料残留 | 加解密 / 密钥派生的所有错误路径均先 zeroize 中间量再返回(2.7.0 修补 derive_keys 提前返回路径),含密码的缓冲不留可恢复副本 |
| 创建覆盖已有保险柜 | 创建前校验目标路径:目录或 magic 匹配的保险柜文件直接拒绝(2.7.0);非保险柜文件覆盖仍需保存对话框显式确认 |
| 导入 TOCTOU / 无界分配 | 导入改为句柄化读取:按元数据封顶预分配 + take 限制读取总量,源文件中途膨胀不会触发无上界分配,超限内容零化后拒绝(2.7.0) |
| Windows 保留设备名 | 导入 CON.txt 等保留名文件时改用 verbatim(\\?\)路径打开,避免路径归一化把读取重写到控制台/空设备(2.7.0) |
| 密钥文件读取无界分配 | 按元数据预检 + take 限制读取总量(64 MiB 上限),与导入路径的句柄化读取同一策略(2.7.1) |
| 创建覆盖另一保险柜 | 创建以 create_new 优先:目标已存在时不会被清零;确认「已存在且非保险柜」(保存对话框已让用户确认覆盖普通文件)后才以 create+truncate 重开(2.7.1) |
| 销毁路径二次打开被拒 | 销毁全程交出会话句柄本身,不按路径二次打开;符号链接 / 重解析点的拒绝前移到会话打开阶段(2.7.1) |
| Office 口令计时侧信道 | Agile / Standard 口令校验恒定时间比较(ct_eq);口令派生全部中间量(pwd16/buf/h/tmp/h_final)用后即清零(2.7.1) |
| 恶意文档 CPU DoS / panic | Agile spinCount 上限 10 万(Office 默认值),超出按参数异常拒绝;解析阶段校验「摘要长度 ≥ 密钥长度」,SHA-1 + AES-192/256 的恶意参数不再触发越界 panic(2.7.1) |
| 单实例口令验证预言机 | 外部转发的打开请求先把完整目标路径显示给用户确认,拒绝即不采集口令(2.7.1) |
| 碎片整理中间副本残留 | 备份 copy 失败分支统一「先 DoD 擦除再删除」;整理前预检磁盘可用空间(约 2× 文件 + 4 MiB),不足时明确拒绝且不产生中间文件;恢复 rename 失败不再被静默吞掉(2.7.1) |
| 整理替换丢失文件 ACL | Windows 改用 ReplaceFileW(替换内容同时保留安全描述符/属性/创建时间),不支持时回退 rename;Unix rename 后还原 mode(2.7.1) |
| 启动失败无从排查 | build() 后手动创建主窗口,失败依次降级重试(透明 → 不透明 → 换备用 WebView2 数据目录 → 不透明),仍失败记日志并弹系统消息框;WebView2 数据目录改用 %LOCALAPPDATA%\LynVault\WebView2Data,不可用回退临时目录(2.7.1) |
| 文件关联反复改写 | .lyt 已注册且 open 命令指向当前 exe 时跳过注册与 SHCNE_ASSOCCHANGED 广播(exe 移动/替换后自然重新注册)(2.7.1) |
| 未锁屏时被改密锁死 | 修改密码必须验证当前密码(或密钥文件):防止他人在已解锁的机器上改密锁死真正的主人(2.8.0) |
| 包裹密钥调包 / 头部篡改 | v5 包裹体 AAD 绑定头部前缀(magic/版本/库盐)+ 条目别名 + 条目盐,调包或篡改必然解包失败;认证标签随新盐重算仍绑定头部(2.8.0) |
| v4→v5 升级中断损坏 | 复用碎片整理安全管线:磁盘预检 → 加密备份 → 临时文件重建 → ReplaceFileW 原子替换 → 失败回滚;备份/中间副本统一 DoD 擦除(2.8.0) |
| 升级时审计链被篡改 | 审计日志整链换钥前先用旧密钥硬校验,任何一条失败即中止升级(不静默截断)(2.8.0) |
| 截屏 / 录屏泄露 | 主窗口默认应用 SetWindowDisplayAffinity(WDA_EXCLUDEFROMCAPTURE):不出现在截屏/录屏/远程共享中(旧系统退化为黑块)(2.8.0,仅防软件抓屏) |
| 剪贴板明文残留 | 开柜期间监听并即时清空全系统剪贴板 + Win+V 历史;关柜自动恢复。副作用(已确认):开柜期间其他软件复制同样被清空(2.8.0) |
| 离开机器忘记锁柜 | 空闲 2 分钟自动锁定(可调/可禁用)+ 系统锁屏/睡眠/注销自动关闭(2.8.0,Windows) |
| 保险柜数据静默损坏 | 「完整性体检」逐文件校验 AES-GCM 认证标签,检出坏块/位腐/云同步损坏并给出异常清单(2.8.0) |
| 剪贴板保护静默失效 | 窗口类注册幂等化(ERROR_CLASS_ALREADY_EXISTS 视为复用)+ 监听窗口退出时 DestroyWindow,多次开关柜全程有效(2.8.1) |
| 剪贴板 stop/start 竞态挂起 | 监听线程先发布句柄再检查停止标志 —— stop() 在任意时刻执行都能送达退出消息,开柜路径不再可能被 join 卡死(2.8.1) |
| 升级/整理失败残留全库副本 | v4→v5 升级的原子替换纳入事务闭包:任何一步失败统一擦除 .tmp/.bak 并重开原文件;替换已提交后的重开失败如实告知「改密已生效请重开」而非误报失败(2.8.1) |
| 单实例预检 NTLM 泄露 | magic bytes 预检拒绝 UNC / 设备路径(\server\share、\.\device):本地恶意进程无法借预检免交互触发 SMB 认证(2.8.1) |
| 改密对话框被系统锁定误关 | vault-locked 仅在确实关闭了保险柜时发射;前端仅 vaultOpen 时处理;对话框关闭时清空 DOM(密码不残留)(2.8.1) |
| 启动流程遮罩死锁 | 密码框注册取消回调,遮罩点击关闭对话框同样触发 onCancel —— _startupProcessing 不再卡死(2.8.1) |
| file/folder 同名碰撞 | 导入/新建文件夹路径交叉检查两个命名空间,拒绝 /a 同时为文件与文件夹(2.8.1) |
| v5 密钥材料错误路径残留 | KEK / data_key / 会话密钥副本全面 Zeroizing 化:派生失败 ? 早退、篡改中止、改密取消等所有路径密钥随 drop 清零(2.8.1) |
| GDI 句柄泄漏 | 系统图标读取的 hbmColor/hbmMask 以 RAII DeleteObject(旧实现每次新扩展名泄漏 2 个句柄)(2.8.1) |
| 分块密文截断 / 重排 / 跨文件块调包 | v6 每块的 AAD 绑定「冻结虚拟路径 + 块序号 + 总块数」:删块后长度与索引布局矛盾即拒绝,块交换因 vpath 不匹配必然认证失败(3.0.0) |
| 分块布局参数注入(恶意索引) | 块数 / 块长的长度反推全程 checked 运算,末块明文长度必须落在 (0, 块大小] 区间,越界即拒绝(3.0.0) |
| 胁迫场景下隐藏分区被带出 | 胁迫触发在返回会话之前完成其他分区条目的随机覆写;覆写 I/O 失败时开柜直接失败(fail-closed,宁可可疑报错)(3.0.0) |
| 他人在已解锁机器上恶意设置胁迫标记 / 误降级二因子 | 标记 / 解除 / 二因子启停均要求当前分区密码验证(响应参与验证路径);「修改密码」在启用二因子却未提供钥匙触摸时明确拒绝(3.0.0) |
| 硬件密钥响应被伪造 / 重放 | 响应为钥匙内部密钥对「盐派生挑战」的 HMAC-SHA1 计算,无法离线伪造;响应仅作为 KEK 混合输入,不落盘不落日志。3.0.1:响应不离开后端进程(开柜/改密等命令现场挑战硬件),被攻陷 WebView 无法索取响应字节;挑战盐终生不变,对旧文件快照的「重放」因此无从绕过钥匙在位要求(3.0.0/3.0.1) |
| 二因子状态在头部暴露(「哪个分区更值钱」) | 零格式变更设计:启用二因子只改变包裹 KEK 的派生方式,头部条目结构与普通分区完全一致,无任何标志位(3.0.0) |
| Tauri 2 权限面过宽 | capabilities 细粒度声明:opener 仅允许 GitHub 仓库 URL,窗口动作逐项授权,对话框经插件权限集(3.0.0) |
| 审计尾部截断 / 索引回滚不可检 | 头部保留区审计计数锚点:开柜比对索引实际条目数,不一致显式告警。3.0.1 如实更正:锚点不在 auth_tag 绑定范围内(保留区按规范形置零重建),头部签名在多分区场景只校验不强制 —— 锚点是尽力而为的告警提示,攻击者需回滚整个文件才能绕过(全文件回滚窗口见「已知限制」)(3.0.0/3.0.1 更正) |
| 密钥被换出到 pagefile | 会话密钥装箱 + VirtualLock/mlock 驻留,Drop 先解锁再清零;锁页失败降级为装箱 + 清零(3.0.0) |
| 流式预览被用作批量读取原语 | 预览凭会话级令牌(关柜作废、上限 64 个)+ 扩展名白名单 + 仅分块布局 + 单窗口 16 MiB 封顶;信任模型与 load_file_content 一致(3.0.0) |
| 播放器磁盘缓存残留明文 | 响应 Cache-Control: no-store 禁止 WebView 磁盘缓存;明文仅存在于播放进程内存(3.0.0) |
| 提取中间目录符号链接 TOCTOU | 打开后句柄级回验完整路径仍在目标根内(NO_FOLLOW 仅保护最终组件);窗口收敛到毫秒级(3.0.0 复核) |
| create 覆盖分支硬链接检查 fail-open | API 失败时 fail-closed(拒绝覆盖)——防线方向统一(3.0.0 复核) |
| 提取文件名 RTL 视觉伪装 | sanitize_filename 剔除 U+202A..E / U+2066..9 方向控制字符(3.0.0 复核) |
| GCM 认证失败路径明文残留 | decrypt_into 就地清零后返回 None(aes-gcm 先经 CTR 变换再验标签,失败时缓冲已含明文等价输出)(3.0.0 复核) |
- 在 ZFS/Btrfs/APFS 等写时复制文件系统上,DoD 7-pass 擦除可能写入多个物理副本而非覆写同一物理块。这是文件系统层面的固有限制,建议在 ext4/NTFS 上使用以获得最佳擦除效果。
- 内存硬性 KDF 在低内存设备上可能耗时较长(每次认证约 0.1s);打开时恒定执行 8 次 Argon2id(分区数上限),单分区保险柜打开约需 1s 左右,这是恒定时间与分区计数隐藏的必要代价。
- 防暴力锁定针对「在线猜测 / 误输密码」场景:拥有文件写权限的攻击者可伪造「未锁定」记录(与其直接破坏文件同级);离线复制文件暴力破解不受锁定影响(所有密码库皆然)。
- 跨重启后锁定状态依赖系统时钟(单调时钟不持久化),回拨系统时钟可提前解除锁定,需要文件写权限,与伪造锁定区同级。
- 分区别名以明文存储于头部(分区管理功能需要),真实分区数量可通过解析头部推断;未使用条目填充随机数据使其与真实条目结构不可区分。
- 删除伪装分区时仅能擦除其索引区:该分区的文件密文因无分区密码无法定位,无法一并擦除;保险柜整体销毁时会一并擦除。
- 单文件上限:v6 保险柜导入/提取 1 TiB(分块流式,内存恒定);v4/v5 保险柜及 v6 存量 Legacy 条目为 256 MiB(整段加解密的内存固有限制)。应用内预览/加载上限 256 MiB(IPC 传输限制),Office 预览文本上限 64 MiB,超出请提取后查看;文本编辑上限 4 MB(超过自动只读预览,防止超大 textarea 卡死 WebView)
- 非 UTF-8 编码的文本文件(如 GBK 编码的 TXT)只读预览不提供编辑 —— 保存会以替换字符固化原编码损坏;如需编辑请先在应用外转换为 UTF-8 再导入
- 加密 Office 文档的 Agile
spinCount上限为 10 万(Office 默认值):声称更高迭代参数的文档(含恶意构造)将被按参数异常拒绝预览 - 加密 Office 预览支持 Office 2007 的 Standard Encryption 与 Office 2010+ 的 Agile Encryption(AES 系列;RC4 加密与 .pptx 不支持预览,2.7.0 起移除 pptx)。文档口令经 IPC 传输(与保险柜主密码同一信任模型),解密纯内存进行、用后即清零
- 碎片整理:单分区走紧凑整理(物理文件直接缩小);多分区采用「保守整理」—— 仅重写活跃分区、不截断文件(其他分区数据位置未知),旧数据区以 DoD 7-pass 逻辑擦除。删除后自动整理(2.7.0)同样仅单分区启用(多分区整理无空间收益,保持手动)。
- v5 格式(2.8.0)旧版本 LynVault 无法打开:v4 保险柜执行「修改密码」时自动升级为 v5(一次性全库重加密,耗时与保险柜体积成正比,磁盘需约 2× 剩余空间);升级前请确认磁盘空间充足。多分区 v4 保险柜不支持自动升级(其余分区口令未知,无法生成包裹密钥)。
- 空闲自动锁定(2.8.0)以「应用窗口内无鼠标/键盘输入」计时:在其他应用里长时间操作同样会计时并锁定本应用。
- 完整性体检(2.8.0)执行期间持有保险柜会话锁:扫描完成前其他保险柜操作(含关闭)将排队等待;进度事件已按时间节流(2.8.1)。
- 防截屏(2.8.0)仅防软件抓屏(截屏 / 录屏 / 远程共享 API),无法阻止物理拍摄;该功能为 Windows 专属。
- 剪贴板保护(2.8.0)为 Windows 专属:开柜期间全系统剪贴板内容即时清空(含 Win+V 历史),在其他软件里复制的内容同样被清空;已清空内容不可恢复。
- 系统锁屏 / 睡眠 / 注销自动关闭(2.8.0)为 Windows 专属(Linux 桌面的 logind 事件暂未支持);睡眠触发时的关闭为尽力而为(受系统给应用的处理时间窗限制,索引落盘沿用崩溃安全顺序,中断不会损坏文件)。
- 口令经 Tauri IPC 传输:
String在 WebView JS 堆、IPC JSON、serde 反序列化缓冲中存在多份无法零化的副本,命令层的zeroize只覆盖最后一跳 —— 这是 Tauri 架构限制(3.0.0 已迁移 Tauri 2,该限制本质不变),信任模型上与「本机存在恶意同用户进程即全面失守」一致(2.8.2 起在文档中如实声明)。 - 索引虚拟路径键大小写敏感:
/A.txt与/a.txt可共存(Linux 语义)。3.0.1(#30)起创建/改名/移动路径在同父目录做大小写不敏感查重(保险柜文件可能跨机器迁移,检查在所有平台生效),存量柜中的历史共存条目不受影响 —— 提取到 Windows 时仍按「目标已存在」失败计数反馈,覆盖需显式确认。 - vpath 允许
:等字符(仅禁控制字符/反斜杠/点段):提取时由文件名清洗兜底,柜内名与落地名可能因清洗而不同。收紧字符集会使存量保险柜中含此类字符的条目无法访问,故保持宽松。 - v6 格式(3.0.0)旧版本 LynVault 无法打开(v4/v5 保险柜继续兼容);注意修改密码(含 v4→v6 升级重加密)不保护已被攻击者事先复制的旧副本——旧密文仍可用旧口令解,这是所有改密码实现的固有语义;v5 执行「修改密码」即自动升级 v6(仅头部重写、秒级,旧版将无法再打开该柜);v4 改密码直达 v6(一次性全库重加密,需约 2× 磁盘空间)。v6 保险柜中的存量 v4/v5 时代文件保持 Legacy 整段布局,其单文件 256 MiB 内存上限依旧适用;新导入文件(非空)一律分块布局(上限 1 TiB)。
- 胁迫密码为不可逆机制(3.0.0):用胁迫分区密码开柜成功 = 其他所有分区数据永久销毁(条目被随机覆写,无任何找回手段);主分区数据以密文形态残留但不可解密,仅整体销毁可一并擦除。设置前请务必使用演练模式。
- 开柜失败递增锁定计数(3.0.0 复核):被攻陷的 WebView 可对已知保险柜路径反复调用 open_vault(受 3 秒认证冷却约束)触发 5 次失败锁定 30 分钟、到期续锁 —— 把「写锁定区」这一文件系统能力扩展到了渲染层;正确密码到期后仍可打开(DoS 而非永久锁死)。缓解:保险柜路径不向不可信来源暴露。
- 3.0.0 二因子保险柜砖化(3.0.1 已修复,存量受损柜不可逆):3.0.0 的「开柜轮换挑战盐」存在致命缺陷 —— 启用二因子并再次成功开柜后,data_key 仍包裹在旧盐响应之下,下一次打开即永久 AuthFailed(盐已被覆写,旧响应无法重算,且任何重新包裹路径都要求会话已打开)。3.0.1 取消轮换并附连续重开回归测试。已受损的柜只能从备份 / 网盘历史版本恢复,或在受损前会话尚存活时立即导出数据。缓解:使用 3.0.1 及以上版本。
- 全文件回滚窗口(已知取舍,3.0.0 M-3 复核如实声明):持有旧版本完整副本的攻击者(云同步回灌 / 备份还原场景)可把保险柜整体回滚到旧状态 ——
index_offset/length不在认证标签 / 包裹 AAD / 锁区 HMAC 的覆盖范围内,头部签名又因多分区跨签名不能硬拒。头部内状态无法根治此窗口(曾设想的 generation 计数器经复核未引入 v6);离线持有单一文件的暴力破解者同样不受影响(所有密码库皆然)。缓解:保险柜文件不放在自动双向同步的目录中。 - v6 随机 nonce 用量假设(R2 说明):每块(4 MiB)使用独立随机 96-bit nonce,同一分区 data_key 共享。按 NIST SP 800-38D 随机 IV 的 2³² 次加密边界,需写满约 16 EiB 才触及 —— 当前单文件 1 TiB 上限下余量巨大。勿把 CHUNK_SIZE 调小一个数量级以上、勿跨保险柜复用 data_key,否则需重新评估。
- 头部写入撕裂保护(3.0.1 #1 修复,原「头部写入非原子」):所有对已存在保险柜的原地头部更新(改密 / 索引落盘 / 增删分区 / 锁定计数)现经日志边车(
<保险柜>.hdr.journal)三步协议 —— 完整新头部快照先落盘,再原地覆写,成功后删日志;任意一步中断,下次打开自动收敛(日志完好 → 恢复/完成写入;日志撕裂 → 清理)。残余限制:日志边车在文件同目录多出一个.hdr.journal文件(含完整头部字节,无密钥不可解读),且恢复依赖「下一次打开」发生 —— 若撕裂后文件从未被打开,边车保持待恢复状态(无副作用)。 - 胁迫触发的可观测性:触发时额外重写一次头部(约 2 KiB);对磁盘监控型取证而言与普通开柜后修改头部无法区分,但不伪装成「毫无写入」。
- 开柜内存峰值:8×Argon2id 各 64 MB ≈ 512 MB 峰值(低配机器按核数回落,1 核仅 64 MB);极低内存设备分配失败时 Rust 分配器直接 abort(不可捕获)→ 进程退出,无数据损坏(崩溃安全顺序未涉及内存)。
- 硬件密钥二因子(3.0.0)为可选项:YubiKey 槽 2 需预先配置为 HMAC-SHA1 挑战-响应凭证;钥匙丢失且响应不可复现时该分区数据永久无法打开;钥匙在位校验失败(未配置槽位 / 未触摸)按开柜失败处理。PC/SC 服务不可用时设备探测静默降级为「不在位」,不影响纯密码路径。
- Tauri 2(3.0.0)在 Linux 侧要求
libwebkit2gtk-4.1(此前为 4.0);口令经 IPC 存在多份副本的 Tauri 架构性限制在 v2 下依然存在(raw IPC 只覆盖部分路径),信任模型不变。
- CI 门禁:
.github/workflows/ci.yml—— 每次 push / PR 自动执行 rustfmt 检查 → clippy(警告即失败)→ 双平台测试(vault-core 在 Linux + Windows,应用层在 Windows)→ cargo-deny(依赖漏洞 / yanked / 许可证 / 来源) - 工具链:
rust-toolchain.toml钉死版本(含 rustfmt / clippy 组件),本地与 CI 完全一致 - 兼容性守卫:
tests/fixtures/内置 v4 / v5 二进制夹具(已知密码与内容),每次测试运行都重新打开并逐字节校验 —— 老版本保险柜「永远打得开」由 CI 而非记忆保证;夹具由LYNVAULT_GEN_FIXTURES=1 cargo test generate_compatibility_fixtures重新生成 - 供应链:
deny.toml声明许可证白名单与来源限制,yanked 版本直接拒绝 - 前端运行时冒烟:
ui/smoke-check.js—— 用 DOM/Tauri 桩真实执行前端初始化全链与对话框按钮链路(启动弹窗类副作用 / 启动列表渲染 / 拖放注册 / 列表渲染链 buildFileRow→mountRows / 胁迫与硬件密钥子对话框可点性 / 回车提交密码),语法检查抓不到的运行时回归由此防线兜底;CI 第 5 道 job 每次提交执行(3.0.1 #34 补齐 —— 此前仅文档宣称,CI 未运行) - 模糊测试:
fuzz/内置四个 cargo-fuzz 靶子 —— Office 文档解析(最不可信输入面)、保险柜头部公开字段解析、加密索引反序列化、索引布局算术(3.0.1 新增);每周 CI 定时冒烟(60 秒/靶)+ PR 算术靶 30 秒冒烟,崩溃输入自动上传为 artifact;nightly 与依赖解析均已钉死(3.0.1 #38 落实)
# 安装 Tauri CLI
cargo install tauri-cli
# 在 src-tauri/ 下直接构建可执行文件(前端资源已内嵌,产物为单文件)
cargo build --release
# 或构建发布版安装包(NSIS/MSI)
cargo tauri build产物:target/release/LynVault.exe。单文件即可运行,无需安装;目标机器需具备 WebView2 Runtime(Win 10 1803+ 通常已预装)。
无 Windows 机器时可在 Linux 上交叉编译(已验证):
cargo install cargo-xwin、rustup target add x86_64-pc-windows-msvc后于src-tauri/执行cargo xwin build --release --target x86_64-pc-windows-msvc,得到target/x86_64-pc-windows-msvc/release/lynvault-rs.exe(PE32+ GUI,图标 / 版本信息 / manifest 均已嵌入,可直接改名为LynVault.exe分发)。宿主机需具备clang-cl、lld-link、llvm-rc(或windres)与makensis(仅打包安装包时需要)。
# 构建依赖(Debian/Ubuntu,3.0.0 起 Tauri 2 需要 webkit2gtk-4.1)
sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev \
build-essential curl wget file libssl-dev libpcsclite-dev
cargo install tauri-cli
cd src-tauri && cargo tauri build --bundles deb产物:target/release/bundle/deb/lyn-vault_<版本>_amd64.deb。安装:
sudo dpkg -i lyn-vault_<版本>_amd64.deb # 若提示依赖缺失,执行 sudo apt-get -f install安装后由 /usr/share/mime/packages/lynvault.xml 与 lyn-vault.desktop 将 .lyt 注册为 application/x-lynvault-vault,双击 .lyt 直达密码输入;文件列表使用内置文件类型图标。运行时依赖含 libpcsclite1(YubiKey 硬件密钥功能;缺省安装不影响其余功能)。
通用
- Rust 工具链(rustup,版本由
rust-toolchain.toml钉死)+ MSVC Build Tools(Windows) - 复现验证:
cargo fmt --check && cargo clippy --workspace -- -D warnings && cargo test
Windows
- Windows 10 1803+
- WebView2 Runtime(Win 10 1803+ 通常已预装)
- 构建产物:
target/release/LynVault.exe(workspace 根目录 target);发布产物复制到仓库根目录(LynVault-<版本>-win64.exe,32 位为-win32.exe)
Linux
- 面向 Debian/Ubuntu 的
.deb,运行时依赖libwebkit2gtk-4.1-0、libgtk-3-0(3.0.0 起切换到 webkit2gtk-4.1;安装包已声明,apt 自动解析) - 构建产物:
target/release/bundle/deb/lyn-vault_<版本>_amd64.deb;或用仓库根目录的build-deb.sh手工组装(.deb 输出到仓库根目录)