Why Rolling Your Own Encrypted Storage Still Makes Sense
Transport-layer encryption now guards most traffic across the internet, and disk encryption protects data at rest on phones and laptops. The next step, end-to-end encryption, keeps data unreadable to the service provider holding it — the model behind apps like WhatsApp and Signal. But the gap between storing data locally and trusting a cloud provider becomes obvious when you have files you want to keep private, backed up remotely, and still easily accessible.
That use case drives UtahFS, an open-source, proof-of-concept encrypted file storage system from Cloudflare’s Research Team. It is not a production service, but it tackles a specific set of requirements that existing tools often miss: encrypted and authenticated directory structure, partial reads of large files without full downloads, and a documented protocol. The project code is available on GitHub, and its design shows how several cryptographic and data-structure primitives fit together.
Object Storage Foundation
The system defaults to object storage because it is inexpensive, reliable, and offers geographic redundancy. Providers like Amazon S3, Backblaze B2, and Wasabi are effectively key-value stores. All UtahFS objects stay at or below a configurable size limit, which is 32 kilobytes by default. Larger files are split into multiple objects connected by a skip list, a variant of a linked list with pointers that allow jumping ahead more than one block at a time. That enables fast random access to the middle of a large file.
Deleting or truncating a file moves its blocks to a dedicated “trash” linked list. When new data is written, the system first reuses blocks from the trash list before creating new ones, maximizing block reuse. This allocation strategy mirrors Linked Allocation from The Art of Computer Programming, Volume 1 and keeps the layout compatible with the encryption layer.
Encryption and Authentication
UtahFS separates confidentiality from integrity. Confidentiality is handled by encrypting every block with AES-GCM using a key derived from the user’s password. The scheme deliberately does not attempt to provide forward secrecy or post-compromise security, since that would require storing synchronized keys on the user’s device, and losing them would render the archive unreadable. To mitigate offline password guessing, key derivation uses Argon2, which makes brute-force attempts more costly; the design acknowledges this is a trade-off, not a complete defense.
Integrity, meaning the storage provider cannot silently alter or delete data, is provided by a Merkle Tree built over the user’s content . The tree’s root hash is paired with a version number that increments on every change. The root and version are authenticated with a password-derived key and stored both in object storage under a reserved key and locally on the user’s device. Before reading any block, the client fetches the remote root and verifies that its version number matches or exceeds the local one, preventing the provider from rolling the archive back to an older state. Each retrieved block can then be checked against the most recent root hash. Unlike a simple message authentication code, a Merkle Tree allows verifying individual blocks without downloading the entire archive. It does not, however, defend against forking attacks where the provider shows different versions to different users; detecting that would require out-of-band gossip between clients.
Hiding Access Knobs (Optional)
Encrypting data does not hide access patterns. A passive observer watching requests can infer behavior — for example, seeing regular uploads and almost no downloads may reveal that a user runs automated backups. To counter this, UtahFS offers optional support for Oblivious RAM (ORAM), specifically Path ORAM, which introduces overhead and is therefore disabled by default.
Path ORAM organizes storage into a binary tree and keeps a client-side table mapping logical pointers to random leaf nodes. A lookup reads every block along the path from the assigned leaf to the root, so the provider cannot tell which specific value was requested. After access, the pointer is remapped to a new leaf, and the value is moved to a block that is a parent of both the old and new leaves — the root serves as a fallback. All fetched blocks are re-encrypted and written back, ensuring subsequent accesses touch different random paths. This makes repeated reads of the same value indistinguishable from random access, at the cost of logarithmic overhead relative to total storage size.
Design Lessons
UtahFS demonstrates that a complete end-to-end encrypted storage system is more than encryption bolted onto a cloud bucket. Every feature, from random file access to block reuse, is integrated with the cryptographic layer from the start. The choice to implement custom integrity checks instead of just relying on MACs, and the optional ORAM layer, reflect that each primitive presents its own trade-off between security, efficiency, and practicality.



