🔐 SecureChat App – Enigma 3 Desktop & Mobile

The self-hosted messenger with end-to-end encryption on every layer: messages, attachments and calls — on your own hardware, not at a corporation.

Enigma 3 app icon

Your messages. Your server. Nobody else's. The desktop app checks for updates directly against this repository.

  • Windows · Linux · Android
  • End-to-end encrypted
  • Self-hosted
  • Argon2id keystore
  • Forward secrecy
Category
💻 GitHub projects
Requirements
Described in the guide
Code blocks
0
Read time
15 min read
⬇ Brochure PDF (12 pages)

Everything in one document: security, cryptography, threat model, platforms and setup. For forwarding or printing.

Your messages. Your server. Nobody else's. Enigma 3 is the chat you operate yourself: server, apps and data on your own hardware. Messages, attachments and calls are end-to-end encrypted — the server stores and relays only ciphertext it cannot read.

Self-hosted means self-determined. There is no operator cloud, no vendor instance and no telemetry. If you host the server yourself, you control every byte. The app needs a running SecureChat server with HTTPS.

Why Enigma 3

Most messengers promise: “We protect your data.” That promise depends on trust — in the operator, the company, its employees. The most famous “unhackable” services in the world failed exactly there. The numbers below come from official Europol, Eurojust and prosecution announcements.

💥 EncroChat (2020)

A hardened “crypto phone” for some 60,000 users. Police broke into the vendor's servers — not the cryptography — and pushed an update to every device that captured the decryption keys. Result: 60 million messages read, €700 million seized, 6,500+ arrests by 2023 (Operation Sirus).

💥 Sky ECC (2021)

The provider's servers were seized and the founder arrested. The keys — held by the provider itself — reached the authorities through prosecution, not brute force. The ciphertext became readable after the fact. Hundreds more arrests across Europe (Operation LIMIT).

💥 ANOM (2021)

The “unwiretapable” device was a covert FBI operation (Trojan Shield). Every message was readable by investigators from the first day. Not a technical failure — the product itself was the backdoor.

🛡️ The common failure

All three failed at the same point: the operator was the weak spot, not the encryption. Whoever controls the server controls every device — without touching one. Enigma 3 removes that spot: the server runs at your place. There is nothing left to seize.

🔐 Security by default

You don't configure anything. All of the following applies from the very first message:

🔐 End-to-end encryption

Direct messages: X3DH + Double Ratchet (like Signal) with forward secrecy, self-healing and replay protection. Channels and groups: sender keys, rotated on every departure. Attachments: AES-256-GCM, filename and type inside the ciphertext. The server stores and relays ciphertext only — it cannot read anything.

📞 Encrypted calls

Voice and video with screen sharing, a media key per call, packed to the participants' device keys. New key at every participant change. Unconfirmed participants show as “without key”. Built on LiveKit E2EE.

⏱️ Self-destructing messages

Lifetime per message: off · 1 h · 7 h · 24 h · 3 · 7 · 30 days (default 7). The timer lives inside the encrypted content — the server cannot extend it. The client deletes at the earlier of its own timer or the server's time and shows deviations.

🔥 Irreversible deletion

Crypto-shredding: every message has its own key. Deleting or expiry destroys the key — copies on the server and in backups become unreadable. Deliberately no built-in backups or snapshots that would defeat deletion.

📱 Devices & safety numbers

A separate key per device, never leaving it. Review and revoke devices, alerts on new devices, optional auto-removal of inactive devices. Safety numbers for comparison rule out unnoticed eavesdropping.

🔑 Local vault

Biometrics or a PIN seal the keys on the device (Argon2id, AES-GCM). Android Keystore/StrongBox, iOS Secure Enclave, Windows DPAPI. Without the PIN, a seized device yields only ciphertext.

🔬 Cryptography in detail

Vetted standard primitives, no proprietary crypto: WebCrypto with NIST P-256 (ECDH, ECDSA), HKDF/HMAC-SHA-256 and AES-256-GCM. Private keys never leave the device.

🤝 Key agreement: X3DH

The sender fetches the recipient device's prekey bundle and verifies the signed prekey against the pinned identity signing key (trust on first use). The result is a shared secret known only to these two devices. Prekey retrieval is rate-limited against draining one-time prekeys.

🔁 Double Ratchet (DMs)

