Scroll
Index / Work / 02 · WhisperBox
2026 HNG Internship 14 · Stage 4b Solo · frontend React 19 · WebSocketWeb CryptoE2E

WhisperBox is an end-to-end encrypted messenger that runs the entire cipher in the browser. RSA-OAEP wraps each conversation’s symmetric AES-GCM key, the user’s private key is itself wrapped behind PBKDF2 with 100,000 iterations, and the server only ever sees opaque envelopes it routes over WebSocket.

Client
HNG Internship 14 · Stage 4b
Role
Solo · frontend
Duration
04 / 2026
Stack
React 19 · Vite · TanStack Router · TanStack Query · WebSocket · Web Crypto · Tailwind
WhisperBox — cover
WHISPERBOX · 2026 · COVER PLATE
02 / 11
RSA-OAEP
2048-bit keypair
AES-GCM
fresh key per message
100k
PBKDF2 iterations
Account setup · keys generated client-side
Account setup · keys generated client-side
§ 03 · Chapter

Crypto stays on the client

Registration generates a 2048-bit RSA-OAEP keypair and derives a wrapping key from the user’s password via PBKDF2-SHA256. The private key is encrypted with AES-GCM under that wrapping key, then handed to the server as an opaque blob. Sending a message generates a fresh AES-GCM key, encrypts the body, and wraps the symmetric key once for the recipient and once for the sender so history stays readable on either side.

Sign in · the server never sees a plaintext byte
Sign in · the server never sees a plaintext byte
§ 05 · Chapter

The trade-offs I made on purpose

The README ships the limitations on the front page: JWTs live in localStorage, the unwrapped private key sits in IndexedDB during a session, PBKDF2 was the right call for a stage submission but Argon2 would be the right call for a product, and identity verification is trust-on-first-use. WhisperBox is a working proof — not a Signal replacement, and I wrote it that way.

§99 · Continue

Have a brief?
Let's talk.

© 2026 · Moluno · Powered by sapa
v2.04.026 · 60Hz · 6.5244 N · 3.3792 E