StegoToolkit

PNG Steganography Hider

Hide text or files in a PNG using methods built on the PNG file layout: Chunk Injection (tEXt/iTXt/zTXt/custom), EOF Append, Alpha Channel, Row Filter Encoding, and LSB in IDAT. Chunk viewer, auto-verify, AES-256-GCM, Reed-Solomon, per-recipient batch watermarking (one uniquely marked file per recipient).

AES-256
PNG file layout

Try the demo instantly

Loads a 120×120 PNG with a transparent region — shows the chunk viewer and alpha capacity immediately

Drop a PNG here, or click to browse

PNG only — chunk architecture is PNG-specific

Processed in your browser

Your PNG is processed in this browser tab, in a Web Worker, and is not sent to a StegoToolkit server. Basic usage analytics record coarse facts such as file type and size range, never the file or your payload.

How to Hide Data in a PNG (5 steps)

  1. Upload a PNG image as the carrier (up to 50 MB).
  2. Type your secret message or choose a file to hide.
  3. Optionally add a password to encrypt the payload with AES-256-GCM on the next step.
  4. Switch to Standard or Forensic to pick Chunk Injection, EOF Append, Alpha Channel, Row Filter Encoding or LSB in IDAT.
  5. Click Embed — the tool decodes its own output and compares it with your payload before offering the download.

PNG Steganography — 5 Methods Compared

MethodWhere it is storedCapacityEffect
Chunk InjectionA tEXt, iTXt, zTXt or custom ancillary chunk before IEND (payload base64 in tEXt/iTXt)The finished PNG must stay within 50 MB (tEXt/iTXt: about 37 MB of payload)Pixels unchanged; survives a file copy only
EOF AppendBytes after the IEND chunkThe finished PNG must stay within 50 MB (tEXt/iTXt: about 37 MB of payload)Pixels unchanged; survives a file copy only
Alpha ChannelRed value of fully transparent (alpha 0) pixels, 1 bit eachtransparent pixels ÷ 8 bytes, minus 18Needs a transparent cover; survives a file copy only
Row Filter EncodingParity of each scanline's filter-type byte, 1 bit per rowrows ÷ 8 bytes, minus 18; max 512 × 512Experimental; pixels unchanged; no password fits
LSB in IDATLowest bit of R, G, B from pixel 0, with an 18-byte headerpixels × 3 ÷ 8 bytes, minus 18Survived lossless re-saves; destroyed by JPEG and resizing

What Hides Where in a PNG

A PNG file is a signature followed by chunks — IHDR (size and format), optional ancillary chunks such as tEXt or gAMA, one or more IDAT chunks holding the compressed pixel data, and IEND. Four of this tool's five methods use that structure or the pixel data's own bytes instead of changing visible colours: Chunk Injection adds a chunk, EOF Append adds bytes after IEND, Row Filter Encoding picks scanline filter types, and Alpha Channel writes into colours that cannot be seen because the pixel is fully transparent. Only LSB in IDAT changes the colours of visible pixels, by at most 1 out of 255 per value.

Nothing here is encryption on its own. Without a password the payload is stored as plain bytes behind an 18-byte header; the Extractor, or anyone who reads the chunk list, the bytes after IEND or the pixel bits, can find it. With a password the payload is encrypted first, but the header is not, so the file still shows that a payload of a given size and method exists.

Choosing a Method

Quick mode uses a tEXt chunk. Standard adds EOF Append, the other chunk types (iTXt, zTXt, custom) and deflate compression. Forensic adds Alpha Channel, Row Filter Encoding, LSB in IDAT, Reed-Solomon, IHDR manipulation and a two-layer decoy mode.

Chunk Injection and EOF Append keep every pixel and every other byte of the original file, and in our tests the decoded pixels were identical to the cover. They are also the easiest to find: a chunk list (pngcheck -v) or the size of the file shows them. Importantly, they only survive a byte-for-byte copy of the file. In our tests a plain re-save with the macOS image tool removed them in all 8 photographs, together with Row Filter and Alpha data; only LSB in IDAT survived lossless re-saves (PNG to PNG, BMP and TIFF round trips), and nothing survived JPEG conversion or resizing.

Use LSB in IDAT when the PNG may be re-saved losslessly. Use Alpha Channel only with a cover that already has fully transparent pixels. Treat Row Filter Encoding as a curiosity: it holds 1 bit per row, at most 64 bytes in a 512-row image, so it cannot hold an encrypted payload at all (the header plus AES wrapper alone is 66 bytes).

How Each Method Stores the Data

Every payload is wrapped as an 18-byte header followed by the payload bytes (deflated if you chose that, then AES-256-GCM encrypted if you set a password, then Reed-Solomon parity if you picked a level). The header is big-endian: the magic 'PSTG', a version byte (1), a flags byte (bit 0 encrypted, bit 1 compressed, bits 2–3 Reed-Solomon level), a 2-byte method code, the 4-byte stored length, 2 reserved bytes (0) and a CRC-32 of the first 14 bytes. The CRC-32 detects accidental change; it does not authenticate anything.

Chunk Injection stores that wrapper in one of four forms. tEXt and iTXt hold it as base64 text under a keyword (default 'stegotoolkit'), which makes it a third larger; zTXt holds it deflated; a custom chunk type holds it raw. EOF Append writes it after IEND. Alpha Channel writes one bit into the lowest bit of the red value of each fully transparent pixel, in raster order. LSB in IDAT writes one bit into the lowest bit of R, G, then B of each pixel from the first pixel, in raster order. Row Filter Encoding re-filters each scanline so that the parity of its filter-type byte (0 None, 1 Sub, 2 Up, 3 Average, 4 Paeth) carries one bit; defiltering recovers identical pixel values whichever type is used. It needs a non-interlaced PNG no larger than 512 × 512.

Alpha Channel and LSB in IDAT decode the pixels and write a brand-new PNG with this tool's own writer, so the file's other ancillary chunks (tEXt, iTXt, iCCP, gAMA …) are dropped and the image data is rewritten. Chunk Injection and EOF Append copy the original file's bytes unchanged and only add the new chunk or bytes. Row Filter rewrites the image data but keeps the other chunks.

Capacity: What Fits

Capacity is the raw figure for the method minus the 18-byte header, minus 48 bytes if you set a password (4-byte length, 16-byte salt, 12-byte IV, 16-byte tag) and minus Reed-Solomon parity. LSB in IDAT holds width × height × 3 ÷ 8 bytes raw; Alpha Channel holds transparent pixels ÷ 8; Row Filter holds rows ÷ 8. Capacity here means the size of your original payload. The tool stores a larger stream (18-byte header, plus 48 bytes with a password, plus Reed-Solomon parity, plus base64 for tEXt/iTXt), and the bar subtracts all of that for you. The bar's figure is exact when Deflate is off (it cannot predict compression). It is tested equal to what the encoder accepts, and one byte more is refused with a message; this is tested at the exact limit for each method in the table below. Deflate is not predicted by the bar: the encoder checks the compressed size.

Three limits are separate. The carrier PNG you open is limited to 50 MB. The finished PNG must also stay within 50 MB, because that is the largest file the Extractor opens. And each method has its own payload capacity, which is usually far below 50 MB (LSB in IDAT, Alpha Channel and Row Filter are bounded by the image). Chunk Injection and EOF Append add bytes to the file, so their limit is the finished PNG: it must stay within the 50 MB the Extractor accepts (the Hider refuses a larger result with a message, because the Extractor could not open it). That leaves about 50 MB minus the carrier's size for EOF Append and custom chunks, and about 37 MB for tEXt and iTXt because base64 is a third larger. In browser tests a 1 MB, a 40 MB and a 49.8 MB file payload (EOF Append) were embedded, downloaded and extracted again in Chromium, Firefox and WebKit, with the downloaded bytes checked independently. Those size tests used EOF Append only. At the exact displayed limit, EOF Append, tEXt and custom-chunk output round-tripped in an automated (non-browser) test while a payload 2,000 bytes over was refused; iTXt and zTXt were not size-tested.

How Strong Is the Encryption?

