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
.ghostfile. Decrypt accepts either a pasted block or an opened.ghostfile 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 anyhttps://host. Openingindex.htmldirectly viafile://also works in most browsers.
Message format (v1)
Each encrypted blob is base64 of a binary envelope, wrapped in armor:
| bytes | meaning |
|---|---|
0 | format version (0x01) |
1..16 | PBKDF2 salt (16 bytes) |
17..28 | AES-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:
| bytes | meaning |
|---|---|
0 | bundle version (0x03) |
1..16 | PBKDF2 salt (16 bytes) |
17..28 | AES-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.