Kingry Graphical Book Cipher Compression Resistant Encrypted Steganography Tool
A steganography tool that hides secret messages in images using a book cipher combined with DCT watermarking. Messages survive JPEG compression down to quality 60.
Double-click run.bat - this starts the server and opens your browser to the tool.
Or manually:
python server.pyThen open http://localhost:8080
Messages are encoded using character positions in a shared source text file (source_text.txt). Each character is found in the source text, and its relative position from the previous character is recorded.
Example: Encoding "The"
- Find
'T'at position 325 -> record: 325 (first character, absolute) - Find
'h'at position 225 -> record: -100 (100 characters backwards) - Find
'e'at position 228 -> record: +3 (3 characters forwards)
Result: [325, -100, +3]
The cipher always finds the nearest occurrence of each character (forward or backward), minimizing the numbers stored.
Message -> BOOK CIPHER -> COMPRESSION -> REED-SOLOMON -> REPETITION -> DCT WATERMARK -> Encoded Image
- Book Cipher: Characters to relative positions in source text
- Compression: zlib compresses the position data (40-60% reduction)
- Reed-Solomon: Adds 64 parity symbols for error recovery
- Repetition: Each bit repeated 7x (majority vote recovery)
- DCT Watermark: Embedded in frequency domain coefficients
The data is embedded in the Discrete Cosine Transform (DCT) coefficients of the image - the same frequency domain that JPEG compression operates in. This is why encoded images survive JPEG compression.
By embedding data in mid-frequency coefficient (4,3), we hide information in a region that:
- Survives JPEG quantization (unlike high frequencies)
- Isn't visually obvious (unlike DC/low frequencies)
- Has enough "room" to encode bits robustly
The strength parameter (150) determines the quantization step size:
- Higher strength = more robust to compression, but more visible artifacts
- Lower strength = less visible, but more fragile
- 150 is tuned to survive JPEG quality 60 while remaining visually subtle
Message capacity depends on image size:
| Image Size | Resolution | Approximate Capacity |
|---|---|---|
| VGA | 640x480 | ~75 characters |
| HD | 1280x720 | ~250 characters |
| Full HD | 1920x1080 | ~500 characters |
| 4K | 3840x2160 | ~2000 characters |
Tested results:
| Format | Quality | Result |
|---|---|---|
| PNG | lossless | Works |
| JPEG | 90 | Works |
| JPEG | 80 | Works |
| JPEG | 70 | Works |
| JPEG | 60 | Works |
| JPEG | 55 | Fails |
| WebP | lossless | Works |
| WebP | 80 | Works |
| File | Description |
|---|---|
run.bat |
Start the server and open browser |
server.py |
Python web server backend |
web_client.html |
Web interface (served by server.py) |
book_cipher.py |
Core encoding/decoding algorithms |
source_text.txt |
Shared source text for book cipher |
pip install pillow numpy scipy reedsoloSTRENGTH = 150 # DCT modification strength
RS_SYMBOLS = 64 # Reed-Solomon parity symbols
REPETITION = 7 # Bit repetition count- Zigzag encoding: Converts signed integers to unsigned for efficient storage
- Varint encoding: Variable-length encoding (small numbers = fewer bytes)
- zlib compression: Further reduces data size
- Reed-Solomon: Adds 64 parity bytes, can correct up to 32 byte errors
- Repetition: Each bit repeated 7 times, majority vote recovers from noise
- Source text required: The
source_text.txtfile must contain all characters in your message - Image modification: Cropping or resizing the image will break the watermark
- Compression floor: JPEG quality below 60 corrupts the embedded data
- Capacity: Limited by image size (see capacity table above)
Copyright (c) 2026 Adam Kingry. Licensed under the MIT License.