Your Phone Already Has the Hardware to Prove a Photo Is Real. Nothing Uses It.
#opensource #mobile #security #reactnative
The Problem Is Already Here
In 2025 Adobe's Content Authenticity Initiative reported that 97% of organizations have encountered AI-generated content being used against them. Deepfakes, synthetic product photos, fabricated evidence.
Meanwhile every phone in your pocket has a tamper-resistant cryptographic chip sitting idle. Secure Enclave on iOS. StrongBox or TEE on Android. Hardware designed to sign things in a way that can't be extracted or faked.
Nobody is connecting these two facts.
C2PA: The Standard Nobody Talks About
C2PA is an open standard from Adobe, Microsoft, Intel and others. It works like HTTPS but for media files. A cryptographic manifest gets embedded directly into the JPEG containing:
- What device captured it
- When and where
- Every edit made after capture
- A signature that breaks if a single pixel changes
Leica, Sony and Nikon already ship C2PA in some cameras. But on mobile, where 90%+ of photos are taken? Almost nothing.
Enter attestation-photo-mobile
I built attestation-photo-mobile to close that gap.
It's a React Native package. You bring your own camera lib, take a photo, and pass the path. The package does the rest: hashes the image, signs it with hardware-backed keys, and embeds a full C2PA manifest before the file ever touches disk.
How It Works
The architecture has three layers:
- Native layer (Swift/Kotlin): Handles hardware keystore access. Provisions an ECDSA P-256 key inside Secure Enclave or StrongBox. This key never leaves the hardware.
- Rust layer (c2pa-rs): Builds the JUMBF manifest, computes the asset hash, constructs the C2PA claim. I tried doing this in pure JS first. Don't.
-
React Native bridge: Exposes a single
signPhoto(path)function and auseAttestedCapturehook that handles key provisioning, location prefetch, and error wrapping.
Usage
import { useAttestedCapture, saveToGallery } from '@rolobits/attestation-photo-mobile';
function CaptureScreen() {
const { signPhoto, isReady } = useAttestedCapture({
includeLocation: true,
appName: "My App",
nonce: "server-challenge-token",
});
const onCapture = async (photoPath) => {
// Sign and embed C2PA manifest
const signed = await signPhoto(photoPath);
// signed.trustLevel -> "secure_enclave" | "strongbox" | "tee"
// signed.embeddedManifest -> true
// signed.signature -> SHA-256 hex of original asset
await saveToGallery({ filePath: signed.path });
};
}
The output JPEG can be verified with any C2PA tool. Upload it to verify.contentauthenticity.org or run:
cargo install c2patool
c2patool verify output.jpg
What Gets Blocked
The SDK runs device integrity checks before signing. Jailbroken or rooted devices get E_COMPROMISED_DEVICE. No Secure Enclave or StrongBox? E_NO_TRUSTED_HARDWARE. You can control this with requireTrustedHardware: true|false.
Where This Actually Matters
This isn't a solution looking for a problem. These are scenarios where someone has a financial incentive to submit fake photos:
- Insurance claims: Snap damage photos in-app. Each one is hardware-signed with device, location, timestamp. The adjuster's backend verifies the manifest automatically.
- Marketplace listings: Verified photos for cars, real estate, rentals. Buyers know the images aren't AI-generated or recycled from 2019.
- Field inspections: Construction sites, equipment audits. Timestamped proof of conditions for compliance.
- KYC: Selfie-based identity verification where the photo is provably from a real device, not a generated face fed through a virtual camera.
This is a v1. Here's what's missing:
- Self-signed certificates. The signing key has no CA chain. Verifiers will show a valid signature but "unknown signer." This means tamper detection works today but attribution doesn't. CA integration is the next priority.
Top comments (0)