A zero-knowledge file vault designed for NAS. The Rust/Axum backend only stores and transmits ciphertexts; the master password, recovery key, vault key, file keys, file names, MIME types, and plaintext contents only exist in the browser or future native apps.
A random 256-bit vault key is generated during client initialization. It is responsible for wrapping each file's random key and encrypting metadata and thumbnails. The vault key is further wrapped by two independent sets of credentials:
The server only stores two wrapped copies of the vault key along with the SHA-256 verification values for the authentication tokens. Changing the master password forces the generation and rotation of the recovery key, and the server atomically replaces both new credentials; only the vault key needs to be re-wrapped, with no need to rewrite files.
Each file uses an independent, random 256-bit file key, encrypted using XChaCha20-Poly1305 in fixed 1 MiB blocks. AAD binds the file ID, purpose, and plaintext offset, preventing ciphertext blocks from being swapped across files or locations. Metadata such as file names in the server database are also ciphertexts.
This guarantees that cloning NAS hard drives, database leaks, or even reading the memory of a running Rust service process cannot expose the vault key or plaintext. The web still has inherent boundaries: an attacker with long-term control over the NAS can tamper with subsequently loaded web pages/WASM to trick the next unlock; signed Android/iOS clients will provide stronger resistance against this.
The server still sees file counts, ciphertext sizes, upload timestamps, access IPs, and request timing, and can delete or block data if compromised. Zero-knowledge protects confidentiality and tamper detection, which does not replace offline backups and availability protection.
Generate a one-time initialization token and create .env:
openssl rand -base64 32
Fill the output into VAULT_SETUP_TOKEN, then start:
services:
charming-locker:
image: charmingcheung000/charming-locker:latest
container_name: charming-locker
restart: unless-stopped
ports:
- "{port}:8080" # To prevent port scanning, it is best to set it to 127.0.0.1:{port}:8080
environment:
VAULT_DATA_DIR: /data
RUST_LOG: info
VAULT_SETUP_TOKEN: ${VAULT_SETUP_TOKEN:-}
volumes:
- ./data:/data
Open the page, enter the initialization token and a master password of at least 12 characters. Once initialization is complete, delete the VAULT_SETUP_TOKEN environment variable and restart the container.
Upon successful creation, the browser will display the recovery key once; you must copy or download and save it offline before entering the vault.
This program enforces HTTPS by default. If you are only deploying locally and accessing via a VPN without directly exposing to the public network, you can disable HTTPS enforcement by adding environment variables:
VAULT_REQUIRE_HTTPS=false
VAULT_COOKIE_SECURE=false
VAULT_TRUST_PROXY=false
HttpOnly; Secure; SameSite=Strict cookies;Reverse proxies should still implement connection/request rate limiting and allow only VPN or whitelist addresses. Application-level rate limiting is not a replacement for running naked on the public internet.
vault.json: KDF parameters, random salt, two authentication verification values, and two wrapped copies of the vault key; no plaintext vault key exists;vault.db: Random file IDs, encrypted metadata, ciphertext sizes, and timestamps;files/<uuid>.bin: Encrypted file headers and ciphertext blocks;files/<uuid>.thumb: Client-generated encrypted thumbnails.The one-time display recovery key must be saved offline during initialization. It is not used as a daily login method; if you forget your master password, you can only verify the recovery key through the "Forgot Password" flow, which forces setting a new master password and saving a new recovery key before entering the vault. If both the master password and recovery key are lost, recovery is impossible. The recovery key does not protect against disk failure, deletion, or ransomware; backups must still include the entire data directory and recovery should be verified periodically.
专为 NAS 设计的零知识文件保险库。Rust/Axum 后端仅存储和传输密文;主密码、恢复密钥、保险库密钥、文件密钥、文件名、MIME 类型以及明文内容仅存在于浏览器或未来的原生客户端中。
客户端初始化时会生成一个随机的 256 位保险库密钥。它负责包装每个文件的随机密钥,并加密元数据和缩略图。保险库密钥进一步由两套独立的凭据进行包装:
服务器仅存储保险库密钥的两份包装副本以及身份验证令牌的 SHA-256 验证值。修改主密码会强制生成并轮换恢复密钥,服务器以原子方式替换两份新凭据;只需重新包装保险库密钥,无需重写文件。
每个文件使用独立的、随机的 256 位文件密钥,采用 XChaCha20-Poly1305 在固定的 1 MiB 块中加密。AAD 绑定了文件 ID、用途和明文偏移量,防止密文块在不同文件或位置间被篡改替换。服务器数据库中的文件名等元数据也皆为密文。
这确保了克隆 NAS 硬盘、数据库泄露、甚至读取正在运行的 Rust 服务进程内存,都无法暴露出保险库密钥或明文。Web 端仍存在固有边界:长期控制 NAS 的攻击者可以篡改随后加载的网页/WASM 来诱骗下一次解锁;已签名的 Android/iOS 客户端将提供更强的对抗能力。
服务器仍然能够看到文件数量、密文大小、上传时间戳、访问 IP 和请求时序,如果被攻破也能够删除或阻止数据。零知识保护的是机密性和防篡改,它不能替代离线备份和可用性保护。
生成一次性初始化令牌并创建 .env 文件:
openssl rand -base64 32
将输出内容填入 VAULT_SETUP_TOKEN,然后启动服务:
services:
charming-locker:
image: charmingcheung000/charming-locker:latest
container_name: charming-locker
restart: unless-stopped
ports:
- "{port}:8080" # 为防止端口扫描,最好设置为 127.0.0.1:{port}:8080
environment:
VAULT_DATA_DIR: /data
RUST_LOG: info
VAULT_SETUP_TOKEN: ${VAULT_SETUP_TOKEN:-}
volumes:
- ./data:/data
打开页面,输入初始化令牌和长度至少为 12 位的主密码。初始化完成后,请删除 VAULT_SETUP_TOKEN 环境变量并重启容器。
创建成功后,浏览器会显示一次恢复密钥;在进入保险库之前,你必须复制或下载并将其离线保存好。
本程序默认强制启用 HTTPS。如果你仅在本地部署并通过 VPN 访问,未直接暴露到公网,可以通过添加环境变量来禁用 HTTPS 强制要求:
VAULT_REQUIRE_HTTPS=false
VAULT_COOKIE_SECURE=false
VAULT_TRUST_PROXY=false
HttpOnly; Secure; SameSite=Strict 的 Cookie;反向代理仍应实现连接/请求速率限制,并且仅允许 VPN 或白名单地址。应用级限流不能替代裸奔在公共互联网上的安全风险防护。
vault.json:KDF 参数、随机盐、两个身份验证验证值以及保险库密钥的两个包装副本;不存在明文保险库密钥;vault.db:随机文件 ID、加密的元数据、密文大小和时间戳;files/<uuid>.bin:加密的文件头和密文块;files/<uuid>.thumb:客户端生成的加密缩略图。一次性显示的恢复密钥必须在初始化期间离线保存。它不作为日常登录方式使用;如果忘记主密码,只能通过“忘记密码”流程验证恢复密钥,该流程会强制设置新主密码并保存新恢复密钥后才能进入保险库。如果主密码和恢复密钥同时丢失,将无法恢复。恢复密钥无法防止磁盘故障、删除或勒索软件;备份仍必须包含整个数据目录,并且应定期验证恢复有效性。
Content type
Image
Digest
sha256:3888e6439…
Size
34 MB
Last updated
2 months ago
docker pull charmingcheung000/charming-locker