JPEG Steganography Extractor
Extract hidden data from JPEG images encoded with F5, JSteg, or JPEG Comment/APP metadata. DCT scan mode, brute-force mode, and CTF heuristic guess mode included.
Upload stego JPEG to decode
JPEG image that may contain hidden metadata
Supports JPEG/JPG files · max 50 MB desktop, 20 MB mobile
How to Extract Hidden JPEG Data (5 steps)
- Upload the JPEG image you want to check.
- Click Scan — it shows a JSteg pairs-of-values chi-square p-value and a weak F5 indicator. They are statistical hints, not extraction results.
- Click Decode, or use Brute-Force to run a fixed list of extraction steps (it does not guess passwords).
- Enter a passphrase if the payload was encrypted or F5-protected.
- Copy the message or download the hidden file.
JPEG Steganography Detection Methods
| Method | Technique | Detection | Best For |
|---|---|---|---|
| Auto-Detect | Reads this tool's Comment or APP3 header first. If there is none, it tries F5 once (with the passphrase you typed, or with the built-in default key if you typed none), then JSteg | Stops at the first plausible result; success depends on the file | Unknown encoding method |
| F5 | Matrix decoding in the coefficient order set by your passphrase, or by the built-in default key when there is none; a wrong passphrase reads noise | Real DCT-domain extraction | When F5 is confirmed or suspected (via Scan Mode) |
| JSteg | Reads the low bit of every eligible coefficient (magnitude 2 or more) after a 32-bit length | Real DCT-domain extraction | When JSteg is confirmed or suspected (via Scan Mode) |
| JPEG Comment / APP Extension | Searches COM (0xFFFE) / APP3 (0xFFE3) segments for this tool's header | Direct, fast extraction | When a metadata method is confirmed |
| Brute-Force | Tries, in order and until one gives a plausible result: Comment → JSteg → F5 with your passphrase (only if you typed one) → F5 with the default key → CTF heuristic | A finite list of steps; it does not guess or crack passwords | Unknown method, CTF challenges |
| CTF Heuristic Guess Mode | Last resort: an F5 read (your passphrase, or the default key), then a raw JSteg read with no plausibility check. It does not implement the steghide algorithm | Best-effort only; this is not the steghide algorithm | Last resort (use the Steghide Extractor for steghide files) |
What This Extractor Reads
It reads the four layouts the JPEG Steganography Hider writes: F5 (a passphrase-shuffled matrix code in the DCT coefficients), JSteg (the low bit of every eligible coefficient, in file order), and the JPEG Comment and APP3 segments, which carry a text header. It also reads the Hider's two Plausible Deniability features, each through its own control in Forensic mode (see Plausible Deniability Files below).
Auto-Detect checks the Comment and APP3 headers first. If neither is present it tries F5 once, with the passphrase you typed or, if you typed none, with the built-in default key, then JSteg. It accepts a result only if the bytes read as text, as one of the file types in the table below, or as this tool's encrypted layout; unknown binary data can therefore be missed, and a payload may exist even when Auto-Detect reports nothing. For files made by other tools, such as steghide, use the Steghide Extractor; for metadata fields such as EXIF or XMP use the EXIF Data Extractor.
F5 Passphrases
Two separate operations use the passphrase, and they use different keys. F5 ordering: the permutation key is the SHA-256 hash of the passphrase, and it decides the order in which F5 visits the coefficients. When the Hider is given no passphrase the permutation key is a fixed default built into the tool (the text StegoToolkit), so the order is the same for every file and the Extractor needs nothing from you; that default gives no secrecy against anyone who knows the tool, and it is not an encryption key. Payload encryption: PBKDF2-HMAC-SHA-256 (100,000 iterations) derives the AES-256-GCM key from the same password, and the payload is encrypted whenever a passphrase was used. The Extractor must be given the same passphrase for both. A wrong passphrase does not give a password error: it reads the coefficients in the wrong order, the length field does not fit the image, and the result is the message that the passphrase is wrong, the data was hidden without one, or the file holds no F5 data. The same happens for a file with no F5 data at all.
Plausible Deniability Files
The Hider has two Forensic-mode deniability features. Plausible Deniability Mode (F5 only) puts a plain decoy comment in the Comment segment and hides the real, encrypted message with F5 without this tool's header; read it with Deniability Mode (F5) switched on and the passphrase. The panel Plausible Deniability — Decoy + Real Payload writes a plain decoy comment and an AES-256-GCM encrypted real payload hidden with JSteg; read it with Plausible Deniability Decode. In that panel the decoy needs no password and the real layer needs one passphrase; a blank passphrase shows only the decoy, and a wrong one shows the decoy and reports the real layer as not decrypted. Neither feature is found by Auto-Detect or the normal F5 or JSteg reads (checked in the tests), and each control reads only its own kind of file.
The Scan Panel
The scan runs before you decode and is detection, not extraction: nothing it shows is a decoded message. For JSteg it computes the pairs-of-values chi-square test over the coefficient values 2k and 2k+1 and reports the highest p-value over growing windows from the start of the coefficient walk: near 1 means the pairs look equalised, as they do after JSteg writes random-looking bits; near 0 means the observed coefficient pairs differ substantially from the equalised distribution the test expects after JSteg. A low p-value does not prove the image is clean: it only means the expected equalisation was not observed. HIGH is above 0.8, MEDIUM above 0.3. A p-value is a hint, not proof: other coefficient distributions can look similar, and it falls as a JSteg file is filled only partly. On 60 clean synthetic photos in our test set the p-value was below 0.001 for the 54 that had enough eligible coefficients (the other 6 are too small for the test and report that), and 7 of 9 JSteg files were flagged (conditions on the Hider page); that is an observation on one test set, not a general rate for clean JPEGs.
The F5 indicator counts the zero share of the luminance AC coefficients and compares it with a fixed expectation for the estimated quality (table below). The score is the difference times 500, at most 80, and it is MEDIUM above 50; its confidence is always LOW. The expectations are rough guesses, not a validated model, and the indicator does not separate F5 from clean photographs: it was MEDIUM on 45 of 60 clean test photos and on 5 of 9 F5 files. Treat it as a reason to try a decode, nothing more.
Brute-Force and CTF Heuristic Modes
Brute-Force is a fixed list of extraction steps, not a password search. It tries Comment, then JSteg, then F5 with your passphrase (skipped when you typed none), then F5 with the default key, then the CTF heuristic, and stops at the first hit that passes the same plausibility checks as Auto-Detect. It never guesses or cracks a passphrase: a wrong passphrase finds nothing. The CTF heuristic is the last step. It is an F5 read (with your passphrase, or the default key) followed by a raw JSteg read that skips the plausibility checks, so it can show an unknown binary payload or, rarely, noise. It does not implement the steghide algorithm and cannot extract steghide files.
Reed-Solomon and Encryption
For F5 and JSteg the Hider encrypts first, then wraps the encrypted bytes in Reed-Solomon, then adds a one-byte flag (0 = not encrypted, 1 = encrypted) and the method's length. The Extractor undoes this in reverse: it checks the flag, repairs a Reed-Solomon wrapper (marker RSC2), then verifies AES-256-GCM with your password. Comment and APP Extension have no flag byte: their text header says NONE or AES256GCM, and the Base64 that follows is the stored bytes, which are then unwrapped in the same order (Reed-Solomon, then AES). The Hider page lists the Reed-Solomon header, the parity per block (10, 20 or 30 bytes per 223) and the repair limits (5, 10 or 15 changed bytes per block). If blocks cannot be repaired the result says how many and shows those bytes as found; with a password the authentication then fails and you see a decryption failure. The 16-byte header, the length field and the flag are not repaired.
Layouts Read by Each Method
| Method | Where the bytes are | Needs | Gives up when |
|---|---|---|---|
| JPEG Comment | COM segment starting JPEGsteg:v1:COM: | Nothing (password if the header says AES256GCM) | The segment was removed or the header changed |
| APP Extension | APP3 segment starting STEG, then JPEGsteg:v1:APP: | Nothing (password if encrypted) | The segment was removed |
| JSteg | Low bit of eligible luminance AC coefficients, 32-bit length first | Nothing | The JPEG was re-encoded; the length does not fit |
| F5 | Matrix code over a passphrase-shuffled coefficient order | The passphrase, if one was used | Wrong passphrase; the JPEG was re-encoded |
What Each Mode Tries, in Order
| Mode | Steps, in order | What the passphrase is used for |
|---|---|---|
| Auto-Detect | 1. Comment or APP3 header. 2. F5 once. 3. JSteg. | Step 1: decrypts if the header says AES256GCM. Step 2: sets the F5 order and decrypts. Step 3: decrypts. |
| Brute-Force | 1. Comment. 2. JSteg. 3. F5 with your passphrase (skipped if none). 4. F5 with the default key. 5. CTF heuristic. | Steps 1 and 2: decrypts. Step 3: sets the F5 order and decrypts. Step 4: nothing (default key, never encrypted). Step 5: see the next row. |
| CTF heuristic (step 5) | a. An F5 read. b. A raw JSteg read. | a. Uses the selected key (your passphrase, or the default key) and the normal payload processing: Reed-Solomon repair, the flag byte, decryption when applicable, and the same plausibility checks as Auto-Detect. b. Skips the plausibility checks and the normal processing: no Reed-Solomon repair and no decryption; only the one-byte flag is removed, and data flagged as encrypted is not returned. |
F5 Indicator: Expected Zero Share by Estimated Quality
The F5 indicator compares the zero share of the luminance AC coefficients with these fixed expectations. The quality is estimated from the file's quantisation table. The expectations are rough guesses, not a validated model.
| Estimated JPEG quality | Expected zero share |
|---|---|
| 90 to 100 | 55% |
| 75 to 89 | 65% |
| 60 to 74 | 72% |
| Below 60 | 80% |
File Types Recognised in the Recovered Bytes
These nine are the only signatures the Extractor recognises. A match identifies a possible file type from its opening bytes; it does not validate the file. Bytes that are readable text are shown as text even when they begin with the same letters, and unknown binary is not reported by Auto-Detect.
| Type | First bytes |
|---|---|
| 25 50 44 46 | |
| ZIP | 50 4B 03 04 |
| PNG | 89 50 4E 47 |
| JPEG | FF D8 FF |
| GIF | 47 49 46 38 |
| MP3 | 49 44 33 (an ID3 tag) |
| RIFF / WAV | 52 49 46 46 |
| ELF | 7F 45 4C 46 |
| EXE | 4D 5A |
Examples
Input: The 640×480 test photo with a 695-byte message hidden by F5 without a passphrase.
Result: Auto-Detect finds no Comment or APP header, tries F5, and returns the 695 bytes.
Meaning: Without a passphrase F5 uses the key built into the tool (StegoToolkit), so the coefficient order is known and the reading works without any input.
Input: The same file read with F5 and a passphrase.
Result: No payload: the passphrase shuffles the coefficient order, so the reading is noise and the length field does not fit the image.
Meaning: A wrong passphrase and a file without F5 data look the same.
Input: A 695-byte message hidden by F5 without a passphrase, opened with Brute-Force while the passphrase box holds some text.
Result: Brute-Force finds it at step 4, F5 with the default key (steps 1 to 3 find nothing).
Meaning: Auto-Detect would try F5 only with the typed text and miss it; Brute-Force also tries the default key.
Input: A message that starts "GIF89 party" hidden with JSteg, Auto-Detect.
Result: The message is shown as text, not as a GIF file.
Meaning: Readable text wins over a file signature; real binary files of the nine listed types are still reported as files.
Input: A clean JPEG, Auto-Detect.
Result: Nothing is reported. The JSteg scan p-value was below 0.001 for all 54 clean synthetic photos in our test set that were large enough for the test (6 of the 60 were too small).
Meaning: A clean photograph keeps unequal coefficient pairs. This is an observation on one test set, not a general threshold for clean JPEGs.
How the JPEG Extractor Works
1. Parse
The JPEG is parsed in a Worker to its quantized coefficients; scanning and decoding never run on the page itself.
2. Extract
The selected method reads its bytes. Comment and APP3 read a text header and Base64; JSteg reads a length and bits from eligible coefficients; F5 undoes its matrix code in the passphrase order and checks its own length field against what the image can hold.
3. Unwrap
The one-byte encrypted flag is checked, a Reed-Solomon wrapper (marker RSC2) is repaired first where it can be, and then AES-256-GCM is verified with your password. This is the reverse of the Hider, which encrypts first and adds Reed-Solomon second.
4. Interpret
The bytes are classified as text, a known file type, binary or encrypted-looking, and CTF flag shapes are highlighted.
What the results mean
| Result | What it means | What to do |
|---|---|---|
| Text or a file came out | A layout matched and the bytes are readable or have a known file signature. | Copy or download it. |
| Still encrypted | The payload has the AES layout and no or a wrong password was given. | Enter the password; a wrong password and changed bytes look alike. |
| Nothing found | No layout produced a plausible payload. | Pick F5 or JSteg by hand, try the passphrase, or check whether the file was re-encoded after hiding. |
| Scan says 'likely JSteg' but nothing decodes | A statistical hint, not proof. | Try Brute-Force; the file may have been re-encoded. |
| Evidence: Header found / Read from coefficients | Header found: a Comment or APP segment carries this tool's header. Read from coefficients: F5 or JSteg data was read and looked plausible. | Neither is a percentage; there is no suspicion score. |
| Reed-Solomon note | Bytes repaired, or blocks it could not repair (shown as found, possibly wrong). | If blocks are beyond repair, try the original file rather than a copy. |
Limitations
- Only this tool's own layouts are read. Files made by steghide, outguess or other programs are not.
- Re-encoding after hiding (a re-save, a resize, many upload services) destroys F5 and JSteg data.
- A wrong F5 passphrase and a clean file both report nothing found; a wrong AES password and altered bytes both report a decryption failure.
- The scan panel is statistical and was only checked against this tool's own JSteg and F5 files and clean synthetic and test photos. Its F5 indicator is MEDIUM on most clean synthetic photos, so it cannot tell F5 from a clean photograph.
- Brute-Force is a fixed list of steps and does not guess passphrases. The CTF heuristic is not steghide decoding and can return noise.
Privacy
The JPEG is parsed and analysed in your browser; the tool's own code does not upload it. Usage statistics may record which options were used and coarse facts such as sizes, never your image or the extracted bytes. The host keeps ordinary request logs. For encrypted payloads the password is processed with PBKDF2-HMAC-SHA-256 (100,000 iterations) to derive the AES key; F5 also uses a SHA-256-derived key, from the passphrase or the built-in default, for its coefficient ordering. The password is turned into a key with PBKDF2-HMAC-SHA-256 (100,000 iterations) and the salt stored in the payload, and the AES-256-GCM authentication tag then checks it. A wrong password and a damaged payload both simply report failure, so the tool cannot tell you which it was, and there is no way to recover a forgotten password. The full description, including what this scheme does not protect, is on the [JPEG Steganography Hider](/steganography/jpeg-steganography-hider) page.
Which Tool Next?
- JPEG Steganography Hider — create a file this tool reads
- Steghide Extractor — extract from files made by the real steghide program
- EXIF Data Extractor — metadata fields such as UserComment, XMP and GPS
- Steganography Detector — statistical checks for hidden data in an image
Frequently Asked Questions
Why don't zsteg or stegsolve decode JPEG steganography?
zsteg and stegsolve operate on pixel data. JPEG steganography (JSteg, F5) embeds data in quantized DCT coefficients — the frequency-domain representation of pixel blocks. Pixel-domain tools are blind to it. This decoder analyzes JPEG DCT coefficients directly.
How do I decode a steghide JPEG CTF challenge?
steghide uses graph-theoretic embedding, not DCT LSB or F5. CTF Heuristic Guess Mode only runs an F5 read and a raw JSteg read (see the table above); it does not implement the steghide algorithm and cannot extract steghide files. Use the Steghide Extractor on this site, or the real steghide program (steghide extract -sf file.jpg).
The scan says 'likely JSteg' but decode returns nothing — why?
The scan shows a statistical hint, not certainty (and clean photos can occasionally score above zero). The JPEG may have been re-encoded after embedding (social platform upload), which changes DCT coefficients and destroys the embedding. Check if you have the original file vs. a re-encoded copy.
Auto-Detect finds nothing but I know something is hidden. Why?
For F5 and JSteg there is no header to confirm a hit, so Auto-Detect accepts an unencrypted result only if it reads as text or as a file type it recognises, and an encrypted one only if it has this tool's AES layout. Binary data of an unknown type is not reported in Auto mode, so a payload can exist even when Auto-Detect reports nothing: choose F5 or JSteg yourself, and enter the passphrase if F5 was used with one. A wrong F5 passphrase reads noise, so it also shows as nothing found. Auto-Detect tries F5 only once: with the passphrase you typed, or with the built-in default key if you typed none, so a file hidden without a passphrase is not found while a passphrase is typed. Brute-Force tries both.
Does this read files made by steghide?
No. steghide uses a different embedding. Use the [Steghide Extractor](/steganography/steghide-extractor), which reads steghide files, or the real steghide program.
Can this detect outguess?
Not yet. outguess corrects the DCT histogram after embedding to disguise its statistical signature, which is much harder to detect than JSteg's LSB bias or F5's shrinkage pattern.
How do I read a Plausible Deniability file?
There are two features and two controls, both in Forensic mode. For a file made with Plausible Deniability Mode (F5), switch on Deniability Mode (F5) and type the passphrase: Auto-Detect and the normal F5 read do not find it. For a file made with the panel Plausible Deniability — Decoy + Real Payload, use Plausible Deniability Decode: with no passphrase it shows only the decoy comment, with the right passphrase it also shows the real payload, and with a wrong one it still shows the decoy and says the real layer could not be decrypted. The two features are not interchangeable: each control reads only its own kind of file.
Does Auto-Detect try F5 with and without a passphrase?
No. Auto-Detect tries F5 once, with the passphrase you typed or, if you typed none, with the built-in default key. It never tries both. Brute-Force is the mode that tries F5 with your passphrase (only if you typed one) and then F5 with the default key.
Which file types does the Extractor recognise?
PDF, ZIP, PNG, JPEG, GIF, MP3 (an ID3 tag), RIFF/WAV, ELF and EXE (MZ), by their opening bytes. A match does not mean the recovered file is complete or valid, and nothing else is recognised. Readable text is shown as text even when it begins with the same letters as a signature (for example a message starting GIF89 or %PDF).
Why is my extracted data showing as encrypted?
If the original encoder used a passphrase, the payload is AES-256-GCM encrypted. Enter the same passphrase used at encode time.
Does the Extractor show a suspicion score?
No percentage is shown. The result shows Evidence: Header found when a Comment or APP segment carries this tool's header, which is conclusive, or Read from coefficients when F5 or JSteg data was read, for which there is no header and the only evidence is that a plausible payload came out. A percentage built from the share of coefficients equal to +1 or −1 would be high on ordinary photographs (the median was 61 on 60 clean test photos) and says nothing about hidden data. The scan panel's p-value is a statistical hint, not proof; recompressed or noisy JPEGs can show a similar signal without containing steganography.
Related Tools
JPEG Steganography Hider
Hide secret data inside real JPEG images using DCT-domain steganography (F5, JSteg) — embedded in the JPEG's own quantized DCT coefficients, not pixels. Also supports JPEG Comment/APP metadata storage.
Image Steganography Extractor
Extract hidden messages from steganographic image files. Auto-detect mode, bit plane analysis.
Steganography Detector
Statistical steganalysis with three published tests — chi-square, RS analysis and Sample Pairs — fused into one score and checked against the real StegExpose on a small test set. Payload size estimate. Method fingerprint. WAV audio support. Processed in your browser, not uploaded.