Custom health imaging provenance for DICOM and NIfTI formats.
Project description
Health Imaging Provenance Extension
Custom cryptographic provenance for DICOM and NIfTI health imaging formats.
Important: This project implements a custom provenance manifest (JSON sidecar / DICOM private block). It is not interoperable C2PA (no JUMBF/COSE). Manifest timestamps are self-asserted at sign time (
timestamp_kind: self_asserted), not RFC 3161 TSA timestamps.
Install
# From PyPI (after publish)
pip install c2pa-health-imaging
# From source (editable, for development)
pip install -e ".[dev]"
The CLI command is c2pa-health (short for health-imaging provenance). Requires Python 3.10+.
c2pa-health --help
Binding model
A single binding profile produces a deterministic SHA-256 hash over:
- decoded pixel / voxel values (little-endian, C-contiguous — not raw compressed bytes)
- canonical metadata that defines interpretation and geometry (rescale, spacing, affine, etc.)
DICOM binding profile
DICOM binding always includes mandatory keywords required by the Image Pixel Module (e.g. Rows, Columns, BitsAllocated, PhotometricInterpretation). Additional keywords can be supplied at sign time; the resolved list is stored in the signed manifest so verification does not depend on local config.
{
"additional_keywords": ["RescaleSlope", "RescaleIntercept", "PixelSpacing"]
}
c2pa-health sign scan.dcm --key signer.key --cert signer.pem \
--out signed.dcm \
--binding-profile ct.json \
--binding-keyword FrameOfReferenceUID
Artifacts signed before binding profiles were introduced verify using the legacy default keyword set when binding_keywords is absent from the manifest.
Signing and verification
| Format | Storage |
|---|---|
| DICOM | Private manifest block plus a DigitalSignaturesSequence item (custom binding reference, not full PS3.15 MAC) |
| NIfTI | Detached sidecar <file>.c2pa.json |
Signing uses ECDSA P-256 with an X.509 certificate embedded in the signed artifact.
Verification enforces:
- ECDSA signature over the manifest claim
- Certificate validity window (not before / not after)
- Trusted signer policy (CLI:
--trust-cert/--trust-bundle; web: trusted keys in DB)
CLI
# Generate a key pair (optional encryption)
c2pa-health keygen --out-key signer.key --out-cert signer.pem --password 'secret'
# Sign a DICOM or NIfTI file
c2pa-health sign scan.dcm --key signer.key --cert signer.pem --out signed.dcm \
--process "name=acquire;software=CT Scanner" \
--process "name=denoise;software=Pipeline"
# Verify with trusted signer certificate
c2pa-health verify signed.dcm --trust-cert signer.pem --json
# Inspect manifest / process chain
c2pa-health inspect volume.nii
Exit codes: 0 valid, 1 invalid, 2 cannot verify, 3 untrusted signer.
Process-chain parameters block PHI-like keys (patient_id, accession_number, etc.).
Web validator
FastAPI + SQLite validator with trusted-key enforcement and API-key auth for admin routes.
# From repository root (web package is monorepo-local, not pip-installed)
pip install -e ".[web]"
export API_KEY=dev-secret
export REQUIRE_AUTH=true
uvicorn web.backend.app:app --reload --port 8000
Or with Docker:
export API_KEY=change-me-in-production
docker compose up --build
- Frontend: http://localhost:8080 (proxies
/apito backend) - Health: http://localhost:8080/api/../health via backend internal port
Configure via environment variables:
| Variable | Default | Description |
|---|---|---|
API_KEY |
(empty) | Required when REQUIRE_AUTH=true |
REQUIRE_AUTH |
true |
Protect history/trusted-key admin routes |
CORS_ORIGINS |
http://localhost:8080 |
Comma-separated allowed origins |
MAX_UPLOAD_BYTES |
536870912 |
Max upload size (512 MiB) |
DOCS_ENABLED |
false |
Expose OpenAPI /docs |
Uploaded filenames are not stored; history uses anonymized upload_ref values.
Tests
pytest
make lint
make docker-test
Project layout
src/c2pa_health_imaging/ Python library (binding, crypto, DICOM, NIfTI, CLI)
web/backend/ FastAPI + SQLite API (monorepo-local)
web/frontend/ React + Vite + Catalyst UI Kit
tests/ pytest suite
License
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 c2pa_health_imaging-0.0.1.tar.gz.
File metadata
- Download URL: c2pa_health_imaging-0.0.1.tar.gz
- Upload date:
- Size: 21.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7dff77d04c490b0c9d4caffaae4d0afecefc3bfeae1990953426d47b3fdddc05
|
|
| MD5 |
7bae29bb49c62948165ed3c17ea19f04
|
|
| BLAKE2b-256 |
9df741e0212b7e11de514eb0d3c6af4040bc414301160d3f60cefa36155c0087
|
Provenance
The following attestation bundles were made for c2pa_health_imaging-0.0.1.tar.gz:
Publisher:
release.yml on imagin4care/c2pa-health-imaging
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
c2pa_health_imaging-0.0.1.tar.gz -
Subject digest:
7dff77d04c490b0c9d4caffaae4d0afecefc3bfeae1990953426d47b3fdddc05 - Sigstore transparency entry: 1804180663
- Sigstore integration time:
-
Permalink:
imagin4care/c2pa-health-imaging@1ec218aa3387ade976211e04967fcfc7a09d4b10 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/imagin4care
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1ec218aa3387ade976211e04967fcfc7a09d4b10 -
Trigger Event:
push
-
Statement type:
File details
Details for the file c2pa_health_imaging-0.0.1-py3-none-any.whl.
File metadata
- Download URL: c2pa_health_imaging-0.0.1-py3-none-any.whl
- Upload date:
- Size: 24.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0eeccc26c1d75471aa403ee48095533ac7d1b7711c019c939f9a8bba37de445
|
|
| MD5 |
e56f49c8854ba7f5690c06cb8bfd8ebe
|
|
| BLAKE2b-256 |
0971ef5bb30f115c2d288c4ba3f222eef68f6244ab00a5fadb3aedc3ff36b17d
|
Provenance
The following attestation bundles were made for c2pa_health_imaging-0.0.1-py3-none-any.whl:
Publisher:
release.yml on imagin4care/c2pa-health-imaging
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
c2pa_health_imaging-0.0.1-py3-none-any.whl -
Subject digest:
c0eeccc26c1d75471aa403ee48095533ac7d1b7711c019c939f9a8bba37de445 - Sigstore transparency entry: 1804180715
- Sigstore integration time:
-
Permalink:
imagin4care/c2pa-health-imaging@1ec218aa3387ade976211e04967fcfc7a09d4b10 -
Branch / Tag:
refs/tags/v0.0.1 - Owner: https://github.com/imagin4care
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1ec218aa3387ade976211e04967fcfc7a09d4b10 -
Trigger Event:
push
-
Statement type: