ZeroTrust Drive

Encrypt locally. Store ciphertext with a separate provider. Do not ask one company to store your data and control the only client that handles its encryption key.

Hardened v2 Source Preview

The implementation described on this page is available in the current source tree, not in the published binary release. Do not use the v0.6.0 release to create a new store: it predates the Argon2id and XChaCha20-Poly1305 v1 format, as well as the immutable-chunk v2 format. The earlier Hardened v1 Source Preview is now the backward-compatibility path. Build the current source, or wait for a release that explicitly states v2 format support.

V2 remains a durability-focused beta, not yet a write-heavy production filesystem. A sixteen-slot dirty-chunk overlay caps logical retained bytes and requested steady-state capacity at 64 MiB; new, sparse, and short tails begin at 4 KiB instead of allocating a complete 4 MiB chunk. It coalesces small writes before a root-last commit. Explicit offline handling can authenticate, quarantine, and restore exact objects proven unreachable. New physical purge is disabled because no supported portable primitive closes the final concurrent inode-mutation race; quarantine does not reclaim storage. Use it for controlled testing or low-write data with one active writer and an independent backup. The baseline process-death matrix passes on local and hosted APFS and loopback ext4. Dedicated matrices also pass locally on APFS and in hosted APFS/x86_64 loopback ext4: 22 GC-quarantine plus 14 quarantine-recovery, 9 GC-restore plus 8 restore-recovery, and 65 v1-to-v2 migration plus 29 pending-root-recovery kill points. The final hosted run passed the 216-test job in 1m58s, APFS in 1m19s, and asserted-x86_64 loopback ext4 in 1m06s. The compact-tail memory work, one direct immutable-object path family, and local native probes have only local validation since that hosted run. Live FUSE coverage, complete production File Provider wiring, passing real iCloud tests, remote-provider ordering, and evidence-retirement policy remain open. The beta label is unchanged.

Separate the Trust Boundaries

A managed encrypted-storage service can place storage, account control, and the key-handling client under one vendor. Its privacy claim then depends on that same vendor continuing to ship an honest client and operate an honest update channel.

Storage and client-side encryption should have independent owners and update paths. A "trust us" privacy promise is not a cryptographic boundary.

Do not hand both critical roles to one privacy-marketing vendor merely because it labels its own provider-controlled client "end-to-end encrypted." If that vendor stores the data, ships the only key-handling client, and controls silent updates, the architecture still collapses to one organization saying "trust us." Independent ownership makes compromise, coercion, and a malicious update less likely to cross every boundary at once.

ZeroTrust Drive is independent from Google, Apple, Proton, and Yandex. The open-source client encrypts and decrypts locally, while the selected storage provider receives the encrypted backing files. With a strong, unique passphrase, disclosure or compromise of the storage account alone does not automatically disclose plaintext.

Proton is the useful edge case. Proton owns its storage service, sync client, outer encryption, account, and outer recovery process. When Proton stores a ZeroTrust Drive backing folder, its own end-to-end encryption is additional defense in depth, not the foundation of the privacy claim. ZeroTrust Drive has already encrypted and authenticated the inner objects under an independent passphrase that must never be given to Proton.

From the stored backing data alone, that separation prevents plaintext disclosure and creation of a new valid ZeroTrust generation. It does not make Proton an availability-neutral pipe. Proton can still delay, replay, duplicate, delete, or withhold ciphertext, and loss of Proton recovery material can lock the outer encryption even when the ZeroTrust Drive passphrase is safe. Store both recovery domains separately and keep a versioned backup under a different provider or offline failure domain.

Organizational separation is not endpoint sandboxing. Google Drive for desktop, Proton Drive, the Yandex sync client, or another provider process still runs on your Mac and may have permission to access the separate plaintext mount. Endpoint permissions and software updates remain part of the threat model.

This is defense in depth, not a promise that nobody must be trusted. Your Mac, operating system, passphrase, applications with access to the mount, storage-sync software, dependencies, and the ZeroTrust Drive build and update path remain security-critical. Build reviewed source if targeted software updates are part of your threat model.