If you set a password, the payload is encrypted before it is hidden, in your browser, with the Web Crypto API. The cipher is AES-256 in GCM mode. The 256-bit key is derived from your password with PBKDF2 using HMAC-SHA-256 and 100,000 iterations. Every encryption generates a fresh random 16-byte salt and a fresh random 12-byte IV with the browser's cryptographically secure random generator (crypto.getRandomValues), so encrypting the same message twice gives different bytes. The stored layout is a 4-byte length, the salt, the IV, then the ciphertext followed by a 16-byte authentication tag — 48 bytes added in total. The tag means a wrong password, or any change to the ciphertext, makes decryption fail instead of returning garbage.

These are standard, widely used primitives, but this implementation has not had an independent audit, and using them does not make the system unbreakable. Their limits matter. Anyone who finds the hidden data can copy the ciphertext and try passwords against it offline, so your password is the real defence: use a long random passphrase, not a word or a date. The key derivation uses 100,000 PBKDF2-HMAC-SHA-256 iterations. This is below OWASP's commonly cited 600,000-iteration recommendation for password storage. That recommendation is not a direct requirement for this file-encryption format, but the lower count makes a strong, unique password especially important. The iteration count is fixed in the code and is not written into the file, so raising it requires a new, versioned format so that files already made can still be opened.

Encryption hides what the data says, not that it exists, and it does not hide the length: AES-GCM ciphertext is the same length as the plaintext, and the encrypted layout adds a fixed 48 bytes of overhead: its own 4-byte length field, the salt, the IV and the authentication tag, separate from any length or framing the tool puts around it. No padding is added. There is no key file and no way to recover a forgotten password. We have not measured key-derivation time on phones or older devices, so very large batches or slow devices may take noticeably longer per file. The tool is intended for educational and personal use; do not rely on it as the only protection for sensitive information, or against a well-resourced adversary.

Verification, Reed-Solomon and Other Forensic Options

After embedding, the tool decodes its own output with the Extractor's code and compares the recovered bytes with your payload; if they differ it stops with an error instead of offering a download. The SHA-256 shown in the result is of your payload, for your own records.

Reed-Solomon (RS-10, RS-20, RS-30) adds parity so that scattered changed bytes in the stored data can be repaired; it does not rescue a file that another program re-encoded, because that changes almost every byte. IHDR manipulation (Chunk Injection and EOF Append only) writes a wrong width and height into IHDR with a valid CRC so most viewers show a broken image until the real size is restored; it is a CTF device, not a hiding method, and it is incompatible with the three methods whose decoding needs the true size. The decoy mode writes a plaintext message in a tEXt chunk and an encrypted real payload in the pixels' lowest bits.

