macOS 本地加密文件空间
Hello Privacy 是一个原生 macOS 应用,在本地创建独立的加密文件空间。所有文件使用 AES-256-GCM 逐文件独立加密,密码经 macOS Keychain 存储并受 Secure Enclave 硬件保护。应用不包含网络通信代码,不收集任何用户数据。
用户密码经 SHA-256 哈希后,通过 HKDF-SHA256 派生 256 位对称密钥。每个文件空间在初始化时生成 32 字节密码学随机盐(SecRandomCopyBytes),盐值持久化至 ~/.HelloPrivacy/salt.dat。HKDF 的 info 参数固定为 HelloPrivacy-AES256。
SymmetricKey = HKDF<SHA256>(
inputKeyMaterial: SHA256(password.utf8),
salt: SecRandom(32 bytes),
info: "HelloPrivacy-AES256",
outputByteCount: 32
)
派生密钥仅在解锁期间存在于进程内存,锁定时立即调用 clearSessionKey() 销毁。
每个文件使用 AES-256-GCM 独立加密。CryptoKit 为每次 AES.GCM.seal() 调用自动生成 96 位随机 nonce,输出 combined 格式的 SealedBox(nonce 12B + ciphertext + GCM tag 16B)。
文件 >= 10 MB 时自动启用分块加密,每块 1 MB 独立加密,各块拥有独立的 nonce 和 GCM 认证标签:
[chunk_count: UInt32 LE (4B)]
[chunk_0_len: UInt32 LE (4B)] [AES-GCM SealedBox (nonce + ciphertext + tag)]
[chunk_1_len: UInt32 LE (4B)] [AES-GCM SealedBox (nonce + ciphertext + tag)]
...
单块文件(< 10 MB)省略 chunk_len 字段,直接存储一个 SealedBox。
加密后的文件以 UUID 命名并附加 .enc 扩展名存储在 ~/.HelloPrivacy/vault/,原始文件名和目录结构记录在元数据中,元数据本身同样经 AES-GCM 加密后写入 metadata.enc。
密码本身不存储在任何位置。Keychain 中仅保留 SHA-256 哈希摘要:
kSecClass: kSecClassGenericPassword
kSecAttrService: "com.helloprivacy.keychain"
kSecAttrAccount: "passwordHash"
kSecAttrAccessible: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
Value: SHA256(password.utf8) // 32 bytes
WhenUnlockedThisDeviceOnly 确保哈希仅在设备解锁时可读,且不会通过 iCloud Keychain 同步到其他设备。
文件删除时,先通过 SecRandomCopyBytes 生成密码学随机数据,以最大 1 MB 缓冲区循环覆写文件磁盘数据,调用 synchronizeFile() 强制刷盘后再删除文件索引。
密码更换执行全量重加密。分别用旧密码和新密码派生两把密钥,通过 reencryptFile() 对每个文件执行解密-重加密。写入 vault_new/ 和 metadata_new.enc 后,执行原子交换(vault_new → vault),失败时从 vault_old/ 回滚。过程中检查磁盘空间需满足 vault_size + 50 MB。
Password
│
├─→ SHA-256 hash ─→ Keychain (kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
│
└─→ HKDF<SHA256>(hash, salt, "HelloPrivacy-AES256", 32) ─→ SymmetricKey (进程内存)
│
┌───────────┴───────────┐
▼ ▼
AES-256-GCM AES-256-GCM
文件加密/解密 元数据加密/解密
│ │
▼ ▼
~/.HelloPrivacy/vault/*.enc metadata.enc
| 机制 | 实现 |
|---|---|
| 自动锁定 | 双通道事件监听(Global + Local NSEvent Monitor),30 秒间隔检查空闲时间 |
| 暴力破解防护 | 连续 5 次失败后内存锁定 60 秒 |
| 密码强度评估 | 三级实时评估(弱 / 中 / 强) |
| 文件安全删除 | SecRandomCopyBytes 单次覆写 + synchronizeFile() 刷盘 |
| 网络隔离 | 无网络通信代码,无 URL 请求,无远程依赖 |
Hello Privacy 在 ~/.HelloPrivacy/ 下维护一个加密文件空间,提供类 Finder 的文件管理体验:
- 三种视图 — NSCollectionView(图标)/ NSTableView(列表)/ NSBrowser(分栏)
- 多窗口 — NSWindowController 窗口级联
- 文件预览 — 内置预览面板,选中文件临时解密到缓存目录预览
- 拖拽 — NSPasteboard + NSFilePromiseProvider,从 Finder 拖入自动加密,拖出自动解密
- 文件夹嵌套 — VaultItem 递归树结构,支持任意深度目录
~/.HelloPrivacy/
├── vault/ # 加密文件存储(UUID.enc)
├── metadata.enc # 加密元数据(JSON → AES-GCM sealed)
├── salt.dat # 32 字节随机盐(明文)
└── 保险库/ # Free+ 模式临时明文目录(仅解锁期间存在)
元数据使用 JSONEncoder(.iso8601 日期格式)序列化后整体加密,记录所有文件/文件夹的名称、层级关系和对应的加密文件名。
Hello Privacy 提供两种运行模式,在首次引导时选择,后续可通过设置切换。两种模式共享同一加密存储和安全架构,区别在于文件的访问方式。
Standard 模式 — 文件始终以密文形态存在于磁盘。所有文件操作(浏览、预览、导入、导出)在应用内完成,按需对单个文件解密到临时缓存,操作完成后清除缓存。加密文件存储在 ~/.HelloPrivacy/vault/ 下,以 UUID.enc 命名,原始文件名仅存在于加密元数据中。
Free+ 模式 — 解锁时由 FreePlusManager 执行批量解密,将 vault/ 下所有加密文件还原为明文目录结构,写入 ~/.HelloPrivacy/保险库/,随后在系统 Finder 中直接操作。锁定或退出时执行反向流程:
解锁 (Unlock)
1. 清空临时目录
2. 遍历元数据树,构建 (VaultItem, relativePath) 映射
3. 批量创建目录结构
4. 逐文件调用 EncryptionManager.decryptFile() → 保险库/
锁定 (Lock)
1. 扫描临时目录,重建元数据(文件可能被用户增删改)
2. 检查磁盘空间 >= vault_size + 50 MB
3. 逐文件加密到 vault_new/
4. 加密新元数据 → metadata_new.enc
5. 原子交换:vault_new → vault, metadata_new → metadata
6. 失败回滚:vault_old → vault, metadata_old → metadata
7. SecureDelete.deleteDirectory(保险库/)
崩溃恢复:应用启动时检测 保险库/ 目录是否残留明文文件(isTempPopulated()),若存在则提示用户选择重新加密收回或丢弃。
文件空间可导出为 .hpvault 加密归档。自定义二进制格式,所有整数使用 little-endian 编码:
Offset Size Field
0 8 B Magic: 0x48 0x50 0x56 0x41 0x55 0x4C 0x54 0x00 ("HPVAULT\0")
8 4 B Version: UInt32 (= 1)
12 4 B Salt length: UInt32
16 N B Salt data
16+N 8 B Metadata length: UInt64
24+N M B Metadata: AES-GCM sealed (JSON)
24+N+M 4 B File count: UInt32
28+N+M ... File entries (repeated):
├─ 4 B Filename length: UInt32
├─ L B Filename: UTF-8
├─ 8 B Data length: UInt64
└─ D B Data: AES-GCM sealed (与 vault/*.enc 格式一致)
归档内的文件数据与 vault/*.enc 使用相同的加密格式(chunk count header + chunked SealedBox),读写均以 1 MB 流式分块,内存占用恒定。
系统要求:macOS 14.0 Sonoma+,Apple Silicon / Intel
下载:Releases
从源码构建:
git clone <repository-url>
cd HelloPrivacy
xcodebuild -project HelloPrivacy.xcodeproj -scheme HelloPrivacy -configuration Release build纯 Swift,无第三方依赖。
HelloPrivacy/
├── App/
│ ├── AppDelegate.swift # 应用入口、窗口管理、菜单
│ └── AppConstants.swift # 全局常量
├── Managers/
│ ├── EncryptionManager.swift # AES-256-GCM 加密引擎
│ ├── PasswordManager.swift # Keychain 密码管理
│ ├── VaultManager.swift # 文件空间核心操作
│ ├── VaultArchiver.swift # .hpvault 归档读写
│ ├── SessionManager.swift # 空闲检测与自动锁定
│ └── FreePlusManager.swift # Free+ 模式管理
├── Controllers/ # 窗口与视图控制器 (8)
├── Views/ # SwiftUI 视图 (8)
├── Models/ # 数据模型
├── Utilities/ # 安全删除、文件类型识别
└── Resources/ # 图标、本地化
| 层 | 技术 |
|---|---|
| UI | AppKit + SwiftUI |
| 加密 | CryptoKit(AES-GCM / HKDF / SHA256) |
| 凭据 | Security.framework(Keychain Services) |
| 文件视图 | NSCollectionView / NSTableView / NSBrowser |
| 拖放 | NSPasteboard + NSFilePromiseProvider |
| 快捷键 | 操作 |
|---|---|
⌘N |
新建窗口 |
⇧⌘N |
新建文件夹 |
⌘I |
导入 |
⌘E |
导出 |
⇧⌘E |
导出归档 |
⇧⌘O |
打开归档 |
⌘⌫ |
删除 |
⏎ |
重命名 |
⌘1 ⌘2 ⌘3 |
图标 / 列表 / 分栏 |
⇧⌘P |
预览面板 |
⌘L |
锁定 |
⌘, |
设置 |
| 版本 | 日期 | 变更 |
|---|---|---|
| v5.0 | 2026-04 | Free+ 模式、统一设置面板、自动锁定配置、深浅色适配 |
| v4.0 | 2026-03 | 加密文件空间概念重构、引导流程重写 |
| v2.1 | 2026-03 | 密码修改、.hpvault 归档、归档浏览器 |
| v2.0 | 2026-02 | 架构重写:AES-256-GCM + Keychain + 多窗口 |
| v1.0 | 2025-12 | 初始版本 |
- 加密操作基于 Apple CryptoKit,依赖 FIPS 140-2 验证的实现
- 密码哈希通过 macOS Keychain 存储,受 Secure Enclave 硬件保护
- 加密密钥仅存在于会话进程内存中,锁定后立即清除
- 文件删除执行
SecRandomCopyBytes覆写 +synchronizeFile()刷盘 - 不包含网络通信代码,不收集用户数据
- 密码更换执行原子性全量重加密,失败时从备份回滚
- Linux.do - 讨论