使用 Rust + iced 原生实现的跨平台 GUI 工具,用于生成目录摘要,并根据摘要检查目录中的文件或子目录是否被增加、删除、修改或改变类型。
目录遍历、XXH3-128 流式哈希、摘要解析、自校验和差异比对全部由 Rust 实现,不调用归档的 C/C++ 代码。
另提供可部署到 Cloudflare Pages 的浏览器版本:本地文件由 Rust WASM 分块摘要,摘要文本交给 Cloudflare Worker 使用 Ed25519 私钥签名。部署、安全边界和使用说明见 cloudflare/README.md。
- 读取摘要文件:选择已有的
.dirverify摘要并显示。 - 生成摘要文件:选择目录后扫描普通文件和所有子目录,包括空目录。
- 生成签名密钥:使用操作系统安全随机数生成 Ed25519 私钥和公钥。
- 根据摘要验证目录:使用当前显示的摘要检查所选目录,结果通过弹窗显示。
- Ctrl+S 保存并签名:选择 ZIP 路径和私钥,生成与 Web 版一致的“目录名.dirverify.sign.zip”,其中包含摘要和签名两个文件。
- 摘要显示区域不自动换行;内容超出宽度或高度时自动提供水平、垂直滚动条。
- 扫描和校验使用 iced 后台任务,操作期间会暂时禁用按钮。
程序明确区分三种结论:
校验通过 目录内容与摘要一致
校验失败 发现缺失、新增、修改或类型变化
校验未完成 存在无法读取的路径,本次结果不可信
“无法读取”和“没有变化”不会被混淆。即使未完成的扫描同时发现了一些差异,最终结论仍是“校验未完成”。
签名 ZIP 可以保存在被校验目录内。生成后保存或执行校验时,程序会自动排除该 ZIP,避免把它记录进摘要或误报为新增文件。读取旧式摘要时仍兼容相邻的 .dirverify 和 .dirverify.sign 两个文件。
读取摘要和执行目录校验都强制验证 Ed25519 签名。签名文件缺失、签名无效、公钥不匹配或磁盘摘要在读取后发生变化时,程序会拒绝继续校验。
需要 Rust 1.88 或更高版本。
cargo run --release仅构建:
cargo build --release产物位置:
- Linux/macOS:
target/release/dir_integrity_check - Windows:
target\release\dir_integrity_check.exe
Linux 使用 XDG Desktop Portal 打开文件和目录选择对话框。常见 GNOME、KDE 桌面通常已安装对应后端;精简桌面环境可以安装 zenity 作为回退。
- 首次使用时点击“生成签名密钥”,分别保存私钥和公钥。
- 把私钥放在安全位置;不要放入被校验目录,也不要交给验证方。
- 点击“生成摘要文件”,选择需要生成摘要的目录。
- 等待摘要内容显示完成。
- 按
Ctrl+S选择 ZIP 保存路径,然后选择用于签名的私钥。
假设选择的目录是:
/data/example
默认保存路径为:
/data/example.dirverify.sign.zip
ZIP 内包含:
example.dirverify
example.dirverify.sign
需要在以后重新读取该摘要时,先解压 ZIP,再通过“读取摘要文件”选择其中的 .dirverify;程序会读取同目录下对应的 .dirverify.sign。
- 确保
.dirverify和对应的.dirverify.sign位于同一目录。 - 点击“读取摘要文件”,选择摘要。
- 选择来自可信来源的 Ed25519 公钥。签名无效或签名文件缺失时,摘要不会被载入。
- 点击最右侧的“根据摘要验证目录”。
- 程序再次读取摘要和签名并重新验证,然后才允许选择要检查的目录。
- 在弹窗中查看校验结论和具体差异。
刚生成但尚未保存签名 ZIP 的摘要不能用于目录校验。保存成功后,程序会在校验前重新读取 ZIP 内的摘要和签名并验签。
读取时找不到签名文件或公钥会提示“读取摘要失败,未找到签名”;签名格式无效、公钥不匹配或摘要被修改会提示“读取摘要失败,验签未通过”。
目录验证前的二次验签采用相同分类,分别提示“验证摘要失败,未找到签名”或“验证摘要失败,验签未通过”,并拒绝选择校验目录。
摘要继续使用 #dirverify 1 行式文本格式,与归档的 C++ 版本兼容:
#dirverify 1
#algo xxh3-128
#root example
#created 2026-07-30T00:00:00Z
#entries 2
d 0 - empty
f 3 06b05ab6733a618578af5f94892f3950 a.txt
#trailer xxh3-128 ...
- 条目按相对路径的 UTF-8 字节序排序。
- 普通文件记录文件大小和 XXH3-128 内容摘要。
- 目录是独立条目,因此可以检测空目录的增加和删除。
- 路径中的反斜杠、换行、回车和制表符会被转义。
#trailer覆盖前面的全部字节,可检测摘要截断或意外损坏。- 读取摘要时会先验证尾部摘要和条目数量,再执行目录校验。
签名覆盖 .dirverify 文件的全部原始字节,签名文件格式为:
#dirverify-signature 1
#algorithm ed25519
#signature <128 位十六进制签名>
签名文件不内嵌公钥。验证时必须由用户选择可信公钥,防止攻击者同时替换摘要、签名和公钥。
生成的私钥文件在 Unix 系统上会设置为仅当前用户可读写(0600)。私钥仍是未加密文件,必须单独、安全地保管;公钥可以分发给验证方,建议通过可信渠道核对。
记录并校验:
- 普通文件的内容摘要和大小
- 目录,包括空目录
不记录:
- 权限、时间戳、所有者
- 符号链接
- socket、FIFO 和设备文件
符号链接和特殊文件虽然不参与摘要,但扫描时会计数。遇到不可读文件、不可读目录或无法写入文本摘要的非 Unicode 路径时,程序不会给出“校验通过”的结论。
XXH3-128 用于高效检测目录内容变化,#trailer 用于发现摘要文件的意外损坏;两者都不是防伪机制。防篡改能力由 Ed25519 签名提供,其前提是私钥没有泄露,并且验证者选择的是可信公钥。
cargo test --all-targets
cargo clippy --all-targets -- -D warnings测试覆盖摘要往返解析、摘要损坏检测、旧 C++ 摘要兼容、签名 ZIP 读写、Ed25519 签名、签名缺失和篡改拒绝、目录差异分类、目录内输出排除和未完成扫描结论。
.
├── Cargo.toml
├── Cargo.lock
├── src/
│ ├── main.rs iced GUI、文件对话框和快捷键
│ ├── lib.rs 摘要生成、保存和校验入口
│ ├── archive.rs 摘要与签名 ZIP 的生成和严格读取
│ ├── manifest.rs 摘要序列化、解析和尾部自校验
│ ├── scanner.rs Rust 原生目录遍历和文件哈希
│ ├── signature.rs Ed25519 密钥、签名和严格验证
│ └── verifier.rs 差异比较、折叠和结果报告
├── cloudflare/
│ ├── wasm/ 浏览器端 Rust WASM 摘要生成器
│ ├── worker/ Rust Ed25519 签名 Worker
│ └── web/ Cloudflare Pages 前端与 Service Binding
└── cpp_archive/ 已归档、可独立构建的旧 C++ 版本
归档 C++ 版本的说明和 CMake 工程位于 cpp_archive/。