Jazil Imran
← All work

03 / 06End-to-end encrypted messaging2026

Encrypta

Messaging, group chat and video calls where everything is encrypted on your device. The server stores and relays ciphertext it cannot read.

X25519direct-message key exchange
AES-256-GCMmessages and sealed keys
600,000PBKDF2 iterations, run on your device

01 · Try it

Live · runs in your browserX25519 · HKDF-SHA256 · AES-256-GCM

Alice’s device

public key
shared secret

The server sees

Nothing yet.

Act as a malicious server:

Bob’s device

public key
shared secret

decrypted

Real keys, generated just now by your browser and thrown away when you leave. Each side computes the shared secret from its own private key and the other’s public key, so it never crosses the wire.

02 · The problem

Most chat apps ask you to trust the server with your messages. Encrypta is built so the server never has to be trusted with them: it sees who is signed up and who is online, and nothing else.

03 · How it works

Scroll the steps. The scene follows.

password••••••••••
PBKDF2-SHA256 rounds
HKDF → auth7c1e…a90f
7c1e…a90f
server storesArgon2id(7c1e…a90f)the password itself: never sent
public keyX25519 · shared
private keyX25519 · yours
sealed with AES-256-GCMIndexedDB · non-extractable

generated in the browser at sign-up, sealed under a key derived from your password

alice writesmeet me outside Caius at seven9f3a c1e0 77b4 02de 51aa e8c3 90f1 …
bound as associated datafrom alice → to bob
server rewrites the senderfrom mallory → to bob✗ tag mismatch · rejected
ABCD
group keyv1 · sealed to A B C Dv2 · sealed to A B C

when D leaves, the next sender makes a new key that D never receives

Illustrated from the project’s README and code. Values shown are examples.

  1. 01

    Your password never leaves the device

    The browser runs PBKDF2-SHA256 (600,000 iterations) to derive a master secret. The server receives HKDF(master, "auth"), stored as an Argon2id hash. The password itself is never sent.

  2. 02

    Keys made and sealed on the device

    An X25519 key pair is generated in the browser at sign-up. The private key is sealed with AES-256-GCM under a separate derived key and kept in IndexedDB as a non-extractable CryptoKey.

  3. 03

    Messages bound to their sender

    Direct messages use X25519 → HKDF-SHA256 → AES-256-GCM with a fresh 96-bit IV. Sender and recipient ids are bound in as associated data, so the server cannot redirect a message or forge who it came from.

  4. 04

    Groups that rotate keys

    Each group has a shared AES-256 key sealed to every member. When someone leaves, the next sender generates a new key sealed only to those who remain. Calls are peer to peer over WebRTC with DTLS-SRTP.

04 · Architecture

The whole system, running.

Passwordnever leaves the devicePBKDF2-SHA256600,000 iterationsHKDF → authstored as Argon2idX25519 key pairmade in the browserAES-256-GCMfresh IV · ids as AADServerrelays ciphertext onlyIndexedDBnon-extractable keyHKDF → key-wrapseals the private keyGroup keyrotates on leaveWebRTC callsDTLS-SRTP, peer to peer

05 · Stated plainly

There is no forward secrecy (no Double Ratchet), so someone who later learns a password and holds stored ciphertext could read that user’s history.

Like every web-based E2EE app, it is only as trustworthy as the JavaScript the server delivers.

Built with

  • React
  • TypeScript
  • WebCrypto
  • FastAPI
  • PostgreSQL
  • WebSockets
  • WebRTC
  • Docker