Athena — auditPic/verification-protocol.md

AuditPic — Verification Protocol

Purpose

This document describes the cryptographic protocol used to sign photos at capture time and verify their integrity later. It is written so that any technically competent third party can independently audit a photo without using the AuditPic app.


Signing (at capture time)

Step 1 — Hash the image on device

The mobile app computes the SHA-256 hash of the raw image bytes before any upload or server contact.

sha256 = SHA-256(raw_image_bytes)          # hex string, 64 characters

This ensures the server cannot substitute a different hash — the device is the sole source of truth for the hash.

Step 2 — Record device timestamp

capturedAt = current UTC time in ISO-8601  # e.g. 2026-03-27T14:30:00.000Z

Step 3 — Upload to server

The app sends (file, sha256, capturedAt) to POST /api/v1/photos.

Step 4 — Server signs the record

The server records its own timestamp:

signedAt = current server UTC time

The server computes an HMAC-SHA256 over the concatenation of sha256 and signedAt:

payload   = sha256 + ":" + signedAt.epochMilli
signature = HMAC-SHA256(payload, HMAC_SECRET)   # hex string, 64 characters

The HMAC_SECRET is a server-side secret stored in environment variables; it is never exposed to clients.

Step 5 — Store record

The server stores in PostgreSQL:

verificationId  UUID (public, shareable)
capturedAt      from device
signedAt        from server
sha256          from device
signature       HMAC computed by server
storageKey      path in MinIO

The original image bytes are stored in MinIO at storageKey.


Verification (at any time)

Method A — Using the AuditPic app

  1. Open the Verify screen
  2. Enter the verificationId (or scan QR)
  3. The app fetches { sha256, capturedAt, signedAt, isAiGenerated } from the server
  4. Optionally pick a local copy of the suspect photo
  5. The app computes SHA-256(local_photo_bytes) and compares to the stored sha256
  6. MATCH = photo is byte-for-byte identical to the original captured photo
  7. MISMATCH = at least one byte differs — the photo has been edited or replaced

Method B — Independent (no app required)

You only need: the verificationId, the suspect photo file, and any SHA-256 tool (e.g., shasum -a 256 on macOS/Linux).

1. Fetch the stored metadata

curl https://api.auditpic.com/api/v1/photos/{verificationId}

Response:

{
  "verificationId": "...",
  "capturedAt": "2026-03-27T14:30:00Z",
  "signedAt":   "2026-03-27T14:30:01Z",
  "sha256":     "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
  "isAiGenerated": false,
  "aiConfidence": 0.02
}

2. Hash the suspect photo

shasum -a 256 /path/to/suspect_photo.jpg
# Output: <hex_hash>  /path/to/suspect_photo.jpg

3. Compare

  • If <hex_hash> == sha256 from step 1 → unaltered
  • If different → modified

4. Download the original for side-by-side comparison

curl https://api.auditpic.com/api/v1/photos/{verificationId}/download
# Returns: { "url": "https://minio.../..." }

curl -o original.jpg "<presigned_url>"
shasum -a 256 original.jpg   # Should match sha256 from metadata

What the protocol does NOT guarantee

  • It does not guarantee the photo was taken of a real scene (only that it wasn't altered after capture)
  • The device clock (capturedAt) is user-controlled; signedAt (server time) is authoritative for tamper-evidence
  • AI detection (isAiGenerated) is a probabilistic score, not a guarantee
  • If the user took the photo of an already-AI-generated image, the protocol cannot detect that (it only detects post-capture alteration)

Threat model

| Threat | Mitigated? | How | |---|---|---| | Photo edited after capture | Yes | SHA-256 mismatch | | Photo replaced on server | Yes | HMAC signature ties hash+timestamp to server secret | | User claims wrong capture time | Partial | signedAt (server time) is in the record | | Server collusion | No | Requires trusting the server operator | | AI-generated photo submitted as real | Partial | AI detection service (probabilistic) |

Reacties

Nog geen reacties