Capacity Examples (computed by the tool's own function)

Largest plain payload in bytes after the 18-byte header and, where stated, the 48-byte password wrapper or RS-10 parity. Alpha Channel figures assume half of the pixels are fully transparent.

Image and methodRaw capacityNo passwordWith passwordPassword + RS-10
800 × 600, LSB in IDAT180,000 B179,982 B179,934 B172,188 B
1920 × 1080, LSB in IDAT777,600 B777,582 B777,534 B744,138 B
800 × 600 (240,000 transparent px), Alpha Channel30,000 B29,982 B29,934 B—
400 × 400, Row Filter Encoding50 B32 Bdoes not fitdoes not fit
512 × 512, Row Filter Encoding64 B46 Bdoes not fitdoes not fit

Image Quality of LSB in IDAT (PSNR)

PSNR over all RGBA bytes (peak 255), mean of 8 crops of 400 × 300 cut from one photograph, random payloads. Chunk Injection, EOF Append and Row Filter leave the decoded pixels identical in our tests, so their PSNR is infinite. One photograph is an example, not a promise for every image; PSNR says nothing about statistical detectability.

Method5% full25% full100% full
LSB in IDAT65.4 dB58.4 dB52.4 dB

Does It Survive a Conversion? (our test)

A 12-byte message hidden with each method in the same 8 photograph crops (Alpha Channel: the same crops with the left 40% made fully transparent, so that row is synthetic). Each PNG was converted with the macOS system image tool (sips) and read by the Extractor with Auto Extract. Method: one run per crop and conversion, no repeats; a message counts as recovered only if the bytes match exactly. This is limited evidence (one photograph, one converter), repeated on the current code on 2026-10-21 with identical results. Other programs, encoders, resizing ratios and individual websites or apps were not tested.

MethodPNG → PNG re-saveBMP round tripTIFF round tripJPEG q100 / q75Resize to 90%
Chunk Injection (tEXt, zTXt, custom)0 of 80 of 80 of 80 of 80 of 8
EOF Append0 of 80 of 80 of 80 of 80 of 8
Row Filter Encoding0 of 80 of 80 of 80 of 80 of 8
Alpha Channel (synthetic transparency)0 of 80 of 80 of 80 of 80 of 8
LSB in IDAT8 of 88 of 88 of 80 of 80 of 8

Examples

Input: A 100 × 100 PNG and the 22-character message 'Hello world round trip', Chunk Injection (tEXt), no password

Result: A tEXt chunk with the keyword stegotoolkit is added before IEND. Auto Extract returns all 22 bytes, and the decoded pixels are identical to the cover.

Meaning: The file grows by the chunk (the 18-byte header plus 22 bytes, base64-encoded, plus chunk framing); nothing else changes.

Input: An 800 × 600 PNG, LSB in IDAT, a file of exactly 179,982 bytes, no password

Result: Accepted and read back byte for byte; 179,983 bytes is refused with a message about LSB capacity.

Meaning: 180,000 raw bytes minus the 18-byte header. With a password the limit is 179,934.

Input: A 512 × 512 PNG, Row Filter Encoding, a 46-byte message

Result: Accepted: 512 rows give 64 raw bytes, minus the 18-byte header. A password is refused because the AES wrapper alone is 48 bytes.

Meaning: Row Filter Encoding is a research curiosity: tiny capacity, and any re-save of the file removed the data in our tests.

Input: A PNG with no transparent pixels and Alpha Channel selected

Result: Refused with 'Payload needs … transparent-pixel bits, but only 0 alpha=0 pixels are available.'

Meaning: Alpha Channel only writes into fully transparent pixels; it never makes pixels transparent.

How the PNG Hider Works

1. Read the PNG

The file is parsed into chunks in a Web Worker; pixel decoding happens only for Alpha Channel and LSB in IDAT. Nothing is uploaded.

2. Build the stored stream

Your bytes are optionally deflated, optionally AES-256-GCM encrypted, optionally given Reed-Solomon parity, then prefixed with the 18-byte header.

3. Check it fits

For the capacity-limited methods the stream is compared with the method's capacity; if it does not fit, encoding stops with a message.

4. Embed

A chunk or bytes are added to the original file, or the pixel or filter bits are written and a new PNG is produced.

5. Verify and download

The tool decodes its own output and compares it with your payload before offering the download.

What the results mean

ResultWhat it meansWhat to do
Success screen after embeddingThe tool read its own output back and the bytes matched your payloadShare the file as a file; this does not test other programs or websites
IHDR notice on the success screenThe file reports a wrong width and height and renders broken in normal viewersRestore the real size shown in the result (hex editor or pngcheck) to view the picture
Capacity refusalThe stored stream is larger than the method can holdUse a larger or more transparent cover, another method, or a smaller payload
Transparent-pixel refusalAlpha Channel found fewer fully transparent pixels than bits neededUse a cover with transparency, or another method
Row Filter size or interlace refusalRow Filter Encoding needs a non-interlaced PNG up to 512 × 512Use another method

Limitations

  • A plain re-save of the PNG with another program removed Chunk Injection, EOF Append, Row Filter and Alpha data in every one of our tests; only LSB in IDAT survived lossless re-saves, and nothing survived JPEG conversion or resizing. Other programs and individual websites or apps were not tested.
  • Chunk Injection and EOF Append are visible to any chunk list or file-size check; they are for transfer and CTF use, not for concealment from someone who looks.
  • Alpha Channel needs a cover that already has fully transparent pixels, and Row Filter Encoding needs a non-interlaced image up to 512 × 512 and cannot hold a password-protected payload.
  • Alpha Channel and LSB in IDAT drop the other ancillary chunks of the original PNG (metadata, colour profile) because the file is rewritten.
  • The 18-byte header is never encrypted (only the payload is, if you set a password), so anyone who finds it can read the method and stored length. Finding it takes knowing where to look: for Chunk Injection and EOF Append that is trivial, for the pixel methods it means reading the right bits.
  • PSNR and survival figures were measured on 8 crops of one photograph with one converter (macOS sips); that is limited evidence, and the survival table was re-run on the current code on 2026-10-21 with identical results.

Privacy

Your PNG, payload and password are processed in your browser, in a Web Worker, and are not sent to a StegoToolkit server by the tool's own code. The only things the tool keeps in your browser are your chosen mode (localStorage) and a flag that you dismissed the mobile tip. Site analytics, if you accept them, may record coarse facts such as the method you chose, the file type, a size range and timing — never the image, payload, password or file name. The hosting provider's ordinary request logs still record your visit.

Which Tool Next?

Frequently Asked Questions

Can I hide text in a PNG image?

Yes: type the text on the second step, or choose a file. The default method (a tEXt chunk) leaves every pixel unchanged, so the picture looks the same; the text is stored as base64 in a named chunk, anyone who lists the chunks (pngcheck -v, the PNG Chunk Analyzer) can see it, and a plain re-save removes it. For text that must survive lossless re-saves use LSB in IDAT, which changes each pixel value by at most 1.

Where inside a PNG file can data be hidden?

A PNG is a signature followed by chunks. Data can sit in an extra chunk (tEXt, iTXt, zTXt or a custom ancillary chunk), in bytes after the IEND chunk, in the scanline filter-type bytes, in the lowest bits of pixel colours, or in the colour of fully transparent pixels. This tool writes to each of those places; the table above gives the capacity and what each one survives.

Why is this different from the Image Steganography Hider?

The Image Steganography Hider changes pixel values (LSB, DCT, Spread Spectrum) in any image format and always writes a PNG. This tool works on the PNG file's own structure: it can add a chunk, append bytes after IEND, or choose scanline filter types, leaving the decoded pixels identical in our tests. Only LSB in IDAT and Alpha Channel change pixel data.

Which method should I use?

Chunk Injection (tEXt) is the default: no pixel change, but it only survives a byte-for-byte copy of the file. LSB in IDAT survived lossless re-saves in our tests and is destroyed by JPEG conversion and resizing. Alpha Channel needs a cover with transparent pixels. Row Filter Encoding holds at most 64 bytes and cannot carry a password-protected payload.

Will the hidden data survive social media uploads?

Probably not: services usually re-encode images, and in our tests even a plain re-save of the PNG removed every method except LSB in IDAT, which JPEG conversion also destroyed. We did not test individual websites or apps. Send the PNG as a file and check by extracting it.

What happens to my PNG's other metadata?

Chunk Injection and EOF Append keep the original file's bytes and only add the new chunk or bytes. Alpha Channel and LSB in IDAT decode the pixels and write a new PNG with this tool's own writer, so tEXt, iTXt, iCCP, gAMA and other ancillary chunks of the original are dropped.

What is the PNGSTEG v1 header for?

An 18-byte big-endian header ('PSTG', version, flags, method, stored length, CRC-32) in front of every payload. It lets the Extractor recognise the file, the method and whether the payload is encrypted or compressed. The CRC-32 detects accidental change; it is not authentication, and the header is not encrypted.

What is auto-verify?

After embedding, the tool decodes its own output with the Extractor's code and compares the recovered bytes with your payload. If they differ, you get an error instead of a download. The SHA-256 shown is of your payload.

How does Row Filter Encoding work, and why is it experimental?

Every PNG scanline starts with a filter-type byte (0–4). Defiltering gives the same pixels whichever type was used, so the parity of each row's type can carry one bit. It needs a non-interlaced PNG up to 512 × 512, holds rows ÷ 8 bytes minus the 18-byte header (at most 46 bytes), cannot carry a password-protected payload, and was removed by a plain re-save in all of our tests.

What is IHDR dimension manipulation?

A Forensic-mode CTF device: it writes a wrong width and height into IHDR with a valid CRC while the pixel data is untouched, so most viewers show a broken image until the real size is restored. It works only with Chunk Injection and EOF Append, because the other methods need the true size to decode.

Related Tools