EncFS: The 20-Year-Old Filesystem That Encrypts One File at a Time
Hook
Most encrypted filesystems hide everything in a monolithic container. EncFS deliberately exposes your file structure—and that's sometimes exactly what you want.
Context
When EncFS emerged in 2003, encrypted filesystems were either kernel-level behemoths requiring root privileges or heavyweight container solutions like TrueCrypt that locked entire volumes. Cloud storage didn't exist yet. Dropbox was five years away. The idea of syncing encrypted files across the internet wasn't even a consideration.
EncFS took a radically different approach: it leveraged FUSE (Filesystem in Userspace) to create a transparent encryption layer that worked file-by-file. You'd mount a directory, access plaintext files through that mount point, and EncFS would handle encrypting each file individually in a separate backing directory. When Dropbox arrived, EncFS users discovered something remarkable—because encryption happened per-file, cloud sync tools could efficiently detect and upload only changed files. Full-disk encryption solutions forced you to sync entire container files, sometimes gigabytes large, for tiny changes. EncFS's granular approach meant a 2KB text file edit resulted in a 2KB encrypted file change. Fast forward to 2024: the original C++ codebase has been rewritten in Rust, bringing memory safety and modern cryptographic primitives to an architecture that, despite its age, still fills a unique niche that alternatives struggle to replicate.
Technical Insight
EncFS operates as a reverse filesystem proxy. When you create an encrypted filesystem, you specify two directories: a backing directory where encrypted data lives, and a mount point where you access plaintext. The FUSE layer intercepts every filesystem operation—reads, writes, directory listings—and translates them into encrypted equivalents.
The Rust implementation maintains this architecture while introducing V7 configuration format with modern crypto. Here's how you'd create a new encrypted filesystem:
# Create directories
mkdir ~/encrypted ~/plaintext
# Initialize EncFS (will prompt for password)
encfs ~/encrypted ~/plaintext
# The V7 config uses AES-256-GCM-SIV with Argon2id KDF
# Files written to ~/plaintext appear encrypted in ~/encrypted
echo "secret data" > ~/plaintext/test.txt
# Check the encrypted backing directory
ls -la ~/encrypted/
# Shows: encrypted filename with encrypted contents
# Unmount when done
fusermount -u ~/plaintext
The encryption granularity matters more than you'd initially think. Traditional block-level encryption (LUKS, BitLocker) encrypts fixed-size blocks, hiding everything but requiring you to mount entire volumes. Container-based solutions (VeraCrypt) create single large files that sync poorly. EncFS's per-file approach means your directory structure remains visible—you can see there's a file called dGVzdC50eHQ (base64-encoded "test.txt") that's 48 bytes—but the contents are cryptographically protected.
The Rust rewrite introduces AES-GCM-SIV, an authenticated encryption mode that's nonce-misuse resistant. This is critical for filesystems where IV (initialization vector) reuse could happen if a file is overwritten. The V7 config also adds HMAC-based filename authentication, preventing attackers from swapping encrypted filenames around:
// Simplified architecture concept
struct EncFSNode {
encrypted_path: PathBuf, // Where encrypted data lives
plaintext_name: String, // Decrypted filename
cipher: Cipher, // AES-GCM-SIV instance
}
impl EncFSNode {
fn read(&self, offset: u64, size: usize) -> Result<Vec<u8>> {
// Read encrypted file from backing directory
let encrypted = fs::read(&self.encrypted_path)?;
// Decrypt with per-file key derivation
let plaintext = self.cipher.decrypt(&encrypted)?;
// Return requested chunk
Ok(plaintext[offset..offset+size].to_vec())
}
}
The killer feature that modern alternatives haven't replicated well is reverse mode (encfsr). Instead of mounting encrypted data as plaintext, reverse mode mounts plaintext data as an encrypted view. Why would you want this? Backups. You can run encfsr ~/documents ~/encrypted-view, point your backup software at ~/encrypted-view, and upload encrypted files to untrusted storage without ever storing plaintext remotely. The plaintext stays on your local disk; only the encrypted view gets backed up.
This reverse mode only works with V7 configs and doesn't support per-file IV headers (which would change on every file modification, defeating incremental backups). The tradeoff is intentional—stable encrypted representations enable efficient rsync-style backups where unchanged files don't retransmit.
EncFS also supports legacy V4/V5/V6 configurations from the C++ era. The Rust implementation can read these older formats and provides an upgrade path to V7, ensuring data encrypted in 2005 remains accessible in 2024. This backward compatibility is rare—most rewrites break compatibility entirely—and speaks to the longevity problem EncFS solves. Your encrypted archives need to outlive the tools that created them.
Gotcha
The elephant in the room: EncFS exposes metadata that more paranoid solutions hide. An attacker who gains access to your encrypted backing directory can see exactly how many files you have, their approximate sizes (within padding granularity), and your complete directory structure. They can't read contents without your password, but they know you have a 2.3MB file in /work/clients/acme/invoices/. CryFS and similar tools go further, hiding file counts and directory structures entirely by using fixed-size encrypted blocks. If metadata leakage matters for your threat model, EncFS is the wrong choice.
The Rust rewrite is explicitly alpha status. The author—who maintains both the original C++ version and the Rust port—recommends keeping separate backups and suggests new users choose GoCryptFS instead. This isn't false modesty; it's a realistic assessment that the Rust implementation lacks the two decades of battle-testing the C++ version received. There are rough edges: the reverse mode limitations with IV headers, interaction issues with Dropbox's rename detection when using certain cipher modes, and an upgrade path from legacy configs that works but requires manual intervention.
Performance is also a consideration. Every file operation goes through FUSE userspace transitions and cryptographic operations. For sequential reads of large files, modern NVMe drives will bottleneck on CPU crypto before disk I/O. Small random I/O patterns amplify the overhead—each 4KB read requires decrypting potentially larger encrypted blocks. If you're running a database on an EncFS mount, you're going to have a bad time. This is a tool for encrypting document archives and backup repositories, not high-IOPS workloads.
Verdict
Use if: You have legacy EncFS-encrypted data that needs ongoing access, you specifically need per-file encryption granularity for cloud sync workflows (Dropbox, rclone, rsync), or you want reverse-mode encryption for creating encrypted backup views of plaintext directories. The Rust rewrite brings memory safety and modern crypto to a proven architecture. Skip if: You're starting fresh—the author himself recommends GoCryptFS for new deployments. Skip if metadata protection (hiding file counts, sizes, directory structure) matters for your threat model; use CryFS instead. Skip if you need production-stable code; the Rust implementation is alpha and the author is transparent about this. Skip if you're encrypting high-performance workloads; per-file encryption overhead will crush IOPS. EncFS excels at one thing: granular, sync-friendly encryption of file archives where metadata exposure is acceptable. For everything else, better tools exist.