An encrypted filesystem that stores its blocks in Telegram. You see a mounted directory. Telegram sees noise. XChaCha20-Poly1305 + ML-KEM-768. FUSE. Dead man's switch. 22-word recovery. 473 tests.
You want encrypted cloud storage you actually control. Not a third-party service that holds your keys. Not a local drive that dies when your hardware does. Something that looks like a normal folder but is actually ciphertext scattered across the cloud.
Mount a volume. Copy files into it. They show up as a normal directory. Edit them with any application. Unmount when you're done.
Optionally, start the REST API server and control everything programmatically. 21 endpoints. Bearer token auth.
Encrypts every file with XChaCha20-Poly1305 using keys derived from your password through Argon2id. Splits the ciphertext into content-defined chunks. Deduplicates. Uploads the chunks to your Telegram account as opaque blocks.
The metadata database uses BLAKE3-derived names for every table and column. If someone steals the SQLite file, they can't even tell what the schema is without the key.
The dead man's switch monitors for check-ins. If you stop responding -- because you can't, or because you choose not to -- it destroys the volume. Configurable triggers, configurable delay. The data doesn't wait around for someone else to find it.
We didn't invent any primitives. Every choice is a well-studied, conservative selection. The only unusual part is ML-KEM-768 for post-quantum key exchange during sharing -- and that's NIST FIPS 203, not some academic prototype.
| Primitive | Algorithm | What it does |
|---|---|---|
| AEAD | XChaCha20-Poly1305 | Encrypts and authenticates every block and metadata record |
| Password KDF | Argon2id | Derives root key from your password (64 MB, 3 iterations) |
| Key hierarchy | HKDF-SHA256 | Derives 6 purpose-specific subkeys from root |
| Content hash | BLAKE3 | Block identity, deduplication, integrity |
| Post-quantum KEM | ML-KEM-768 | Key encapsulation when sharing volumes between users |
| Schema obfuscation | BLAKE3 keyed hash | Derives all SQLite table/column/index names from a schema key |
Every ciphertext is bound to its context through Additional Authenticated Data. A block encrypted for inode 42 at offset 0 cannot be moved to inode 43 or offset 1024 -- the Poly1305 tag will reject it. This kills replay, reorder, and substitution attacks at the cryptographic level.
The crypto layer has zero I/O. The store layer knows nothing about Telegram. The FUSE layer doesn't know how encryption works. Each crate has a single, testable responsibility.
curl -fsSL https://raw.githubusercontent.com/hedonistic-io/tgcryptfs/main/scripts/install.sh | bash
cargo install tgcryptfs-cli
git clone https://github.com/hedonistic-io/tgcryptfs && cd tgcryptfs && ./scripts/build.sh --install
.\scripts\install.ps1
After installing, you need Telegram API credentials.
Run ./scripts/setup-telegram.sh or follow the
manual setup guide.
It takes about two minutes.
Service files for systemd and launchd are in
system/
if you want the API server or dead man's check-in running as a
background service.
Share volumes via ML-KEM-768 key exchange. Invite links with expiration. Read/write/admin permissions. Revocation.
Your 256-bit root key encoded as 22 English words. Write them down, put them in a safe. Recover any volume from those words alone.
Rolling-hash chunk boundaries with BLAKE3 identity. Deduplication across and within volumes. Change one byte, re-upload one chunk.
Epoch-based key rotation. Rotate your keys, old epochs are zeroized. Past data becomes unrecoverable even if the current key leaks.
Every table name, column name, and index is a BLAKE3 keyed hash. The database is structurally meaningless without the schema key.
21 endpoints via Axum. Bearer token auth, CORS, rate limiting. Volume ops, sharing, dead man's switch, system status. JSON in, JSON out.