GhostType

Private, client-side AES-256 encryption in the browser. Lock text, rich formatting and images behind a password – no account, no server, nothing stored or uploaded. All cryptography runs locally via the browser’s native Web Crypto API. Please note that this project was vibe-coded and meant as an experiment and not for mission-critical use.

Features

  • AES-256-GCM authenticated encryption (tamper is detected, not silently decrypted).
  • PBKDF2-HMAC-SHA256, 250,000 iterations, random 16-byte salt per message.
  • Rich input box: bold/italic/underline, lists, links, and images (paste or upload).
  • One input that accepts plaintext or an encrypted block, with auto-detection.
  • Output box with copy to clipboard — encrypted text, or decrypted rich content copied as HTML and plain text so formatting survives a paste into email, chat or docs.
  • PGP-style -----BEGIN GHOSTTYPE MESSAGE----- armor so blocks are obviously encrypted wherever they land.
  • Attachments — attach any files (≤ 50 MB each) to your message on the Encrypt screen. Text-only messages stay lean, pasteable armored blocks; once you attach files, the whole thing (message + every file, with their names and types) is sealed into one downloadable .ghost file. Decrypt accepts either a pasted block or an opened .ghost file and gives you the message plus a download for each attachment.
  • Passphrase generator — one click builds a memorable, high-entropy passphrase (six words + a number, ≈49 bits) using crypto.getRandomValues.
  • 100% offline-capable. No analytics, no network calls.

Run it

It is a static site – no build step.

# from the repo root
python3 -m http.server 8080
# then open http://localhost:8080

The Web Crypto API requires a secure context, so use http://localhost (treated as secure) or any https:// host. Opening index.html directly via file:// also works in most browsers.

Message format (v1)

Each encrypted blob is base64 of a binary envelope, wrapped in armor:

bytesmeaning
0format version (0x01)
1..16PBKDF2 salt (16 bytes)
17..28AES-GCM IV (12 bytes)
29..ciphertext + 16-byte GCM tag

Bundle format (v3 — message + attachments)

The same envelope is used for armored text and .ghost files; only the packaging differs. Envelope:

bytesmeaning
0bundle version (0x03)
1..16PBKDF2 salt (16 bytes)
17..28AES-GCM IV (12 bytes)
29..ciphertext of the bundle payload

Decrypted bundle payload: u32 msgLen · message · u16 fileCount · [ u16 nameLen · name · u16 typeLen · type · u32 dataLen · data ]×fileCount. Armored output is Base64 of the envelope in the BEGIN GHOSTTYPE MESSAGE block; a .ghost file is the 4-byte magic GHST followed by the raw envelope.

Project layout

index.html            # page + structure
src/styles.css        # styling
src/app.js            # UI controller (editor, clipboard, mode switching)
src/ghost-crypto.js   # the crypto engine — zero DOM deps, reusable in extensions

src/ghost-crypto.js is deliberately self-contained (window.GhostCrypto, also a CommonJS export) so the Firefox & Chrome extensions can bundle the exact same audited engine to encrypt/decrypt any field on the web – including email composers.

Security notes

  • There is no password recovery. A lost password means lost data, by design.
  • Decrypted content is rendered as HTML. Only decrypt blocks you trust, since decryption is the act of running content you (or whoever holds the key) authored.
  • The strength meter is guidance only – use a long, unique passphrase.

Demo

https://ghosttype.ramin.io

Github

https://github.com/raminhossaini/GhostType