Skip to content
MatrixMagicianPublic

About

A Python-based steganography toolkit that hides secret data across six different media types: images (LSB encoding), audio files (WAV/FLAC sample manipulation), QR codes (error correction exploitation), PDFs (whitespace and invisible text layers), plaintext (zero-width Unicode characters) and git commits (timestamp and whitespace encoding)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

21 Commits

Folders and files

Repository files navigation

PySteg

A Python steganography toolkit that hides AES-256-GCM encrypted data inside six different carrier formats. Encode a secret, decode it back with the correct password — carriers remain perceptually identical to originals.

Format Technique Carrier types
Image Least-significant-bit (LSB) pixel manipulation PNG, BMP
Audio LSB sample manipulation WAV, FLAC
QR Code Reed-Solomon error correction exploitation PNG (generated)
Text Zero-width Unicode characters (U+200B / U+200C) Any .txt
PDF Invisible text layers (rendering mode 3) Any PDF
Git Commit timestamp second-field encoding Any git repo

Plus cross-format utilities: auto-detect decode, capacity analysis, and batch processing.


Prerequisites

  • Python 3.11+
  • git on PATH (only required for git commit steganography)
  • libzbar (only required for QR code steganography)

Install libzbar for your platform:

# Debian / Ubuntu
sudo apt-get install libzbar0

# macOS
brew install zbar

# Fedora
sudo dnf install zbar

Installation

From PyPI

pip install pysteg

From source

git clone https://github.com/MatrixMagician/PySteg.git
cd PySteg
pip install -e .

Or with uv:

git clone https://github.com/MatrixMagician/PySteg.git
cd PySteg
uv sync

Verify installation

pysteg --version
# pysteg, version 1.0.0

pysteg --help

Usage

Every format follows the same pattern: encode hides data, decode extracts it. All payloads are encrypted with AES-256-GCM before embedding — you'll be prompted for a password if --password is omitted.

Image Steganography (PNG / BMP)

Hides data in the least-significant bits of pixel colour channels.

# Encode a text message into a PNG
pysteg image encode \
  --carrier photo.png \
  --message "Top secret message" \
  --password mypassword \
  --output stego.png

# Encode a binary file into a BMP
pysteg image encode \
  --carrier photo.bmp \
  --payload secret.zip \
  --password mypassword \
  --output stego.bmp

# Decode
pysteg image decode \
  --carrier stego.png \
  --password mypassword \
  --output recovered.txt

Audio Steganography (WAV / FLAC)

Hides data in the least-significant bits of PCM-16 audio samples.

# Encode
pysteg audio encode \
  --carrier music.wav \
  --message "Hidden in audio" \
  --password mypassword \
  --output stego.wav

# Decode
pysteg audio decode \
  --carrier stego.wav \
  --password mypassword \
  --output recovered.txt

QR Code Steganography

Generates a QR code encoding visible content (e.g. a URL) with a hidden payload embedded by flipping data modules within the Reed-Solomon error correction tolerance. The QR scans normally with any standard reader.

# Create a text file with the visible QR content
echo "https://example.com" > url.txt

# Encode a hidden message into the QR code
pysteg qr encode \
  --carrier url.txt \
  --message "Secret payload" \
  --password mypassword \
  --output qr_stego.png

# Decode the hidden message from the QR image
pysteg qr decode \
  --carrier qr_stego.png \
  --password mypassword \
  --output recovered.txt

Note: The --carrier for encode is a text file containing the visible QR content. For decode, it is the PNG image.

Text Steganography (Zero-Width Unicode)

Inserts invisible zero-width characters between visible characters. The text looks completely normal to human readers.

# Encode
pysteg text encode \
  --carrier document.txt \
  --message "Invisible secret" \
  --password mypassword \
  --output stego.txt

# Decode
pysteg text decode \
  --carrier stego.txt \
  --password mypassword \
  --output recovered.txt

PDF Steganography

Appends invisible text (PDF rendering mode 3 — neither fill nor stroke) to page content streams. The PDF reads normally in any viewer.

# Encode
pysteg pdf encode \
  --carrier report.pdf \
  --message "Hidden in plain sight" \
  --password mypassword \
  --output stego.pdf

# Decode
pysteg pdf decode \
  --carrier stego.pdf \
  --password mypassword \
  --output recovered.txt

Git Commit Steganography

Encodes 5 bits per commit in the seconds field (0–31) of author/committer timestamps. Commits look completely normal in git log.

# Encode — creates commits in the target repo
pysteg git encode \
  --repo /path/to/repo \
  --message "Hidden in history" \
  --password mypassword
# Output: "Encoded in N commits."

# Decode — specify how many recent commits to scan
pysteg git decode \
  --repo /path/to/repo \
  --commits N \
  --password mypassword \
  --output recovered.txt

Capacity Analysis

Check how much hidden data a carrier can hold before encoding:

# Single file
pysteg capacity photo.png

# Multiple files — outputs a Rich table
pysteg capacity photo.png music.wav report.pdf document.txt

The table shows Raw capacity (total bytes available) and Usable capacity (after subtracting the 53-byte encryption header).

Auto-Detect Decode

Decode without specifying the format — PySteg detects it automatically:

pysteg decode stego.png --password mypassword --output recovered.txt
pysteg decode stego.wav --password mypassword --output recovered.txt
pysteg decode stego.pdf --password mypassword

Supports image (PNG/BMP), audio (WAV/FLAC), text, and PDF. For PNG files, tries image LSB first, then falls back to QR decoding. Git repos require pysteg git decode with --commits.

Batch Processing

Encode the same payload into every compatible carrier in a directory, or decode all carriers at once:

# Batch encode — encodes into all supported files in ./carriers/
pysteg batch encode \
  --message "Same secret everywhere" \
  --password mypassword \
  --carriers ./carriers/ \
  --output-dir ./encoded/

# Batch decode — decodes all supported files in ./encoded/
pysteg batch decode \
  --password mypassword \
  --input-dir ./encoded/ \
  --output-dir ./decoded/

Files that lack capacity are skipped. Git and QR formats are excluded from batch operations.


Encryption

All payloads are encrypted with AES-256-GCM before embedding into any carrier:

  • Key derivation: PBKDF2-HMAC-SHA256, 600,000 iterations
  • Fresh salt and nonce generated per encryption call
  • Authentication tag detects tampering — wrong password or modified ciphertext raises an error
  • Wire format v1: PST\x00 magic + version(1) + salt(16) + nonce(16) + tag(16) + ciphertext = 53-byte header overhead

Documentation

See docs/GUIDE.md for the full user guide covering theory behind each technique, detection/steganalysis methods, and detailed examples.


Development

git clone https://github.com/MatrixMagician/PySteg.git
cd PySteg
uv sync

# Run the test suite (258 tests)
uv run pytest tests/

# Lint
uv run ruff check pysteg/ tests/

License

GPLv3

About

A Python-based steganography toolkit that hides secret data across six different media types: images (LSB encoding), audio files (WAV/FLAC sample manipulation), QR codes (error correction exploitation), PDFs (whitespace and invisible text layers), plaintext (zero-width Unicode characters) and git commits (timestamp and whitespace encoding)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages