Hide encrypted messages in photos and text

StegPony encrypts a message or a file and hides it in the fine detail of an ordinary photo, or in text you can paste anywhere. Nothing in the file marks it: no header, no marker, no fixed layout, and without the right passphrase or key the image is just a photo. How hard it is to detect depends on how much you hide, and the app rates that before you hide it.

Android, in testing. Release candidates are published here and on GitHub. Version 1.0 will come to F-Droid and as a direct download.

How it works

  1. Pick a cover

    Take a photo with StegPony's camera, or pick one you took yourself and haven't shared anywhere.

  2. Write the message

    Type text or pick a file. The capacity meter shows how much fits and how detectable the result would be.

  3. Lock it

    Use a passphrase or someone's public key. Add a decoy under a second passphrase if you want one.

  4. Send the file

    Send the image as a file or document. The recipient opens it in StegPony with the passphrase or their key.

Features

Hiding

JPEG photos
The message goes into the photo's own compressed data, so it stays a JPEG with your camera's compression, like any other photo from your phone.
Lossless PNG
For images that were PNGs to begin with, such as screenshots and graphics.
Text
As a run of ordinary words that reads as nonsense, or as invisible characters inside a message you write. Both hold far less than a photo and are labelled honestly in the app.
Detectability rating
Low, medium or high, from tests with a standard detector on real phone photos, shown before you hide.
Files too
Hide any file that fits, including an age or PGP file from AgePony or PGPony.
Telegram photos from an iPhone
Experimental. StegPony prepares a copy of the photo the way Telegram on an iPhone would, so the message should survive being sent as a photo there. Not verified yet: send one to yourself first.

Keys

Passphrases
Stretched with Argon2id, so guessing is slow.
Public keys
Hide for someone's age key or Curve25519 OpenPGP key; only their secret key opens it.
Hardware keys
Open hidden messages with an OpenPGP card over NFC or USB. The secret stays on the card.
Contacts and QR codes
Add contacts by QR code, by pasting a key, from a file, or shared in from another app such as PGPony.

On your phone

Decoy
A second message under a second passphrase. Nobody can tell whether an image has one.
No network access
The app has no internet permission at all.
App lock and screenshot blocking
Fingerprint, face or screen lock to open the app. Reveal and Keys always block screenshots.
Launcher disguise
Show the app as Photo Tools, Notes or Utilities in the launcher. It slows down a casual look; the real name still shows in Android's app settings.
Cover reuse warning
StegPony remembers fingerprints of covers you've used, on the phone only, and warns before one is used again.
Metadata removed
Location, time and device details are stripped from the output by default.

Sending the image

What's hidden survives only if the file arrives unchanged, or changed in a way StegPony has prepared for. These are the results so far, from real sends.

How you send itResultNotes
As a file or document, by email, USB, RelayPony or cloud storage that keeps files unchangedWorksThe file arrives byte for byte, which is all StegPony needs. Some cloud and photo services re-save images, so check yours.
Telegram photo, sent from an iPhone through the photo galleryExperimentalChoose "Telegram photo from an iPhone (experimental)" when hiding, save the image to Photos and send it from Telegram's gallery in standard quality, not HD, one per message. In early tests, including one copy made by the app, everything hidden came through intact. Not verified yet: send one to yourself first.
Telegram photo sent from Android, or attached on an iPhone with Attach, then FileNot yetIn tests, Telegram re-saved both of these at a different quality, which destroys what's hidden.
WhatsApp or Signal photoNot yetBoth recompress photos. Measurements so far show they need an error-tolerant mode, which is planned.
Hidden text in a messageDepends on the appWords survive as long as no word is changed, so watch for autocorrect. Many apps remove invisible characters, so send yourself a test first.

Never send or post the original photo as well. Anyone holding both can compare them.

What StegPony can't protect against

Hiding lowers the odds of being noticed; it doesn't make them zero. The app's Help says the same thing in more detail.

  • Someone who has the original photo you hid in.
  • A detector trained on photos from your own camera, especially with a lot hidden.
  • Someone who knows StegPony is installed and insists on a second passphrase.
  • A forensic examination of your unlocked phone.
  • Anyone who sees whom you send images to, and when. StegPony hides what you send, not that you sent it.

Technical details

Envelope
Passphrase
Argon2id, 128 MiB, 3 passes, 4 lanes
Public key
X25519 with Elligator 2, HKDF-SHA256
Encryption
ChaCha20-Poly1305
Layout
No header, no length or version in the clear; padded to fixed sizes
Slots
Two in every carrier: payload plus decoy or random filler
Embedding
Code
Ternary syndrome-trellis code
JPEG
AC coefficients, J-UNIWARD costs, no re-encoding
PNG
Pixel values, HILL costs
Text
4,096-word English list, or zero-width characters
Positions
Keyed permutation from the passphrase, or from the recipient's public key in public-key mode (anyone with that key can find the positions, not read them)
App
Platform
Android 8.0 or later, arm64-v8a and x86_64
Core
StegPonyCore, in Rust, written to be shared across platforms
Permissions
Camera (in-app photos and QR codes) and NFC (hardware keys); no internet
Keys at rest
Encrypted with an Android Keystore key, left out of backups
License
Apache-2.0

Source code

Everything is open source. The format is written down, with test vectors, so the scheme can be checked on its own.

FAQ

Can anyone tell that a photo has something hidden in it?
Not from the file format: there is no header, marker or fixed layout, and without the right secret the image is just a photo. Steganalysis can still notice statistical traces, more easily the more you hide in a small or flat photo. That is what the detectability rating is for: keep it low by hiding little in a large, detailed photo.
Why can't I send the image as a normal photo in WhatsApp or Signal?
Messengers recompress photos to save data, and recompression rewrites the fine detail the message is hidden in. Send the image as a file or document instead. Measurements so far show WhatsApp, Signal and Telegram sent from Android need an error-tolerant mode, which is planned. Telegram sent from an iPhone is offered as an experimental option and is not verified yet.
What is the decoy?
Every image and every text has room for two hidden messages. The second one is either a decoy under its own passphrase or random filler, and the two look the same. If someone forces you to open an image, you can give them the decoy passphrase.
Does it work with my age or PGP keys?
Yes, for X25519 keys. An age recipient or identity works directly, and a Curve25519 OpenPGP key (cv25519 or X25519) can be imported from a file or shared in from PGPony. RSA and NIST-curve keys cannot be used.
Can I open hidden messages with a hardware key?
Yes, with an OpenPGP card (such as a YubiKey, Nitrokey or Token2) holding a Curve25519 decryption key, over NFC or USB. The key exchange happens on the card, so its secret never leaves it. A Nitrokey 3 works over USB only, because its OpenPGP app is switched off over NFC.
Is there an iPhone or desktop version?
Not yet. Android comes first; the format and the core are platform-neutral, so other versions can follow.
Where do I get it?
StegPony is in testing. Release candidates are published on this site and as GitHub pre-releases, each with its SHA-256 and a signature. Version 1.0 will be on F-Droid and available here as a direct download.

Download

StegPony is in testing. The latest release candidate is 1.0.0-rc3, from October 29, 2026. It is a test build for Android, signed and published with its SHA-256 so you can check it.