Encrypted Image Watermark Injector / Validator
Project description
Pixseal
Encrypted image watermark injector/validator that hides text (optionally RSA encrypted) inside 24-bit PNG or BMP files by modulating the parity of carefully selected color channels.
- GitHub: https://github.com/kyj9447/Pixseal
- Changelog: https://github.com/kyj9447/Pixseal/blob/main/CHANGELOG.md
Features
- Noise-resistant embedding: Chooses the RGB component whose value is farthest from 127 and nudges it ±1 to match each payload bit, keeping noise visually imperceptible.
- Sentinel-based framing: Automatically prefixes/suffixes payloads with
START-VALIDATION/END-VALIDATIONmarkers so the validator knows where to look. - Optional RSA envelope: When you pass a public key, both the sentinels and payload are encrypted with OAEP (SHA-256). Validation decrypts with the matching private key before building a verdict.
- Pure Python image I/O:
SimpleImagereads/writes uncompressed BMPs as well as 8-bit RGB/RGBA PNGs without third-party imaging libraries.
Installation
pip install Pixseal
# or for local development
pip install -e ./pip_package
Python 3.8+ is required. The only runtime dependency is cryptography>=41.0.0.
Usage
Sign an image
from Pixseal import signImage
result = signImage(
imageInput="original.png", # accepts a file path or raw PNG/BMP bytes
hiddenString="!Validation:kyj9447@mailmail.com",
publicKeyPath="SSL/public_key.pem", # omit for plain-text embedding
)
result.save("signed_original.png")
- The payload is looped if it runs out before the image ends, so even small files carry the full sentinel/payload/end pattern.
- When
publicKeyPathis omitted, the payload remains plain text.
Validate and (optionally) decrypt
from Pixseal import validateImage
report = validateImage(
imageInput="signed_original.png", # accepts a file path or raw PNG/BMP bytes
privKeyPath="SSL/private_key.pem", # omit for plain-text payloads
)
print(report["extractedString1"])
print(report["validationReport"])
validateImage returns:
{
"extractedString1": "<payload or encrypted blob>",
"extractedString2": "<truncated payload or encrypted blob>",
"validationReport": {
"arrayLength": 4,
"lengthCheck": True,
"startCheck": True,
"endCheck": True,
"isDecrypted": True,
"tailCheckResult": True,
"verdict": True,
# decryptSkipMessage when a decrypt request was skipped
}
}
CLI demo script
python testRun.py offers an interactive flow:
- Choose 1 to sign an image. It reads
original.png, asks for a payload (default!Validation:kyj9447@mailmail.com), optionally encrypts withSSL/public_key.pem, and writessigned_<name>.png. - Choose 2 to validate. It reads
signed_original.png, optionally decrypts withSSL/private_key.pem, and prints both the extracted string and verdict. - Choose 3 to benchmark performance. It reads
original.png, encrypts it withSSL/public_key.pem, and writessigned_original.png, printing the elapsed signing time. Then it readssigned_original.png, performs extraction/decryption/validation, and prints the elapsed validation time along with the total elapsed time. - Choose 4 to test signing and validation with file-path input option.
- Choose 5 to test signing and validation with byte-stream input option.
Key management
Generate a test RSA pair (PKCS#8) with OpenSSL:
openssl genpkey -algorithm RSA -out SSL/private_key.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in SSL/private_key.pem -out SSL/public_key.pem
Point publicKeyPath / privKeyPath to these files.
API reference
| Function | Description |
|---|---|
signImage(imageInput, hiddenString, publicKeyPath=None) |
Loads a PNG/BMP from a filesystem path or raw bytes, injects hiddenString plus sentinels, encrypting each chunk when publicKeyPath is provided. Returns a SimpleImage that you can save() or saveBmp(). |
validateImage(imageInput, privKeyPath=None) |
Reads the hidden bit stream from a path or raw bytes, splits by newlines, deduplicates, optionally decrypts each chunk (Base64 indicates ciphertext), and returns the payload plus a validation report. |
Examples
| Original | Signed (!Validation:kyj9447@mailmail.com) |
|---|---|
Validation output excerpt:
[Validate] verdict: True
[Validate] extracted string: !Validation:kyj9447@mailmail.com
[Validate] decrypted with private key: SSL/private_key.pem
(When encrypted, each line appears as Base64 until decrypted with the RSA private key.)
| Corrupted after signing |
|---|
Validation output excerpt:
...
string argument should contain only ASCII characters
string argument should contain only ASCII characters
string argument should contain only ASCII characters
[Validate] verdict: False
[Validate] extracted string: !Validation:kyj9447@mailmail.com
[Validate] decrypted with private key: SSL/private_key.pem
Related projects
https://github.com/kyj9447/imageSignerCamera
- Mobile camera that signs images on capture:
- Server-side validator that decrypts and verifies payloads.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pixseal-0.1.2.post0.tar.gz.
File metadata
- Download URL: pixseal-0.1.2.post0.tar.gz
- Upload date:
- Size: 11.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3bbf1c15eb43f82d36896f0aac0ccb3d658defcdf3d1b0fde0cf574e400c5075
|
|
| MD5 |
d43fddacadda7394d7ae25ea4952f4a2
|
|
| BLAKE2b-256 |
92d53f19c593242dda4bede852c2f694afb0d618db70336b8b370292a8ffaf29
|
File details
Details for the file pixseal-0.1.2.post0-py3-none-any.whl.
File metadata
- Download URL: pixseal-0.1.2.post0-py3-none-any.whl
- Upload date:
- Size: 10.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
844b424faa677e2927b3cd37af9cf233fd4f8135e0ab00fccac76e37d8cd8923
|
|
| MD5 |
641dea7701d719f4a87d0f7f3786921d
|
|
| BLAKE2b-256 |
a588538bac776b9ecc5edcaf7322b543877d612fb6082d41279613c935003107
|