Pixseal 1.0.0__pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: Pixseal
3
+ Version: 1.0.0
4
+ Summary: Image integrity and authenticity verification tool
5
+ Requires-Python: >=3.8
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: cryptography>=41.0.0
8
+
9
+ <p align="center">
10
+ <img src="https://raw.githubusercontent.com/kyj9447/Pixseal/main/assets/logo/Pixseal.png" width="200px"/>
11
+ </p>
12
+
13
+ # Pixseal
14
+ ### Prove what you published — and what you didn’t.
15
+ Pixseal is a Python-based **image integrity and authenticity verification tool**
16
+ designed to **detect whether an image has been modified since signing.**
17
+
18
+ Pixseal embeds a **cryptographically verifiable integrity seal** into an image in an
19
+ invisible manner. During verification, **any modification** — including editing,
20
+ filtering, cropping, resizing, re-encoding — will cause verification to **fail**.
21
+
22
+ Pixseal signs the payload and image hash with an RSA private key. Verification uses
23
+ the matching RSA public key or an X.509 certificate that contains it.
24
+
25
+ Pixseal is not a visual watermarking or branding tool.
26
+ The watermark exists solely as a **means to achieve strict, deterministic image
27
+ tamper detection**.
28
+ Pixseal prioritizes tamper sensitivity over robustness against intentional adversarial manipulation.
29
+
30
+ - GitHub: https://github.com/kyj9447/Pixseal
31
+ - Changelog: https://github.com/kyj9447/Pixseal/blob/main/CHANGELOG.md
32
+
33
+ ## Features
34
+ - **Image Integrity Verification**
35
+ - Cryptographically proves that an image remains in its original, unmodified state
36
+ - Detects single-pixel changes with deterministic verification results
37
+
38
+ - **Tamper Detection**
39
+ - Detects image modifications such as:
40
+ - editing
41
+ - filters and color adjustments
42
+ - cropping and resizing
43
+ - re-encoding and recompression
44
+ - pixel-level changes
45
+
46
+ - **Invisible Integrity Seal**
47
+ - Embeds verification data without any visible watermark
48
+ - Preserves the original visual appearance of the image
49
+
50
+ - **RSA Signatures + Certificate Support**
51
+ - Signs payloads and image hashes with an RSA private key
52
+ - Validates with RSA public keys or X.509 certificates (PEM/DER)
53
+
54
+ - **Flexible Key Inputs**
55
+ - Accepts key/cert objects, PEM/DER bytes, or file paths
56
+
57
+ - **Fully Local & Offline**
58
+ - No external servers or network dependencies
59
+ - Pure Python implementation
60
+
61
+ - **Lossless Format Support**
62
+ - Supports PNG and BMP (24-bit) images
63
+ - Lossy formats (e.g., JPEG, WebP) are intentionally excluded to preserve integrity guarantees
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ pip install Pixseal
69
+ # or for local development
70
+ pip install -e ./pip_package
71
+ ```
72
+
73
+ Python 3.8+ is required. Wheels published to PyPI already include the compiled
74
+ Cython extension, so `pip install Pixseal` automatically selects the right build
75
+ for your operating system and CPU.
76
+
77
+ ### Building the Cython extension
78
+
79
+ If you cloned the repository (or downloaded the source), run the helper script
80
+ to compile the `simpleImage_ext` extension for your environment:
81
+
82
+ ```bash
83
+ git clone https://github.com/kyj9447/Pixseal.git
84
+ cd Pixseal
85
+ python3 -m pip install -r requirements.txt
86
+ ./compile_extension.sh
87
+ ```
88
+
89
+ This command regenerates the C source via Cython and invokes your local C
90
+ compiler (`clang` or `gcc`) to produce `pip_package/Pixseal/simpleImage_ext*.so`.
91
+ You still need a working build toolchain (`gcc`/`clang` and Python headers)
92
+ installed through your OS package manager. If you skip this step, Pixseal falls
93
+ back to the pure Python implementation, which works but is significantly slower.
94
+
95
+ ## Quick start
96
+
97
+ ### Sign an image
98
+
99
+ ```python
100
+ from Pixseal import signImage
101
+
102
+ signed = signImage(
103
+ imageInput="assets/original.png",
104
+ payload="AutoTest123!",
105
+ private_key="assets/CA/pixseal-dev-final.key",
106
+ )
107
+ signed.save("assets/signed_original.png")
108
+ ```
109
+
110
+ - The payload is looped if it runs out before the image ends, so even small files carry the full sentinel/payload/end pattern.
111
+
112
+ ### Validate a signed image
113
+
114
+ ```python
115
+ from Pixseal import validateImage
116
+
117
+ report = validateImage(
118
+ imageInput="assets/signed_original.png",
119
+ publicKey="assets/CA/pixseal-dev-final.crt", # cert or public key
120
+ )
121
+
122
+ print(report["verdict"])
123
+ ```
124
+
125
+ ## Key and certificate inputs
126
+
127
+ Pixseal accepts multiple input formats so you can keep the calling code minimal.
128
+
129
+ - `signImage(..., private_key=...)` accepts:
130
+ - `RSAPrivateKey`
131
+ - PEM/DER bytes (`bytes`, `bytearray`, `memoryview`)
132
+ - file path (`str` or `Path`)
133
+
134
+ - `validateImage(..., publicKey=...)` accepts:
135
+ - `RSAPublicKey`
136
+ - `x509.Certificate`
137
+ - PEM/DER bytes (`bytes`, `bytearray`, `memoryview`)
138
+ - file path (`str` or `Path`)
139
+
140
+ If a certificate is provided, Pixseal extracts the embedded RSA public key and
141
+ verifies the signatures. Certificate chain validation is the responsibility of
142
+ the calling application.
143
+
144
+ ## Payload structure
145
+
146
+ Pixseal embeds a compact JSON payload with the signed data and image hash:
147
+
148
+ ```json
149
+ {
150
+ "payload": "AutoTest123!",
151
+ "payloadSig": "BASE64_SIGNATURE",
152
+ "imageHash": "SHA256_HEX",
153
+ "imageHashSig": "BASE64_SIGNATURE"
154
+ }
155
+ ```
156
+
157
+ - `payload`: user-provided text
158
+ - `payloadSig`: RSA signature of `payload` (Base64)
159
+ - `imageHash`: SHA256 hex digest computed over the signed image buffer.
160
+ - `imageHashSig`: RSA signature of `imageHash` (Base64)
161
+
162
+ ## Embedded sequence layout
163
+
164
+ Pixseal writes the following newline-delimited sequence into the image:
165
+
166
+ ```
167
+ <START-VALIDATION signature>
168
+ <payload JSON>
169
+ <payload JSON>
170
+ <payload JSON>
171
+ <payload JSON>
172
+ ...(Repeated until it fills the entire image)...
173
+ <payload JSON> # truncated tail (prefix of payload JSON)
174
+ <END-VALIDATION signature>
175
+ ```
176
+
177
+ During extraction, Pixseal deduplicates the sequence and typically returns four
178
+ lines in order: start signature, full payload JSON, truncated payload prefix,
179
+ and end signature.
180
+
181
+ For a valid image, deduplication results in four extracted
182
+ lines.
183
+
184
+ ```
185
+ <START-VALIDATION signature>
186
+ <payload JSON>
187
+ <payload JSON> # truncated tail
188
+ <END-VALIDATION signature>
189
+ ```
190
+ <sub>※ In rare edge cases, the truncated payload prefix may be absent, in which
191
+ case only three lines are returned.</sub>
192
+
193
+ ## Validation output
194
+
195
+ Validation Report
196
+
197
+ - `lengthCheck`
198
+ - `length` : Length of deduplication result array.
199
+ - `result` : True for 4 or 3 (valid deduplication cases).
200
+ - `tailCheck`
201
+ - `full` : Full payload intact. (output truncated)
202
+ - `tail` : Truncated payload intact. (output truncated)
203
+ - `result` : True when the full and truncated payload portions match.
204
+ - `startVerify` : Verification result of the first SIG against "START-VALIDATION"
205
+ - `endtVerify` : Verification result of the last SIG against "END-VALIDATION"
206
+ - `payloadVerify` : Verification result of the "payload" against "payloadSig"
207
+ - `imageHashVerify` : Verification result of the "imageHash" against "imageHashSig"
208
+ - `imageHashCompareCheck`
209
+ - `extractedHash` : Value of "imageHash" from extracted payload
210
+ - `computedHash` : Image hash computed directly from the image
211
+ - `result` : True when extractedHash and computedHash are identical
212
+ - `verdict` : True when all validation checks pass.
213
+
214
+ ## CLI demo script
215
+
216
+ `python testRun.py` offers an interactive flow:
217
+
218
+ Before the menu, it prompts for the SimpleImage backend
219
+ (Enter/1=cython, 2=python fallback) and sets `PIXSEAL_SIMPLEIMAGE_BACKEND`.
220
+
221
+ 1. Choose **1** to sign an image. It reads `assets/original.png` and writes `assets/signed_original.png`.
222
+ 2. Choose **2** to validate. It reads `assets/signed_original.png` and prints the validation report.
223
+ 3. Choose **3** to run the failure test. It reads `assets/currupted_signed_original.png`.
224
+ 4. Choose **4** to benchmark performance (sign + validate with timings).
225
+ 5. Choose **5** to test signing and validation using in-memory bytes.
226
+ 6. Choose **6** to run the optional line-profiler demo.
227
+ 7. Choose **7** to run validation multi-pass tests.
228
+
229
+ Option **6** requires the optional dependency `line_profiler` and must be run via
230
+ `kernprof -l testRun.py` so that `builtins.profile` is provided. Without
231
+ `line_profiler` installed the script will continue to work, but the profiling
232
+ option will display an informative message instead of running.
233
+
234
+ ## API reference
235
+
236
+ | Function | Description |
237
+ | --- | --- |
238
+ | `signImage(imageInput, payload, private_key)` | Loads a PNG/BMP from a filesystem path or raw bytes, injects `payload` plus sentinels, and signs the payload/hash using the RSA private key. Returns a `SimpleImage` that you can `save()` or `saveBmp()`. |
239
+ | `validateImage(imageInput, publicKey)` | Reads the hidden bit stream from a path or raw bytes, rebuilds the payload JSON, verifies signatures and the computed image hash, and returns a validation report. Accepts RSA public keys or X.509 certificates. |
240
+
241
+ ## Examples
242
+
243
+ | Original | Signed (`AutoTest123!`) |
244
+ | --- | --- |
245
+ | <img src="https://raw.githubusercontent.com/kyj9447/Pixseal/main/assets/original.png" width="400px"/> | <img src="https://raw.githubusercontent.com/kyj9447/Pixseal/main/assets/signed_original.png" width="400px"/> |
246
+
247
+ Validation output (success):
248
+
249
+ ```
250
+ Validation Report
251
+
252
+ {'lengthCheck': {'length': 4, 'result': True},
253
+ 'tailCheck': {'full': '{"payload":"AutoTest...lgu9lUM+s7OHUZywYqYYOYIFVTWCmq...',
254
+ 'tail': '{"payload":"AutoTest...lgu9lUM+s7',
255
+ 'result': True},
256
+ 'startVerify': True,
257
+ 'endtVerify': True,
258
+ 'payloadVerify': True,
259
+ 'imageHashVerify': True,
260
+ 'imageHashCompareCheck': {'extractedHash': '2129e43456029f39b20bbe96340dce6827c0ad2288107cb92c0b92136fec48d6',
261
+ 'computedHash': '2129e43456029f39b20bbe96340dce6827c0ad2288107cb92c0b92136fec48d6',
262
+ 'result': True},
263
+ 'verdict': True}
264
+ ```
265
+
266
+ | Corrupted after signing |
267
+ | --- |
268
+ | <img src="https://raw.githubusercontent.com/kyj9447/Pixseal/main/assets/currupted_signed_original.png" width="400px"/> |
269
+
270
+ Validation output (failure):
271
+
272
+ ```
273
+ Validation Report
274
+
275
+ {'lengthCheck': {'length': 31, 'result': False},
276
+ 'tailCheck': {'result': 'Not Required'},
277
+ 'startVerify': True,
278
+ 'endtVerify': True,
279
+ 'payloadVerify': True,
280
+ 'imageHashVerify': True,
281
+ 'imageHashCompareCheck': {'extractedHash': '68d500c751dfa298d55dfc1cd2ab5c9f43ec139f02f6a11027211c4d144c2870',
282
+ 'computedHash': '43fd2108f5aa16045f4b64d70a0ce05991043cba6878f66d82abd3e7edb9d51e',
283
+ 'result': False},
284
+ 'verdict': False}
285
+ ```
@@ -0,0 +1,11 @@
1
+ pixseal-1.0.0.dist-info/WHEEL,sha256=VbVV36H_sGWs2wDlSVuZCfrfUlk3NfehwD_wG4zKlug,162
2
+ pixseal-1.0.0.dist-info/top_level.txt,sha256=q35ICL7vJyo5hOpL4YbL5t_g4297gwUPIuLy82kgL3s,8
3
+ pixseal-1.0.0.dist-info/METADATA,sha256=HQJKCdanhScu8WEww9YeQLQFzyVxVyUiMQwHQjPDnCY,10214
4
+ pixseal-1.0.0.dist-info/RECORD,,
5
+ Pixseal/simpleImage_py.py,sha256=6U44kNUP-ygcf7Sz91fjG99CrVWcROIC4tneQXDdbOA,27583
6
+ Pixseal/keyInput.py,sha256=p49Y_ZKRMxF8aU53eB6GGvos-AaI_m5d5z5z1reMgmU,3523
7
+ Pixseal/imageValidator.py,sha256=aRBfEz6eHJlhExqMyw83mCnx_I05yTD217oeJzffPpo,11607
8
+ Pixseal/simpleImage.py,sha256=dkpMEhkT1z0pZOgy-AbgYlF9GC73eM2WGaYb5FiGNpk,1234
9
+ Pixseal/imageSigner.py,sha256=fWQ1o8MAOgRihT1rYKdht0W8eUoA8qJJ02YDcGpch-U,10636
10
+ Pixseal/__init__.py,sha256=J66ptDDimT5fe8AZCqeJv2xLUl-rbPqLFGJlMTsuwA8,646
11
+ Pixseal/simpleImage_ext.pypy39-pp73-x86_64-linux-gnu.so,sha256=i_L0LuOmWbhW-2HUVfmqX228jVEJt1RWwmgiHWmnJmw,320472
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.1)
3
+ Root-Is-Purelib: false
4
+ Tag: pp39-pypy39_pp73-manylinux_2_17_x86_64
5
+ Tag: pp39-pypy39_pp73-manylinux2014_x86_64
6
+
@@ -0,0 +1 @@
1
+ Pixseal