Every message gets its own key. The symmetric ratchet gives forward secrecy; the Diffie-Hellman ratchet gives self-healing after a compromise. Headers are encrypted. Seen base keys are rejected (replay protection). Each message is encrypted for every recipient device (up to 64) and your own other devices.

👥 Sender Keys (groups & channels)

Each device maintains a chain per room: mk = HMAC(ck, 0x01), ck' = HMAC(ck, 0x02). Every message is signed with the chain's signing key; the signature covers room and sender. Chains are distributed through the pairwise Double-Ratchet sessions to confirmed members only. Rotation: on any departure, device change, after 7 days, or before counter overflow. New members get the chain from the current state — older messages stay unreadable.

📞 Calls & attachments

Calls: LiveKit Insertable Streams. A leader generates random media keys per call and distributes them packed to each participant's device keys; new key at every change. Attachments: AES-256-GCM via the ratchet (DMs) or sender key (channels), bound to room and sender. EXIF, GPS and XMP metadata are stripped on upload.

Keys per device — every device generates its own, private keys never leave it:

Identity key (ECDH P-256)Device identity, basis of the safety number — permanent per device.
Signing key (ECDSA P-256)Signs the signed prekey; pinned on first contact (TOFU).
Signed prekeyFor the X3DH exchange — renewed regularly.
One-time prekeysSingle-use for X3DH — replenished after consumption, retrieval rate-limited.

🚫 Enforcement: what the server refuses

Plaintext is rejected

CreateMessage, UpdateMessage, CreateUpload and image descriptions return e2ee_required without ciphertext — in DMs, groups and channels. This duty cannot be switched off in production, neither by setting nor environment variable. Old plaintext channel messages are destroyed at startup: key destroyed, storage securely overwritten.

No silent eavesdroppers

The client remembers the first seen member list. Members added later stay pending until you confirm them in the room or verify their safety number. The server can claim new members — but cannot hand out keys unnoticed. In DMs, sending pauses until you confirm a changed key.

Removed, not disabled

No bots — API keys, MCP, webhooks gone; existing bot accounts revoked at startup. No SSO/OAuth — password login always active. No link previews — the server would see the URL in plaintext. No telemetry, no crash reporting.

Hard defaults

Invitation-only registration · 12-character minimum password · login throttling with growing lockout · absolute session lifetime (default 12 h, not just idle) · HTTPS with HSTS · strict CSP, no embedding · optional auto-removal of devices inactive 30–365 days.

🛡️ Device security in detail

🔑 The vault (app lock)

The PIN or passphrase derives a key-encryption key with Argon2id (64 MiB, t=3; otherwise PBKDF2-SHA256 ≥600k iterations). It wraps a random 256-bit data key (DEK). Every vault entry is sealed with AES-GCM — unique nonces, record ID as authenticated data. Platform binding adds a second layer: Android Keystore/StrongBox, iOS Secure Enclave, Windows DPAPI. On lock, timeout, background and app exit the DEK is discarded from memory. On mobile, every return from background requires Face ID/Touch ID/fingerprint, PIN as fallback.

⛔ Attacks and answers

Wrong PIN: exponential backoff; optional vault wipe after N attempts (default selectable: 10). Forgotten PIN: local wipe and re-registration as a new device — server messages stay. Stolen database: without the PIN only ciphertext; hardware binding makes offline brute force expensive. Weak short PINs stay offline-bruteforceable — a long passphrase is recommended.

📱 Device management

Settings show all devices with message keys; each is individually revocable. A revoked device is logged out and gets no new keys. New sign-ins alert your other devices with name and time — “Was that me?” — with one-click revocation. Inactive devices can be auto-removed after 30, 60, 90, 180 days or a year, revoked completely along with keys, sessions and tokens.

✅ Safety numbers

Derived from both accounts' identity keys. Compare in person or via QR code — afterwards the person counts as verified. In groups and channels this works per member through the lock in the header, which also shows every member, their devices and the sender-key status. A key change on a verified device pauses sending until you confirm — in DMs, groups and channels alike.

🧭 Who sees what — the threat model

