A while back, I got obsessed with a question: what if you could hide a file inside a photo, and no one could tell it was there?
That curiosity turned into Stego.Image — a client-side web app that combines steganography, AES-256 encryption, and GZIP compression to secretly embed files inside ordinary images. No server. No uploads. No trace.
🔗 Live Demo → stegoimage.pages.dev
The Core Idea: Two Layers of Security
Most security tools give you one lock. Stego.Image gives you two:
- Steganography hides the existence of the data — to any observer, it's just a regular image.
- Encryption protects the contents of the data — even if someone knows something is hidden, they can't read it without the password. This combination is sometimes called "security through obscurity + cryptographic security." Neither alone is bulletproof. Together, they're a meaningful barrier.
How It Works
Step 1 — Compress
Before anything else, the input file is compressed using GZIP (via the pako library). This reduces the payload size, which matters because the amount of data you can hide is constrained by the image's pixel count.
Step 2 — Encrypt
The compressed bytes are encrypted with AES-256 using crypto-js. The key is derived from a user-provided password. No password = no data. This step ensures the hidden payload is unreadable gibberish without the correct credentials.
Step 3 — LSB Steganography
Here's the fun part. The encrypted bytes are embedded into the Least Significant Bits of the image's RGB pixel values.
Original pixel value: 11001010
Modified pixel value: 11001011
Changing the last bit of a color channel moves the value by at most 1 — from 0 to 255, that's invisible to the human eye. The output image looks identical to the original, byte for byte to the eye, but it's secretly carrying your data.
Extraction
Decoding reverses the process: extract the LSBs → decrypt with the password → decompress → reconstruct the original file.
What Can You Hide?
Basically anything binary:
- Documents (PDF, DOCX, TXT)
- Images (PNG, JPG, GIF — yes, an image inside an image)
- Archives (ZIP, RAR, 7z)
- Media files (MP3, MP4)
- Code files (JS, Python, JSON)
Why 100% Client-Side Matters
The decision to keep everything in the browser wasn't just a technical choice — it was a privacy choice.
If files were sent to a server for processing, that server operator could log them, inspect them, or have them compromised in a breach. By processing everything locally using the Web Crypto API and canvas manipulation, the user's data never leaves their device.
No server = no attack surface on the server side.
The Tech Stack
| Category | Library |
|---|---|
| Framework | React + Vite |
| Styling | Bootstrap |
| Encryption | crypto-js |
| Compression | pako |
| File Handling | file-saver |
| Archive Output | jszip |
| File Upload | react-dropzone |
| Routing | react-router-dom |
Interesting Challenges
Capacity math. The image has to be large enough to hold the payload. Each pixel contributes 3 bits of storage (1 per RGB channel). A 1000×1000 image has 1,000,000 pixels = ~375 KB of storable data before accounting for metadata overhead. The UI shows a live capacity indicator so users know upfront if their image is big enough.
PNG is required for output. JPEG compression is lossy — it would destroy the LSB data. The output is always a PNG, even if the input was a JPEG.
Key derivation matters. A weak or simple password makes the AES-256 encryption only as strong as the password. Future work could add PBKDF2 or Argon2 to stretch the key and resist brute-force attacks.
What I Learned
Building this taught me more about how images work at the bit level than any tutorial ever did. It also got me thinking about the gap between "encrypted data" and "hidden data" — and why both matter in different threat models.
Steganography has real-world uses: journalists communicating in high-censorship environments, digital watermarking, and covert channels in security research. It's also a great vehicle for learning about cryptography and binary manipulation.
Try It or Contribute
- 🌐 Live App: stegoimage.pages.dev
- GitHub: Stego.image
- Licensed under MIT
If you find this interesting, have ideas for improvements, or want to contribute, pull requests are welcome. I'd especially love feedback on the UX and any edge cases people find in the capacity/encoding logic.
Top comments (0)