A "trust me" privacy label, audit badge, or zero-knowledge slogan does not repair a design where one vendor stores the only copy, ships the only key-handling client, controls silent updates, and owns account recovery. That is a concentrated trust claim, not separation. Keep an offline recovery secret and at least one independent backup under a different failure domain.

The backing store reveals ciphertext sizes, object counts, modification timing, account metadata, and non-secret KDF parameters. It does not contain plaintext filenames, the plaintext directory tree, file contents, or the encryption key.

What Separation Changes

Trust question Single-vendor encrypted storage ZeroTrust Drive separation
Who stores ciphertext? The encryption-service vendor Your selected cloud provider
Who ships the key-handling client? The same vendor An independent open-source project
Organizational control One organization controls both surfaces Storage and encryption have separate owners and update paths
Operational burden Managed for the user You manage mounting, sync discipline, backups, and release verification
Endpoint trust Your local device remains trusted Your local device remains trusted

How It Works

  1. Choose a fully downloaded local cloud-sync folder for the encrypted backing store
  2. Mount ZeroTrust Drive through FUSE and work with ordinary plaintext names at the separate mount point
  3. File contents are encrypted with XChaCha20-Poly1305 under a key derived from your passphrase with Argon2id before entering the backing directory
  4. V2 stores fresh opaque chunks on a 4 MiB logical grid and copy-on-write tree/index generations, then switches the small authenticated _root.age pointer last: updates use atomic exchange and retain the displaced root, while the first root uses atomic no-replace
  5. Unmounting removes the plaintext filesystem view; the synchronized backing directory remains ciphertext

The .age suffix is a filename convention. ZeroTrust Drive does not use the age file format.

macOS First: Choose the Backing Store

Google Drive Mirror - Recommended

Use a dedicated folder in My Drive with Google Drive for desktop configured to Mirror files. Permanently local ordinary files best match the current POSIX fsync and atomic-rename assumptions.

On a Mac this also creates the clearest organizational split: Apple supplies the OS, Google supplies storage, and ZeroTrust Drive supplies encryption.

Tradeoff: Mirror mode keeps all of My Drive locally, needs the Google desktop client, and can still suffer stale status, DriveFS cache problems, conflicts, quota failures, and upload stalls.

iCloud Drive - Beta (Constrained)

Mark the complete encrypted backing folder Keep Downloaded before mounting. iCloud has lower setup friction and supports folder-level local retention, but Apple supplies both the OS and storage even though the encryption client remains independent.

iCloud users report opaque upload queues, stuck placeholders, Keep Downloaded surprises, conflict copies, and limited diagnostics. There is no general user-facing Pause Sync control.

Apple says an individual iCloud Drive file or folder over 50 GB is usually marked Ineligible; treat that as a conservative operational ceiling, not a precisely specified recursive quota. Offline v2 quarantine identifies proven-unreachable objects but does not reclaim their space, and committed history plus recognized conflict/recovery evidence also remain. The relevant number is accumulated encrypted backing data, not visible plaintext size. Keep an iCloud store comfortably below that limit, monitor the backing folder, and migrate away before it approaches 50 GB.

A safe exact-URL NSFileCoordinator shim and capability-rooted storage boundary are implemented and tested. Pinned immutable v2 object publication now enters through the direct StoreRoot backend while retaining descriptor-rooted openat writes and the original durability checkpoints. Coordinated production mode and every other path family remain disabled and unwired. A correct integration must coordinate exact KDF and maintenance controls; v1 indexes, blobs, migration, reads, writes, and cleanup; and every v2 root, object, manifest, staging, evidence, GC, migration, read, rename, and deletion path. Partial coordination would provide a false guarantee, so iCloud remains beta.

A local NSFilePresenter probe now verifies an exact descriptor-rooted move and a bounded presenter notification and operation-queue drain; Foundation's synchronous coordination and presenter-removal calls do not expose a hard cancellation deadline. Opt-in gates use one user-selected disposable iCloud folder marked Keep Downloaded for inherited-policy and all 64 normal-write/recovery process deaths, plus a separate explicitly non-Keep-Downloaded folder for a real evict-then-download materialization transition. They compare bounded exact directory-name/type and regular-file size/link-count/digest inventories after File Provider settles. The SIGKILL gate additionally re-authenticates every root and reachable object while the retained child identity remains unchanged; that authentication still uses presentation paths and cannot exclude a provider ABA replacement. Successful traces and separate conflict-bearing copies of every death state remain available for inspection; the harness does not recursively delete a provider-managed test child. Those three retained-fixture iCloud gates are implemented but have not yet run, so they do not qualify iCloud or change the beta label.

Proton Drive - Experimental

On macOS 13 or later, use a dedicated folder under My files and mark the complete encrypted backing folder Make Available Offline. Proton Drive uses Apple File Provider and initially exposes cloud-only placeholders. Verify the latest successful sync before mounting and again after reboot, sign-in, updates, or storage pressure.

Proton officially warns that large collections of small files can synchronize much more slowly than one large file of the same total size. That is directly relevant to v2's immutable chunks, trees, generations, manifests, and retained evidence. Self-selected reports include small-file stalls, high File Provider CPU, stuck status, duplicate name clashes, and local-availability surprises, while other users report tens of thousands of files or terabyte-scale libraries working after occasional intervention. Treat it as experimental, not as a general data-loss claim.

Proton's own end-to-end encryption is useful defense in depth, but ZeroTrust Drive must remain the independent inner encryption vendor. Keep both passphrases and recovery domains separate. The official Proton CLI is not a continuous sync engine, and the reverse-engineered rclone backend is not supported for a writable store.

Yandex Disk - Experimental Secondary

Yandex offers an official Linux sync daemon, an OAuth REST API with app-folder scope, and WebDAV. That makes it more practical than iCloud on Linux, but it is not the macOS-first default. Use a fully local synchronized folder; do not use a live WebDAV mount as writable storage.

Since June 22, 2026, WebDAV requires a paid plan, and WebDAV deletion bypasses Trash. Yandex documents an upload cap of twice the current storage capacity for a 30-day accounting period beginning with the first upload and resetting every 30 days. Immutable copy-on-write generations and migration can consume that allowance quickly.

Yandex's own documentation warns that simultaneous multi-device editing can create duplicate copies or lose files. Its macOS client also documents stuck synchronization, open-file, quota, network, and resource-throttling failure modes. Treat it as experimental secondary storage, monitor remote freshness and quota, and keep an independent copy.

Do not use Google Drive Stream mode, Shared Drives, cloud-only placeholders, WebDAV, rclone, the Proton CLI as a mounted backing store, or a network-mounted provider cache. Keep the decrypted mount outside every synchronized folder.

See the cloud backend and user-experience review for vendor documentation, current tradeoffs, and sourced anecdotal reports.

Security and Reliability Controls

Authenticated Encryption

XChaCha20-Poly1305 uses a 256-bit key and random 192-bit nonce. Accidental nonce reuse is negligibly probable. Authentication rejects modified, corrupted, or cross-slot ciphertext; v2 parents also bind each child object's complete ciphertext digest. The remaining rollback gap is restoring a complete, internally consistent historical root and all of its objects; legacy v1 can also accept an older same-name, same-size authenticated blob.

Argon2id Key Derivation

A per-drive random salt and bounded memory/time parameters raise the cost of offline guessing. A strong, unique passphrase remains essential.

Fail-Closed Conflict Detection