WhoWhat they seeWhat they cannot do
Server operator / attacker with server accessMetadata: who with whom, when, which room, message sizes, IPs, device lists.Decrypt content, attachments or calls; extend timers; slip in members or devices unnoticed (if you check safety numbers).
Network observerA TLS connection.Read content.
Stolen / seized deviceWith active PIN: keys sealed (Argon2id/PBKDF2 KEK, AES-GCM DEK). Without PIN: ciphertext only.Reconstruct older ratcheted messages of other devices; hardware binding makes brute force expensive.
Push providerTime and target device. By default no plaintext titles or sender names.Read message content or sender names from the payload.
Investigator with server seizureMemberships, timestamps, sizes, device lists, push tokens.Without users' device keys: not a single readable message.

What stays unencrypted — and why: metadata (inherent to any server architecture, stated openly); room names, profiles and reactions (protect server, .env and backups accordingly); system messages like “… joined” (server core, deletable but not E2EE payloads).

Documented openly, not marketed: The complete security model with all its limits is in the server's technical documentation. Anyone who reviews it will find more than is described here.

🕶️ Metadata protection — stage 1

Encryption hides content. Stage 1 also takes away the metadata the server does not need to operate — and makes the rest less precise. Experimental, default-on, no configuration needed.

🏷️ Encrypted channel names

The client encrypts the channel name and description with the room's sender keys; the server stores only ciphertext and a neutral placeholder (🔒 #4f2a9c01d7). The plaintext name never reaches the server — renaming a migrated channel in plaintext is rejected (fail closed). Members who can read messages can read the name; non-members and devices without the key see the placeholder. Old plaintext name records are deleted during migration.

📏 Size padding

Every encrypted message body and edit is padded to a size bucket before encryption (Padmé rule, ≥256 bytes, at most ~12 % overhead, invisible marker characters). The server cannot tell a short reply from a long sentence. Attachments already used size buckets.

⌨️ Typing opt-out

Settings → Security & privacy: “Send typing indicators” off means this device sends none — while you still see everyone else's. Your choice is per device and server, never stored centrally.

🧾 Minimal server logs

By default, process logs write no user IDs, login or display names, room names, e-mails or IPs — identity fields are [redacted]. Sign-in audit records keep no hash of IP or user agent unless the operator enables it — and then only with a key that rotates on a window (default 24 h), so hashes cannot be chained across time. The session list still shows the coarse device class (“Firefox on Windows”).

🎛️ Control: your account, your server — with the hard buttons

🔑 Passkey sign-in (WebAuthn)

Sign in without a password: the server stores only the public credential, the private key stays on your device and never leaves it. Passkeys are optional — password sign-in always stays available and cannot be disabled. Ceremonies are protected by a five-minute nonce that verifies at most once, even under concurrent requests. Adding or removing a passkey alerts your other sessions; removing one revokes established credentials like a password change. The relying party is derived from the public HTTPS URL — credentials can never be scoped broader than your server.

📡 Active sessions: who is online

Settings → Security lists every device signed into your account: device description, sign-in method, sign-in time, last use, an online marker and a “this device” marker. Online means a live realtime connection, tracked per session with 60-second heartbeats — not a guess. Every session except the current one can be signed out with one click. So a stolen laptop, a forgotten browser, or an ex's phone can be logged out precisely — without touching the account itself.

🗑️ Delete everything — the admin button

The server administrator finds a danger button in Admin → Security → self-deleting messages: “Delete all messages”. One action wipes every message in every room, thread and DM — with reactions, edits, attachments and link previews. The server reuses the expiry machinery: each message key is shredded, body events erased, attachment bytes removed, search/unread/notification projections updated, up to eight rooms in parallel as a background job with a progress report. Accounts, rooms, memberships, devices, keys and settings stay. The action is final and lands in the audit log — without any message content.

🧹 Delete all your messages

Users have the same power over their own data: Settings → Self-Destructing Messages has “Delete all my messages”. The server retracts every post you ever wrote — including rooms you left, thread replies and their echoes — newest-first, skipping what is already gone. Membership stays; content, reactions, pins, search entries, notifications, attachments and previews go. Crypto-shredded, not hidden.

📱 Devices & keys under your hand

Settings → “Devices with message keys” shows every device of your account; each is individually revocable. A revoked device is logged out, loses its sessions and tokens and gets no new sender keys — future messages skip it. New logins alert your other devices with name and time and the option “That wasn’t me” for one-click revocation. The operator can add auto-removal of devices inactive 30–365 days; abandoned devices are revoked completely, keys included.

⚙️ Admin → Security: inside the page

