← moodev
steganofox
demos / steganofox

Demo · covert-io · runs entirely in your browser

The image is the zip.

Every pixel has three color channels, and every channel has a bit nobody's eye can see: the least significant one. Flip a few million of those in a deliberate pattern and you've got a whole file riding inside a picture that looks completely untouched. No server, no upload. The embedding and the extraction both happen on your machine, in a canvas element.

hide something in a cover image
download the output, it looks identical
feed it back into the reveal panel
A

Panel A · encode

Hide something in a picture

Pick a cover image, then a secret: type a message or attach a small file. Steganofox writes it into the low bit of each red, green and blue channel and hands you back a PNG.

encoder · LSB writeready

① Cover image

② The secret

capacity used0%
cover capacityupload a cover first
payload + header0 bytes
statuswaiting on a cover image

Before / after

before · cover
no cover yet
after · stego output
not generated yet

Log

$ waiting for a cover image and a secret…
B

Panel B · decode

Pull it back out

Drop in a stego PNG from Panel A (or any image someone else made with this tool). Steganofox reads the header, checks the magic bytes, and recovers exactly as many bytes as it was told to expect.

decoder · LSB readready

Stego image

uploaded image
nothing loaded

Reveal only works on the exact bytes the encoder produced. If this image gets re-saved as a JPG, converted, resized, or screenshotted, the low bits get scrambled and there's nothing left to recover. PNG in, PNG out, PNG back in.

Recovered

statuswaiting on an image

Log

$ waiting for a stego image…
·

How it actually works

No encryption, just a hidden channel

This is steganography, not cryptography: the point is that nobody looking at the image knows there's anything in it, not that the payload is unreadable if found. Four things make the round trip possible.

1. One bit per channel

Each pixel gives up the last bit of its R, G and B values (alpha is left alone). Changing that bit shifts the color value by at most 1 out of 255. Invisible to the eye, easy to read back with code.

2. A magic header

The first 4 bytes written are always SFX1. Reveal checks for that exact sequence before trusting anything else in the image. No match means no payload, or a corrupted one.

3. A length prefix

Right after the header comes a type byte, an optional filename, and a 4-byte big-endian length. That's how the decoder knows exactly where the payload ends instead of guessing or scanning for a terminator.

4. Lossless the whole way

The output is always a PNG. PNG compresses without touching a single pixel value, so the bits you wrote are the bits you get back. A JPG re-encode would round pixel values and destroy the message.