Before a commit, the client verifies the active authenticated root and scans for alternate v1 blob or index names, the v2 root or object namespace, KDF metadata, migration/rekey/write controls, top-level control/index/blob-like iCloud placeholder names, and interrupted top-level staging artifacts. Completed migration-progress entries are audited at startup rather than pinned by every commit. A detected covered arrival blocks or halts the commit; an arrival raced with root publication remains a loud recovery conflict. Once detected, the mount latches read-only and persistence calls fail until remount, even if the provider later hides the conflicting copy. Durable and retained manifest anchors are audited on remount. Immutable generation/index reads and evidence scans or moves stay on retained no-follow directory descriptors, so a visible provider replacement remains a loud error.

File-Size-Independent Memory

V2 reads one authenticated chunk at a time and accepts write requests of at most 4 MiB. A mount-wide overlay retains at most sixteen dirty slots and 256 dirty inode records. New, sparse, and short tails begin with a 4 KiB reservation and grow only as writes reach farther into the chunk; changing an existing full base chunk still retains that authenticated 4 MiB chunk. The sixteen slots cap logical retained bytes and requested steady-state capacities at 64 MiB, not allocator overhead or transient reallocation. Sparse holes allocate no chunks, open handles retain no complete plaintext file, and flush publishes content before metadata. The independent metadata cap remains 64 MiB.

Evidence-Aware Orphan Quarantine

A preview authenticates the complete graph and produces a plan ID without modifying the encrypted backing store or persisting a plan; it acquires only an outside local advisory lock. A separately confirmed command moves exact unreachable object bytes into a reversible quarantine without unlinking those bytes. New physical purge authenticates and revalidates, then fails read-only before intent, tombstone creation, or byte/name mutation. This preserves conflict evidence but means no storage is reclaimed. The purge flag remains only for authenticated compatibility completion when every candidate is already an exact zero tombstone. Unknown artifacts, provider conflicts, and incomplete maintenance fail closed; additive restore remains available before purge intent so a late root change cannot strand exact authenticated quarantined bytes.

Recoverable Maintenance

Explicit v1-to-v2 migration pins the complete v1 source generation and records authenticated per-file receipts. Re-running resumes safely. V1 sources and v2 migration evidence remain intact after the new root is committed. V2 passphrase rotation is currently refused rather than risking a non-atomic KDF/root pair.

Root-Last Generations

Every changed chunk, tree node, file root, metadata index, and generation has a fresh immutable identity. An AEAD-authenticated normal-write manifest records exact old/new intent, and _root.age changes last: updates use atomic exchange and the initial root uses atomic no-replace. Recovery has deterministic error injection after every durability operation. The baseline 64-point SIGKILL matrix passes on local and hosted APFS and loopback ext4. Dedicated matrices also pass locally on APFS and in hosted APFS/x86_64 loopback ext4: 22 GC-quarantine plus 14 quarantine-recovery, 9 GC-restore plus 8 restore-recovery, and 65 migration plus 29 pending-root-recovery kill points; final hosted qualification completed in 1m58s for normal tests, 1m19s for APFS, and 1m06s for asserted-x86_64 ext4. Transaction roots/manifests are retained as evidence.

Open Source

AGPL-3.0-only source, no Lifub account, and no telemetry. You still need a separate storage provider account and a trustworthy build and update path.

Reliability Boundaries

V2 bounds random reads, writes, and flushes independently of complete file size. Open handles retain no complete plaintext file; a sparse radix tree loads one 4 MiB chunk at a time. The directory metadata snapshot still has a separate 64 MiB bound and is copy-on-write rather than overwritten in place. Continuous dirty activity is forced to flush after at most 30 seconds.

Legacy v1 compatibility still has the old limits. Every concurrently open file is currently buffered in memory. The directory metadata index is one authenticated object. Normal v1 content commits still replace dirty blobs before replacing _index.age. Migrate explicitly with --migrate-v2 before relying on bounded file I/O or root-last commits.