The admin menu has a dedicated Security page with three sections — everything observable, nothing hidden:

Access. Blocked usernames: names the server refuses at registration, with a pattern list. OAuth clients: every registered application with its origins and last authorization, each settable to default, trusted or blocked.

Retention. Delete all messages (danger button, background job with progress). System events: join/leave/call/room events — delete immediately (“clear all system events”, with count) or let them follow the message lifetime automatically; the server overwrites stored events securely.

Sessions. Session timeout: absolute lifetime from sign-in (minutes/hours/days, e.g. 12 h) — not just idle, applies overnight too. Inactive devices: auto-revoke devices inactive 30, 60, 90, 180 days or 1 year (off by default). Revoked completely: keys, sessions, tokens — the last device of an account included; a new sign-in then registers a fresh device. The panel shows how many devices are pending removal.

Plus: invitation links with expiry, password policy, login throttling, branding, audit log without message content, IP-watch diagnostics.

💬 Features

💬 Full-featured chat

Direct messages, groups and channels, threads, mentions, reactions, Markdown, pinned messages, emoji and file attachments — all end-to-end encrypted.

🖼️ Files & media

Images, documents, videos — transferred encrypted, EXIF/GPS/XMP metadata removed automatically. Filename and type inside the ciphertext.

📞 Conferences

Voice and video calls with screen sharing, encrypted per call, keys only for confirmed members.

🔔 Notifications

Push carries only sender and location — never your text. UnifiedPush/FCM/APNs/Web Push supported.

🛡️ Verification

Safety numbers per person, device overview, alerts on new devices, optional auto-removal of stale devices.

🧹 Controlled deletion

System messages deletable immediately or automatically — the server securely overwrites stored events, leaving only a content-free deletion proof.

📦 Downloads

PlatformFileHow to start
🪟 Windows 10/11 (x64)Enigma-3-Setup-<Version>.exeRun. Replaces previous versions and keeps all data and keys.
🐧 Linux x86_64Enigma-3-<Version>-x86_64.AppImagechmod +x — then double-click.
🐧 Linux arm64Enigma-3-<Version>-arm64.AppImagechmod +x — then double-click.
🤖 Android 7+enigma3-<Version>.apkSigned release APK (CN=Enigma 3). Uninstall an existing debug APK first.
📱 iPhone / iPad—Use the web app in Safari.
🌐 Browser—Web app served directly from your own server.

All downloads from the official repository: Current release page. Only ever one version is available — older releases are deleted so no outdated packages stay in circulation. Checksums for all files: SHA256SUMS.txt.

  • Windows: the installer is unsigned. SmartScreen shows a warning — only confirm if this page was the source.
  • Android: install via “unknown sources”; the release key differs from test APKs.
  • Upgrades: install the new version over the existing one — all sessions, settings and keys are kept.

🔍 Verifying integrity

sha256sum -c SHA256SUMS.txt

The desktop app checks update notices automatically against these sums: without a matching checksum the app does not offer an update. Updates come exclusively from this repository — no tracking, no crash reporting, no background downloads.

⚡ Up and running in three steps

  1. Server — a Linux machine or VM with Docker Compose v2 (amd64/arm64). A single setup.sh sets up domains, Cloudflare, SMTP and Docker. Stack: SecureChat (server + web app), NATS (data), LiveKit (calls), Caddy or Cloudflare Tunnel (public access). You need your own domain and an SMTP mailbox. Details come from the server operator.
  2. App — download and install the package for your platform. Registration works by invitation link only — the operator decides who joins.
  3. Start securely — enter the server address, register with the owner e-mail, send invitations. First message: compare the safety number, test the first call. If the call drops, the router ports are missing. Everything else is default.
Worth knowing: Enigma 3 is self-hosted software for people who want to take back control — not a free hosted service. Running it needs your own Linux machine and a domain. Technical details, the security model and installation are fully documented in the open.

📄 The brochure as PDF

⬇ Brochure PDF (12 pages)

Everything important in one document: security, cryptography, threat model, platforms and setup — to forward per messenger or to print. Always current with the latest version.

Brochure checksum: 03d05d781cc9036f85cf856414f6ad876b2f8840b5664b9c72843652e30d88af

SecureChat-App on GitHub

Release packages, checksums and issues.

View on GitHub (opens in a new tab)

← Back to all scripts