tgcryptfs v0.1.2

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.

MIT licensed Rust, MSRV 1.75 Linux + macOS github.com/hedonistic-io/tgcryptfs
bash -- 80x24
# install $ curl -fsSL https://raw.githubusercontent.com/hedonistic-io/tgcryptfs/main/scripts/install.sh | bash [ok] Detected: macOS aarch64 [ok] FUSE: macFUSE 4.x found [ok] Downloaded tgcryptfs v0.1.2 (SHA-256 verified) [ok] Installed to /usr/local/bin/tgcryptfs # set up telegram credentials (2 minutes, one time) $ ./scripts/setup-telegram.sh Opening https://my.telegram.org ... Enter your API ID: 39223262 Enter your API Hash: ******************************** Credentials written to ~/.config/tgcryptfs/.env # authenticate with telegram $ tgcryptfs auth login Authenticated as +1********67 # create an encrypted volume, mount it, use it $ tgcryptfs volume create --name work Volume "work" created (256-bit root key, Argon2id KDF) Sentence reference: album bright castle dawn ember frost gate... $ tgcryptfs volume mount work ~/secure Mounted at ~/secure $ cp ~/taxes-2025.pdf ~/secure/ $ ls ~/secure/ taxes-2025.pdf $ tgcryptfs volume unmount ~/secure Unmounted
How it works

The problem is simple

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.

What you do

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.

What tgcryptfs does

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.

And if something goes wrong

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.

Cryptography

Nothing novel, nothing clever

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.

PrimitiveAlgorithmWhat 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
Key hierarchy
Password + Salt | Argon2id (64 MB, t=3, p=4) | K_root 256-bit master key | HKDF-SHA256 with domain separation __________________|__________________________________________ | | | | | | K_data K_meta K_schema K_ih K_wrap K_deadman encrypts encrypts derives integrity sharing audit files inodes table hashing key wrap logging names

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.

Architecture

Nine crates, strict layering

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.

tgcryptfs-cli 9 subcommands, clap, shell completions | tgcryptfs-api 21 REST endpoints, Axum, bearer auth | ____|____________________________ | | | | tgcryptfs tgcryptfs tgcryptfs tgcryptfs -fuse -telegram -sharing -deadman FUSE ops MTProto ML-KEM triggers, via fuser client key wrap destruction | | | | |___________|__________|__________| | tgcryptfs-store opaque SQLite, BLAKE3-derived schema | tgcryptfs-cache encrypted LRU, at-rest encryption | tgcryptfs-core pure crypto. no I/O. no network. no fs. this is where the math lives.
Install

Get it running

Script
curl -fsSL https://raw.githubusercontent.com/hedonistic-io/tgcryptfs/main/scripts/install.sh | bash
Detects your OS and arch. Installs FUSE deps. Verifies checksums. Sets up completions.
Cargo
cargo install tgcryptfs-cli
Needs Rust 1.75+ and FUSE headers (libfuse3-dev on Debian, macFUSE on macOS).
Source
git clone https://github.com/hedonistic-io/tgcryptfs && cd tgcryptfs && ./scripts/build.sh --install
Checks all prerequisites, builds release binary, runs 473 tests, installs.
Windows
.\scripts\install.ps1
Experimental. Requires WinFsp. FUSE support is limited on Windows.
Platform matrix
Platform
Methods
FUSE
API
Dep
Linux x86_64
script, cargo, src
yes
yes
libfuse3-dev
Linux aarch64
script, cargo, src
yes
yes
libfuse3-dev
macOS Intel
script, cargo, src
yes
yes
macFUSE
macOS ARM
script, cargo, src
yes
yes
macFUSE
Windows
source only
exp.
yes
WinFsp

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.

Documentation

Read the docs

What else

The rest of the feature list

Multi-user sharing

Share volumes via ML-KEM-768 key exchange. Invite links with expiration. Read/write/admin permissions. Revocation.

22-word sentence references

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.

Content-defined chunking

Rolling-hash chunk boundaries with BLAKE3 identity. Deduplication across and within volumes. Change one byte, re-upload one chunk.

Forward secrecy

Epoch-based key rotation. Rotate your keys, old epochs are zeroized. Past data becomes unrecoverable even if the current key leaks.

Opaque SQLite

Every table name, column name, and index is a BLAKE3 keyed hash. The database is structurally meaningless without the schema key.

REST API

21 endpoints via Axum. Bearer token auth, CORS, rate limiting. Volume ops, sharing, dead man's switch, system status. JSON in, JSON out.