V2 never overwrites a referenced content object. It durably publishes immutable chunks, radix nodes, file roots, an index, and a parent-linked generation; stages an authenticated normal-write manifest; and switches _root.age last using exchange for updates or no-replace initially. Deterministic tests return an injected error after every write, file fsync, rename/publication, directory fsync, evidence-retention, and recovery checkpoint, then retry recovery against that state. An opt-in test also kills a real child process at every normal-write and recovery checkpoint and verifies the result from another process. The baseline 64-point matrix passes on local and hosted APFS and loopback ext4. Dedicated matrices pass locally on APFS and in hosted APFS/x86_64 loopback ext4: 22 GC-quarantine plus 14 quarantine-recovery, 9 GC-restore plus 8 restore-recovery, and 65 resumable migration plus 29 pending-root-recovery kill points; the migration matrix exposed and helped fix completed and late publication root-sibling bypasses. The harnesses drive representative transactions through ZeroTrustFs and maintenance entrypoints directly, not a live kernel-mounted FUSE filesystem. Under the documented filesystem contract, every tested process death exposes the exact old or exact new generation; a fresh verifier authenticates that raw crash-visible root and its complete reachable graph before recovery. These tests do not emulate sudden power loss, torn sectors, controller-cache loss, provider reordering, concurrent writers, or a device that lies about fsync. Unexpected evidence stops recovery without deletion. See the crash-consistency argument and test mapping.

Root-last is a local durability order, not a remote transaction. A provider may deliver the new root before every immutable object reaches a second device; the receiving client refuses writable mount until a complete reachability scrub succeeds. Wait for complete synchronization and do not treat cloud synchronization as a backup.

Repeated small writes coalesce in a sixteen-slot overlay until capacity pressure, close, fsync, or the dirty timer commits them. New or short tiny-file tails allocate compactly in RAM, but the on-disk v2 object graph is unchanged, and close/fsync-heavy activity can still create substantial upload amplification. Orphan handling is intentionally offline and operator-driven: preview, reversible quarantine, and restore. New destructive purge is disabled rather than risk deleting concurrent conflict evidence, so it currently reclaims no space. Historical storage growth remains a blocker for sustained write-heavy use.

Back up _kdf.json separately with the encrypted store. Its salt is not secret, but losing or corrupting this single file makes the ciphertext undecryptable even when the passphrase is known.

The 64 MiB live-index cap is enforced on input and output. If acknowledged metadata mutations cross it, persistence latches read-only; those uncommitted mutations are not automatically rolled back. Initial creation also fails closed on a KDF-only directory left before the first root publication, because it cannot safely distinguish a local interrupted initialization from incomplete cloud sync.

Technical Details

Cipher XChaCha20-Poly1305 AEAD, 256-bit key, 192-bit random nonce
Key derivation Argon2id, per-drive random salt, bounded resource parameters
Integrity binding V2 binds object role and random ID in AEAD associated data; each parent also authenticates the complete child-ciphertext digest. V1 retains filename AAD and a separate index domain.
V2 storage Immutable authenticated 4 MiB chunks, sparse 256-way copy-on-write radix trees, immutable generations, and one authenticated root switched last by exchange or initial no-replace
Memory bound At most sixteen dirty 4 MiB slots plus bounded request/tree-path work for v2 file I/O; flush never buffers a complete file
Compatibility V1 remains readable and writable; explicit authenticated --migrate-v2 resumes after interruption and retains source evidence
Filename limit 255 bytes
Migration/rekey bound 100,000 manifest entries; 64 MiB manifest and live-index input caps
Offline GC bound One shared 250,000-entry object/evidence/control scan budget; 64 MiB authenticated plan ciphertext
Language and filesystem Rust with FUSE
License AGPL-3.0-only

Platforms

macOS - Primary

Requires macFUSE. Apple Silicon is the preferred development and deployment target.

Linux - Secondary

Uses native FUSE. Google Drive for desktop and iCloud Drive have no native Linux clients. Proton's official Linux CLI transfers files but is not a continuous sync engine. Yandex publishes an official x86 Linux sync daemon, but current Ubuntu compatibility and remote freshness must be validated before relying on it.

Windows - Unsupported

Runtime support would require a WinFSP integration instead of the current FUSE layer.

View Source and Build Instructions