{"id":50912137,"url":"https://github.com/jegly/tesseract","last_synced_at":"2026-06-16T11:01:22.328Z","repository":{"id":364531651,"uuid":"1266028251","full_name":"jegly/Tesseract","owner":"jegly","description":"State of the art, Multi-cipher cascade encryption with post-quantum key wrapping  stack AES, Serpent, Twofish, ChaCha20 and more in any order you choose.","archived":false,"fork":false,"pushed_at":"2026-06-13T11:18:24.000Z","size":1492,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-13T12:23:36.847Z","etag":null,"topics":["encryption","encryption-algorithms","encryption-engine","post-quantum-cryptography","pqc-migration","quantum-encryption"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jegly.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-11T09:09:35.000Z","updated_at":"2026-06-13T11:18:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jegly/Tesseract","commit_stats":null,"previous_names":["jegly/tesseract"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jegly/Tesseract","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jegly%2FTesseract","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jegly%2FTesseract/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jegly%2FTesseract/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jegly%2FTesseract/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jegly","download_url":"https://codeload.github.com/jegly/Tesseract/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jegly%2FTesseract/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34402663,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-16T02:00:06.860Z","response_time":126,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["encryption","encryption-algorithms","encryption-engine","post-quantum-cryptography","pqc-migration","quantum-encryption"],"created_at":"2026-06-16T11:01:20.716Z","updated_at":"2026-06-16T11:01:22.314Z","avatar_url":"https://github.com/jegly.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"packaging/icons/hicolor/scalable/apps/com.jegly.tesseract.svg\" alt=\"Tesseract\" width=\"180\" /\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eTesseract\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003cb\u003ePost-quantum disk \u0026amp; file encryption for the Linux desktop.\u003c/b\u003e\u003c/p\u003e\n\n\u003e **Cross-platform core:** The encryption engine (`tesseract-core`) is pure Rust with no OS calls, no unsafe code, and no platform assumptions — it was designed from the start to be portable. The GTK4 GUI and the Linux-specific agent are the only platform-bound layers. Porting to Windows or macOS means replacing those two components; the crypto heart carries over unchanged.\n\n[![Made with Rust](https://img.shields.io/badge/Rust-1.85%2B-BD93F9.svg?logo=rust\u0026logoColor=white)](https://www.rust-lang.org)\n[![GTK4](https://img.shields.io/badge/GTK4-libadwaita-8BE9FD.svg)](https://www.gtk.org)\n[![Post-Quantum](https://img.shields.io/badge/Post--Quantum-Hybrid%20KEM-CBA6F7.svg)]()\n[![ML-KEM](https://img.shields.io/badge/ML--KEM-1024%20(Kyber)-89B4FA.svg)](https://csrc.nist.gov/pubs/fips/203/final)\n[![ML-DSA](https://img.shields.io/badge/ML--DSA-87%20(Dilithium)-89B4FA.svg)](https://csrc.nist.gov/pubs/fips/204/final)\n[![X25519](https://img.shields.io/badge/X25519-Hybrid-F5C2E7.svg)]()\n[![HPKE](https://img.shields.io/badge/HPKE-RFC%209180-FF79C6.svg)](https://www.rfc-editor.org/rfc/rfc9180)\n[![Ciphers](https://img.shields.io/badge/Ciphers-AES%20%C2%B7%20Serpent%20%C2%B7%20Twofish%20%C2%B7%20ChaCha-50FA7B.svg)]()\n[![Cascades](https://img.shields.io/badge/Cascades-up%20to%205%20deep-50FA7B.svg)]()\n[![Argon2id](https://img.shields.io/badge/KDF-Argon2id-F1FA8C.svg)]()\n[![FIDO2](https://img.shields.io/badge/FIDO2-YubiKey%20hmac--secret-FFB86C.svg)]()\n[![Non-root](https://img.shields.io/badge/Default-No%20root%20%C2%B7%20No%20sudo-A6E3A1.svg)]()\n[![Sandboxed](https://img.shields.io/badge/Agent-Landlock%20%2B%20seccomp%20%2B%20mlock-FF5555.svg)]()\n[![No telemetry](https://img.shields.io/badge/Network-None%20%C2%B7%20On--Device-FF5555.svg)]()\n[![License](https://img.shields.io/badge/License-GPL--3.0-6272A4.svg)](LICENSE)\n\nIf this project helped you, please ⭐️ star it to help others find it.\n\nsha256:cc00fe1c2af57a624fba2afd0e4698bd37c725632cb98fa281e36a863dd79c5c\n\n---\n\n## What is Tesseract?\n\nTesseract is a privilege-separated, post-quantum encryption tool for the Linux\ndesktop. Think VeraCrypt feature parity — encrypted containers, whole-disk\nencryption, hidden volumes for plausible deniability — plus a simple file/folder\nencryptor and a hardened background service that owns **every** key and never\nhands one to the UI.\n\nThe interface is native GTK4 / libadwaita — not Electron, not a browser shell —\nso it starts instantly and sits properly in your desktop. Everything runs\nlocally: no account, no network, no telemetry.\n\n\u003e [!IMPORTANT]\n\u003e Tesseract is **non-root by default**. The GUI and the key agent both run as\n\u003e your normal user. The default data plane (FUSE + udisks2) mounts encrypted\n\u003e volumes with no `sudo`, no setuid, and no polkit prompt for the device\n\u003e itself — exactly like plugging in a USB stick.\n\n---\n\n## Screenshots\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/unlock.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eUnlock screen\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/new-volume.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eCreate encrypted volume\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/cipher-picker.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eCipher selection\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/unlock-volume.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eUnlock \u0026amp; mount volume\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/file-encrypt-password.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eFile / folder encryption — password mode\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/file-encrypt-algorithms.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eFile encryption algorithm picker\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/file-encrypt-recipients.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eFile encryption — recipient (public-key) mode\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/volume-keys.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eVolume keys \u0026amp; YubiKey enrolment\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/identities.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eHybrid PQ identity management\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/menu.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003eApp menu\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/preferences-appearance.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003ePreferences — appearance \u0026amp; themes\u003c/sub\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003cimg src=\"images/preferences-cascade.png\" width=\"320\"/\u003e\u003cbr/\u003e\u003csub\u003ePreferences — default cipher cascade\u003c/sub\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n---\n\n## Why \"post-quantum\"?\n\nA \"harvest now, decrypt later\" attacker can record your encrypted data today and\ndecrypt it once a large quantum computer exists. Tesseract defends against this:\n\n- **Volume keyslots** can require a **hybrid X25519 + ML-KEM-1024** keyslot, so\n  unwrapping the master key needs both a classical *and* a lattice secret.\n- **File encryption to a recipient** uses the same hybrid KEM through **HPKE\n  (RFC 9180)**.\n- **Attestation/signatures** use **ML-DSA-87** (optionally jointly with\n  Ed25519).\n\nThe symmetric layer is already quantum-resistant: 256-bit ciphers in\nlength-preserving XTS, optionally cascaded up to five deep.\n\n---\n\n## Core Features\n\n### Encrypt a file or folder\nThe simplest flow: pick a file — or a whole **folder** (packed into one\nencrypted `.tsrf`) — set a **password**, and click Encrypt. Anyone with the\npassword can open it later. No keypair, no setup. Choose the cipher\n(ChaCha20-Poly1305, AES-256-GCM, XChaCha20-Poly1305, AES-256-GCM-SIV, or a\ntwo/three-layer cascade). Decryption restores the file, and folders extract\nautomatically.\n\n### Encrypt to a recipient (public-key)\nSwitch to **Recipients** mode to encrypt to someone's public key instead of a\nshared password — only they can open it. Built on HPKE with the hybrid\nX25519 + ML-KEM-1024 KEM, multi-recipient, with an optional detached ML-DSA-87\nsignature. Generate and manage identities right in the app.\n\n### Encrypted volumes\nCreate a container (file, partition, or device) you can **mount like a drive**.\nThe agent encrypts every read and write on the fly through the cascade engine,\nin locked memory — plaintext never touches disk and the GUI never sees a key.\nPick the cipher cascade, hash, and Argon2id cost per volume.\n\n### Hidden volumes (plausible deniability)\nA deniable container can hold a hidden volume inside the free space of an outer\none. The whole header region is indistinguishable from random, so the presence\nof a hidden volume is undecidable without its password. Hidden-volume protection\nprevents the outer volume from overwriting the hidden one.\n\n### Keyfiles \u0026 FIDO2 / YubiKey\nAdd keyfiles (with a built-in generator) or enrol a **FIDO2 security key** as a\nkeyslot via the CTAP2 `hmac-secret` extension — touch your YubiKey to unlock.\n\n### Auto-dismount \u0026 panic\nVolumes auto-lock and wipe their keys on screen lock, suspend, logout, fast\nuser switch, or inactivity (each configurable). A one-press **Panic** control\n(or Ctrl+Shift+P) instantly locks everything and zeroizes all key material.\n\n### Themes\nLive-switching themes — **Dracula**, **Catppuccin** (Latte, Frappé, Macchiato,\nMocha), **Vintage Light**, **Neon Tessera** (cyberpunk), and follow-system —\neach with a custom accent picker, density and motion controls, and HiDPI-crisp\nrounded styling.\n\n---\n\n## How it works — privilege separation\n\n| Component | Runs as | Holds keys? | Job |\n|---|---|---|---|\n| `tesseract-gui` | your user | **No** | Renders state, collects intent |\n| `tesseract` (CLI) | your user | **No** | Scripting parity with the GUI |\n| `tesseract-agent` | your user, sandboxed | **Yes (only here)** | All crypto, in locked non-dumpable memory |\n| `tesseract-mountd` | `CAP_SYS_ADMIN` via polkit | No | *Optional* dm-crypt fast path only |\n\nThe GUI talks to the agent over a `0600` Unix socket, peer-credential checked.\nPassphrases cross once as raw bytes straight into the agent's locked memory; the\nagent runs the KDF and every cryptographic operation. Container references are\npassed as file descriptors (never paths) to avoid TOCTOU.\n\nThe agent hardens itself at startup, in order: disable core dumps →\n`mlockall` → open sockets/fds → **Landlock** filesystem restriction →\n`no_new_privs` → **seccomp** syscall allowlist. The master key lives only in an\n`mmap`'d guard-page arena, `mlock`'d and `MADV_DONTDUMP`'d, and is zeroized on\nany wipe trigger.\n\n---\n\n## Cryptography\n\n| Layer | Primitives |\n|---|---|\n| Sector data | XTS over AES-256, Serpent-256, Twofish-256, Camellia-256, ChaCha20/XChaCha20 — cascade depth 1–5 (experimental: Threefish-512, Kuznyechik, SM4, ARIA, Adiantum) |\n| Keyslot sealing | Committing AEAD (derive-then-commit over XChaCha20-Poly1305 / AES-256-GCM-SIV) — a wrong key fails authentication, never yields a wrong master key |\n| Key derivation | Argon2id (default), scrypt, PBKDF2-HMAC-SHA-512, Balloon (experimental); cost benchmarked at create time, PIM-style knob |\n| Master-key wrapping | LUKS2-style keyslots: passphrase, hybrid PQC (X25519 + ML-KEM-1024), keyfile, FIDO2 hmac-secret |\n| File mode | HPKE (RFC 9180) with hybrid KEM, chunked AEAD body with per-chunk binding, optional ML-DSA-87 / Ed25519 signature |\n| Header integrity | Unkeyed BLAKE3 checksum verified **before** parse; VMK-keyed MAC after unlock; optional ML-DSA-87 attestation |\n| Hashes | SHA-512, SHA-256, BLAKE3, BLAKE2b (experimental: Whirlpool, Streebog) |\n\nAll secret-dependent paths are constant-time; every cipher, KDF, KEM, and\nsignature ships with known-answer test vectors, and the header parser, keyslot\ndecoder, and IPC framer are fuzz targets.\n\n\u003e [!NOTE]\n\u003e Out of scope, by design: system/boot-drive encryption and pre-boot\n\u003e authentication. That needs kernel and bootloader integration outside a\n\u003e userspace non-root tool — use LUKS/dm-crypt for full-disk system encryption.\n\n---\n\n## Install\n\n### Build from source\n\n```bash\ngit clone https://github.com/jegly/tesseract\ncd tesseract\ncargo build --release -p tesseract-agent -p tesseract-cli -p tesseract-gui\npackaging/install.sh          # user-scope install, no root\nsystemctl --user enable --now tesseract-agent\ntesseract-gui                 # or: tesseract \u003csubcommand\u003e\n```\n\n`install.sh --system` does a system-wide install (needs sudo) and is only\nrequired for the optional dm-crypt fast path's polkit helper.\n\n### Requirements\n\n- A GTK4 / libadwaita desktop session (Ubuntu and current stable kernels)\n- `fuse3` and `udisks2` for the default (non-root) mount path\n- Rust 1.85+ to build\n- A FIDO2 authenticator is optional (build with `--features fido2`)\n\n---\n\n## Command line\n\nThe `tesseract` CLI has full parity with the GUI:\n\n```bash\n# encrypt a file or a whole folder with a password\ntesseract file encrypt secret.pdf secret.pdf.tsrf --password\ntesseract file encrypt ./my-folder folder.tsrf --password\ntesseract file decrypt secret.pdf.tsrf out.pdf --password\n\n# public-key file encryption\ntesseract identity generate me.tsrid --seal\ntesseract file encrypt report.txt report.tsrf --to \u003crecipient-b64\u003e\n\n# volumes\ntesseract create vault.tsr --size 2G --cascade aes,serpent --label work\ntesseract mount vault.tsr\ntesseract status\ntesseract unmount \u003cuuid\u003e\ntesseract panic\n```\n\n---\n\n## Security \u0026 quality\n\n| Mechanism | Detail |\n|---|---|\n| Privilege separation | GUI/CLI hold zero key material; the agent owns every key |\n| Memory protection | Guard-page arenas, `mlockall`, `MADV_DONTDUMP`, zeroize-on-drop, core dumps disabled |\n| Sandbox | Landlock + seccomp-bpf allowlist + `no_new_privs`, hardened `systemd --user` unit |\n| IPC | `0600` Unix socket, `SO_PEERCRED` UID check, FD passing (no path TOCTOU) |\n| Verify-before-parse | Header checksum checked before the CBOR decoder runs; bounded lengths/depth |\n| Committing AEAD | Keyslots can never decrypt to a wrong master key |\n| Emergency wipe | Auto-dismount on lock/suspend/logout/idle/socket-EOF/tamper; explicit Panic |\n| Tested | KATs for every primitive, full round-trip + cascade-ordering tests, crash-safe in-place conversion, state-machine and fuzz targets |\n\n---\n\n## License\n\nLicensed under the **GNU General Public License v3.0 or later**.\n© jegly.\n\n---\n\n## Links\n\n- [Tesseract repository](https://github.com/jegly/tesseract)\n- [ML-KEM (FIPS 203)](https://csrc.nist.gov/pubs/fips/203/final)\n- [ML-DSA (FIPS 204)](https://csrc.nist.gov/pubs/fips/204/final)\n- [HPKE (RFC 9180)](https://www.rfc-editor.org/rfc/rfc9180)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjegly%2Ftesseract","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjegly%2Ftesseract","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjegly%2Ftesseract/lists"}