You send someone a photo of a sunset. They open it, admire it, maybe save it. What they do not know is that the photo contains a hidden message — encrypted, invisible, and statistically undetectable. That is steganography.
This guide covers everything you need to know: what steganography is, how it works inside JPEG images, the two fundamentally different approaches (stealth and robustness), why social media makes it hard, and where the real limitations lie. Whether you are a journalist protecting a source, a security researcher studying detection methods, or someone who just thinks hidden messages are fascinating, this page is your starting point.
What Is Steganography?
Steganography is the practice of hiding a secret message inside an ordinary-looking object — an image, an audio file, a video — so that no one suspects the message exists. The word comes from Greek: steganos (covered) and graphein (writing). Literally, “covered writing.”
The critical distinction is between steganography and encryption:
| Encryption | Steganography | |
|---|---|---|
| What it does | Makes data unreadable | Hides data’s existence |
| What an observer sees | Scrambled data (clearly secret) | An ordinary file (nothing suspicious) |
| Raises suspicion? | Yes — encrypted data screams “I have secrets” | No — the carrier looks normal |
| If discovered | Message is unreadable without the key | The jig is up, but encryption can add a second layer |
| Best used for | Protecting data at rest or in transit | Covert communication, plausible deniability |
Encryption and steganography are not mutually exclusive. The strongest approach uses both: encrypt the message first, then hide the ciphertext inside an image. Even if someone discovers the hidden data, they cannot read it without the key. This is exactly what modern steganography tools do — Phasm, for example, encrypts every message with AES-256-GCM-SIV before embedding it, even if you do not set a passphrase.
A Brief History
Steganography is not a modern invention. Humans have been hiding messages for as long as they have been sending them.
Ancient world. Herodotus recorded the earliest known example around 440 BCE: a Greek noble named Histiaeus shaved a slave’s head, tattooed a message on the scalp, waited for the hair to regrow, then sent the slave through enemy territory. Around the same time, Demaratus of Sparta warned Greece of a Persian invasion by scraping wax off a tablet, writing on the wood beneath, then re-covering it with fresh wax. The tablet passed inspection because it appeared blank.
Renaissance to early modern. Invisible ink became a standard espionage technique — lemon juice, milk, or chemical compounds visible only when heated. During both World Wars, microdots (photographs shrunk to the size of a printed period) carried documents across borders in plain sight.
The digital age. When images became files made of numbers, steganography found its most powerful medium yet. A digital photograph contains millions of values that can be subtly altered to carry hidden data — invisible to the human eye and, when done carefully, undetectable by statistical analysis. The first digital steganography tools appeared in the mid-1990s. The field has since evolved from simple bit-flipping to sophisticated algorithms grounded in information theory and perceptual modeling.
How Image Steganography Works
At its core, image steganography modifies values in an image file to encode a message. The approach depends on which values you modify and how.
Spatial Domain: Changing Pixels Directly
The simplest method is LSB (Least Significant Bit) replacement. Every pixel is stored as a number (0 to 255 per color channel). Changing the last bit — from 134 to 135 — is invisible to the human eye, and each modified pixel carries one bit of message.
LSB replacement is easy to implement but easy to detect. Modern steganalysis tools identify it with over 99% accuracy. It is a teaching tool, not a serious security method.
Transform Domain: Working with Coefficients
More advanced methods work in the transform domain — the mathematical representation of the image after applying a transform like the Discrete Cosine Transform (DCT).
JPEG images are stored in the DCT domain. The image is divided into 8x8 pixel blocks, each transformed into 64 DCT coefficients representing different spatial frequencies, then quantized (rounded) and stored. Modifying these coefficients rather than pixels offers two advantages: the changes blend with the quantization noise JPEG compression already introduces, and embedding operates in the same domain as the compression — avoiding the lossy pixel round-trip that would destroy hidden data.
The question becomes: which coefficients do you modify, and how?
Content-Adaptive Embedding
Not all coefficients are equally safe to modify. Smooth regions (clear skies, white walls) are statistically predictable — any change is detectable. Textured regions (tree bark, gravel, woven fabric) already contain high-frequency energy that masks small changes.
Modern steganography uses cost functions that assign a numerical cost to modifying each coefficient. High-cost coefficients (smooth areas) are left untouched; low-cost coefficients (textured areas) absorb the message. The most widely studied cost functions include:
- UERD (Uniform Embedding Revisited Distortion): Estimates cost from block energy and frequency weighting, working entirely in the DCT domain.
- J-UNIWARD (JPEG Universal Wavelet Relative Distortion): Decompresses the image, computes directional wavelet filter responses, and measures how much each coefficient change disturbs those responses. More expensive to compute, but assigns finer-grained costs. For a detailed comparison, see our benchmark: UERD vs J-UNIWARD Detection Benchmarks.
The cost map tells you where to embed. You still need an efficient coding scheme to embed the message while minimizing total distortion. That is the job of Syndrome-Trellis Codes, which we cover in depth in our practical STC implementation guide.
JPEG Steganography Deep Dive
JPEG is the dominant format for steganography for practical reasons: it is the most common image format on the internet and on phone cameras, it already introduces quantization noise that masks small changes, and its DCT-domain storage gives direct access to the coefficients used for embedding.
Why JPEG, Specifically?
Most image formats (PNG, BMP, TIFF) store pixel values losslessly — any modification is faithfully recorded. JPEG is lossy: it rounds coefficients during compression, so small modifications (+1 or -1 to a coefficient) are statistically indistinguishable from the rounding JPEG itself performs. The quantization noise provides natural cover.
The catch: you need a codec that reads and writes DCT coefficients directly, without decompressing to pixels and recompressing. Standard image libraries (libjpeg, PIL, browser canvas APIs) decode to pixels, destroying any embedded data. Building a pure Rust JPEG coefficient codec that operates entirely in the DCT domain was one of the foundational engineering challenges.
DCT Coefficients and Quantization
Each 8x8 block of the image produces 64 DCT coefficients: one DC coefficient (the block average brightness) and 63 AC coefficients (representing progressively higher spatial frequencies). The JPEG quantization table determines how aggressively each frequency is rounded. Low-frequency coefficients retain more precision; high-frequency coefficients are quantized more aggressively.
For steganography, the quantized AC coefficients are the primary embedding space. The DC coefficients are usually avoided because they represent block averages and are more sensitive to visual artifacts. However, for certain robust methods, DC coefficients and block averages become valuable precisely because they survive recompression better — a tradeoff we explore in our analysis of JPEG recompression invariants.
Two Approaches: Stealth vs Robustness
There is a fundamental tension in steganography: do you optimize for being undetectable, or for surviving modifications to the image? You generally cannot do both at once. This leads to two distinct approaches.
Stealth: Ghost Mode
The stealth approach prioritizes making the embedding statistically undetectable. The goal is that no steganalysis tool — no matter how sophisticated — can distinguish a stego image from a clean one.
Phasm’s Ghost mode implements this approach using:
- J-UNIWARD cost function: Assigns embedding costs based on directional wavelet relative distortion. At the low embedding rates typical of real-world use (0.02-0.04 bpnzAC for a short message in a smartphone photo), the best deep-learning steganalyzers achieve only 56-62% detection accuracy — barely above the 50% random-chance baseline. For benchmarks, see UERD vs J-UNIWARD Detection Benchmarks.
- Binary Syndrome-Trellis Codes (h=7): An efficient coding scheme that embeds the message payload while minimizing total distortion cost, using Viterbi-like path optimization through a trellis structure. See Syndrome-Trellis Codes: A Practical Guide.
- AES-256-GCM-SIV encryption with Argon2id key derivation: Every message is encrypted before embedding, regardless of whether you set a passphrase. The encryption key is derived using Argon2id, the current state-of-the-art password hashing algorithm.
Ghost mode is designed for scenarios where the image will not be recompressed or resized after embedding. Send the file directly — via AirDrop, email attachment, cloud link, or “send as file” mode on messaging apps. If the image passes through a platform that recompresses it, the embedded message will likely be destroyed.
Robustness: Armor Mode
The robust approach prioritizes surviving modifications to the image — recompression, format conversion, even geometric transformations like rotation and cropping. The embedding is designed to be recoverable even after the image has been processed.
Phasm’s Armor mode uses a different set of techniques:
- STDM (Spread Transform Dither Modulation): A quantization-based embedding method that encodes data by quantizing coefficient values to specific grid points. The quantization structure survives moderate recompression because the embedded values are “attracted” back to the correct grid during re-quantization.
- Reed-Solomon error correction: Adds parity data so that corrupted bits can be recovered. Combined with adaptive repetition coding for short messages, the system tolerates bit error rates that would destroy uncorrected data.
- Watson perceptual masking: Adapts the embedding strength per-block based on a model of the human visual system, concentrating distortion where it is least visible. See Watson Perceptual Masking for QIM Steganography.
- DFT template for geometric resilience: Embeds a Fourier-domain template that allows the decoder to detect and reverse rotation, scaling, and moderate cropping applied to the image after embedding. See DFT Template Embedding for Geometric Resilience.
- Soft majority voting with log-likelihood ratios: When the message is short relative to image capacity, the extra space is used for repetition coding. Instead of simple hard-decision majority voting, the decoder uses confidence-weighted combination for more accurate recovery. See Soft Majority Voting and LLR Decoding.
Armor mode survives same-quality-factor recompression at over 99%, mild quality drops at over 95%, and cross-library recompression at over 95%. For full benchmarks, see Surviving JPEG Recompression.
The WhatsApp Problem
Social media platforms do not just store your photos. They resize, recompress, strip metadata, and sometimes re-encode with entirely different quantization tables. This is devastating for steganography.
We tested 15 major platforms and found three tiers:
- Preserves or mildly recompresses (steganography-friendly): Direct file sharing, email, AirDrop, phasm.link, “send as file” on most messengers.
- Recompresses but does not resize (Armor mode survives): Telegram (under 2560px), Twitter/X (under 4096px on web), Facebook (under 2048px).
- Aggressively recompresses and/or resizes (destructive): Instagram, WeChat, Snapchat, WhatsApp standard mode.
The third tier was historically a dead zone for steganography. WhatsApp’s standard mode — the default when you send a photo — applies aggressive recompression with a low quality factor and custom quantization tables. Every known DCT-domain steganographic method failed against it.
Fortress Sub-Mode
Armor mode includes a sub-mode called Fortress that targets this problem. Instead of embedding into individual AC coefficients, Fortress uses BA-QIM (Block Average Quantization Index Modulation) — embedding data into DC block averages, the most stable values in a JPEG image. Block averages change very little even under aggressive recompression and moderate resizing.
Fortress auto-activates for short messages within Armor mode. It survives WhatsApp standard recompression end-to-end — the headline capability. It also survives WhatsApp HD mode. For longer messages, the capacity of block averages is insufficient, and the standard STDM path is used instead.
This is not a universal solution. Instagram, WeChat, and Snapchat still destroy embedded messages. But for the world’s most popular messaging platform, steganography is now feasible for short messages without requiring “send as file.”
Cross-Platform Challenges
Steganography software that runs on multiple platforms faces a subtle but critical requirement: determinism. The encoder and decoder must make identical decisions — which coefficients to use, what costs to assign, how to generate the embedding permutation — regardless of whether they are running on iOS, Android, or a web browser.
This is harder than it sounds. Standard math functions like sin and cos are not guaranteed to produce bit-identical results across platforms. An iPhone’s libm may round differently than Chrome’s V8. For steganography, where the decoder must reconstruct the exact permutation and cost map the encoder used, a single-bit floating-point difference can cascade into total decoding failure.
Phasm solves this with a deterministic math module built on FDLIBM, a reference implementation of IEEE 754 math functions producing identical results everywhere. The project also includes an in-house FFT (Cooley-Tukey + Bluestein) to avoid platform-dependent Fourier transform behavior.
The core engine is written in pure Rust, compiling to native code for iOS and Android and to WebAssembly for the web — one codebase, identical output on every platform.
Steganography Security
Steganography alone is not encryption. It hides the existence of a message, but if someone discovers the hidden data, they can read it — unless it is also encrypted. Modern steganography tools combine both.
Encryption Always On
In Phasm, every message is encrypted with AES-256-GCM-SIV before embedding, regardless of whether you set a passphrase. The key is derived using Argon2id, a memory-hard function designed to resist GPU and ASIC brute-force attacks. Without a passphrase, a default key is used — the data is encrypted, but anyone with the same tool could decode it. Setting a passphrase adds a layer only you can unlock.
The combination means:
- An observer looking at the image sees a normal photo (steganography).
- Even if they suspect a hidden message, statistical analysis cannot confirm it at low embedding rates (undetectability).
- Even if they extract the hidden data, it is encrypted and unreadable without the passphrase (encryption).
Open Source and Auditability
For security software, trust requires transparency. The core steganography engine — the Rust crate that handles all encryption, key derivation, embedding, and extraction — is open source under GPL-3.0 at github.com/cgaffga/phasmcore. Every line of code that touches your message is auditable. For the reasoning behind what is open and what is not, see Why We Open-Sourced the Engine, Not the App.
All processing happens client-side. Your message, your passphrase, and your images never leave your device (unless you explicitly use the cloud sharing feature on phasm.link, in which case the already-embedded stego image is uploaded — the plaintext message is never transmitted).
Who Uses Steganography?
Steganography is not just for spies. The practical use cases are broader and more grounded than Hollywood suggests.
Journalists and Sources
A journalist in a country with press censorship needs to receive documents from a source. Encrypted email is blocked. Encrypted messengers are banned. But sending a photo is normal — everyone does it. A source embeds a message in a vacation photo and sends it through an ordinary channel. Even if intercepted, the photo looks like a photo. Nothing to flag, nothing to block, nothing to decrypt. Steganography adds a layer encryption alone cannot provide: deniability.
Activists and Dissidents
In authoritarian contexts, the very act of using encryption can be dangerous. Russia’s SORM surveillance system processes hundreds of thousands of requests annually. Iran’s filtering system inspects encrypted traffic. Myanmar has sentenced journalists to prison for possessing encrypted communication tools. If using encryption is evidence of wrongdoing, you need a method that does not look like encryption. For guidance on keeping steganography tools invisible on your device, see How to Hide Phasm on Your Phone.
Security Researchers
Steganography is an active area of academic research spanning information theory, signal processing, machine learning, and cryptography. Researchers study both the embedding side (how to hide data more effectively) and the steganalysis side (how to detect hidden data). Having open-source, well-documented implementations of modern algorithms is valuable for reproducible research.
Everyday Privacy
Not every use case involves adversarial governments. Some people simply want their private messages to stay private — hidden from a nosy roommate, a controlling partner, or an employer’s device management software. Steganography provides a private channel that does not look like one.
Just for Fun
Some people just think it is cool. Hiding messages in photos for friends, digital scavenger hunts, experimenting with the technology. The same mathematics that protects a dissident’s life can make a birthday surprise more interesting.
Limitations and Honest Answers
Steganography is a powerful tool, but it is not magic. Here is what it cannot do and where it falls short.
What Steganography Is NOT
- It is not a replacement for encryption. Steganography hides the existence of a message. Encryption protects its content. Use both.
- It is not invisible to all analysis. At high embedding rates (stuffing a large message into a small image), statistical detectors can identify the presence of hidden data. Steganography works best when the message is small relative to the image.
- It is not a general-purpose file transfer tool. Phasm supports up to 64KB per image — enough for substantial text, but not for large files (Ghost mode supports documents up to 2MB).
- It is not foolproof against targeted forensic analysis. If someone has the original unmodified image, they can compare the two and detect changes. Steganography protects against mass surveillance and casual inspection, not focused forensics with the original in hand.
Platforms That Do Not Work
Some platforms process images so aggressively that no steganographic method survives:
- Instagram: Aggressive resizing and recompression with custom quantization tables.
- Snapchat: Heavy compression designed for ephemeral content.
- WeChat: Estimated quality factor as low as 53, destroying fine detail.
These platforms will destroy your hidden message. No amount of error correction can recover a signal that has been quantized into oblivion. For these platforms, the only option is to share the file as a document attachment (which bypasses the image processing pipeline) or to use a link-sharing service like phasm.link.
The Recompression Problem
Every time a JPEG is re-saved, DCT coefficients are re-quantized. For Ghost mode, a single recompression is usually fatal. For Armor mode, error correction absorbs moderate recompression — but there are limits, especially across quality factors.
The practical rule: share the image file directly whenever possible. Do not re-save it, do not screenshot it, do not let a platform recompress it. If the channel forces recompression, use Armor mode. For WhatsApp specifically, Fortress is engineered for that pipeline.
Try It Yourself
Phasm runs in your browser at phasm.app — no installation required. It is also available as a native app on iOS and Android. Everything runs client-side; your messages and images never leave your device.
The core steganography engine is written in pure Rust, compiled to WebAssembly for the web and native code for mobile. It supports 37 languages and processes images entirely on your device. The engine source code is open source under GPL-3.0.
And if you are curious about the name: Phasm is short for phasmid — the order of insects (stick bugs and leaf insects) that have spent 165 million years perfecting the art of hiding in plain sight. They are nature’s original steganographers. Read their story: Phantoms of the Forest: The Insects That Inspired Phasm.
Frequently Asked Questions
Is steganography legal?
In most countries, yes. Steganography is a technique, not a crime — just as encryption and lock-picking tools are legal to possess. The legality depends on what you do with it. Some authoritarian regimes restrict encryption tools, which could extend to steganography in practice. Know the laws in your jurisdiction.
Can steganography be detected?
It depends on the method and the embedding rate. Simple methods like LSB replacement are easily detected by modern tools. Advanced methods like J-UNIWARD at low embedding rates approach the theoretical limit of undetectability — at 0.02-0.04 bpnzAC (bits per non-zero AC coefficient), the best deep-learning steganalyzers achieve only 56-62% accuracy, barely above the 50% random-chance baseline. Detection becomes harder as the image gets larger relative to the message.
What is the difference between steganography and watermarking?
Both hide data in images, but with different priorities. Steganography hides the existence of a message — no one should know it is there. Watermarking marks ownership — the mark should survive attempts to remove it. Phasm’s Armor mode sits at the intersection: robustness-focused, but still invisible to casual inspection.
How much data can you hide in an image?
It depends on image size and embedding mode. A typical 12-megapixel smartphone photo can embed several kilobytes in Ghost mode while remaining undetectable. Armor mode has lower capacity due to error correction overhead. Phasm supports payloads up to 64KB. In practice, most messages (a paragraph, a set of coordinates, a short document) are well within capacity.
Does steganography work if I screenshot the image?
No. A screenshot captures the pixels rendered on screen, then recompresses them as a new image — a completely different file with no relationship to the original DCT coefficients. This destroys steganographic data. Always share the original file, not a screenshot.
Can I hide messages in PNG or other formats?
Phasm accepts PNG, GIF, WebP, and HEIC as input — they are automatically converted to JPEG because the DCT domain is where embedding happens. The output is always JPEG. Other methods exist for PNG (spatial-domain embedding), but JPEG steganography is generally more secure because quantization noise provides natural cover.
What happens if I use the wrong passphrase to decode?
The decryption fails silently. The decoder attempts to decrypt the extracted data with the wrong key, gets garbage, and reports that no message was found. There is no way to tell whether an image contains a message encrypted with a different passphrase or contains no message at all. This is by design — it preserves deniability.
Is Phasm’s steganography engine auditable?
Yes. The core engine (phasmcore) is open source under GPL-3.0. All encryption, key derivation, embedding, and extraction code is publicly available. One codebase compiles to the same binary on iOS, Android, and web — fully auditable.
Further Reading
This page is the hub of our steganography knowledge base. Each topic above links to deep-dive posts with full technical detail, benchmarks, and implementation specifics. Here is the complete map:
Steganography core: - UERD vs J-UNIWARD Detection Benchmarks — Quantitative steganalysis comparison across seven methods and three deep-learning detectors. - Syndrome-Trellis Codes: A Practical Guide — How STC embedding works, from theory to Viterbi implementation. - Watson Perceptual Masking for QIM Steganography — Adapting embedding strength to the human visual system. - DFT Template Embedding for Geometric Resilience — Surviving rotation, scaling, and cropping with Fourier-domain templates.
JPEG robustness: - Surviving JPEG Recompression — Armor mode benchmarks across same-QF, cross-QF, and cross-library scenarios. - How 15 Platforms Process Your Photos — What happens to your images on WhatsApp, Instagram, Telegram, and 12 other platforms. - JPEG Recompression Invariants — Which properties of DCT coefficients survive recompression, and which do not. - Soft Majority Voting and LLR Decoding — Confidence-weighted error correction for robust steganography.
Implementation: - Pure Rust JPEG Coefficient Codec — Building a zero-dependency JPEG codec for direct DCT access. - Deterministic Cross-Platform Math for WASM — FDLIBM, in-house FFT, and the challenge of bit-identical math everywhere. - Why We Open-Sourced the Engine, Not the App — The deliberate boundary between open and closed source.
And one more: - Phantoms of the Forest: The Insects That Inspired Phasm — 165 million years of hiding in plain sight. - How to Hide Phasm on Your Phone — Closing the last gap in your deniability chain.