Tools: Your Phone Already Has the Hardware to Prove a Photo Is Real. Nothing Uses It.

Tools: Your Phone Already Has the Hardware to Prove a Photo Is Real. Nothing Uses It.

Source: Dev.to

Your Phone Already Has the Hardware to Prove a Photo Is Real. Nothing Uses It. ## The Problem Is Already Here ## C2PA: The Standard Nobody Talks About ## Enter attestation-photo-mobile ## How It Works ## What Gets Blocked ## Where This Actually Matters #opensource #mobile #security #reactnative 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 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: Leica, Sony and Nikon already ship C2PA in some cameras. But on mobile, where 90%+ of photos are taken? Almost nothing. 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. The architecture has three layers: The output JPEG can be verified with any C2PA tool. Upload it to verify.contentauthenticity.org or run: 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. This isn't a solution looking for a problem. These are scenarios where someone has a financial incentive to submit fake photos: This is a v1. Here's what's missing: 👉 GitHub: RoloBits/attestation-photo-mobile Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse COMMAND_BLOCK: 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 }); }; } Enter fullscreen mode Exit fullscreen mode COMMAND_BLOCK: 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 }); }; } COMMAND_BLOCK: 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 }); }; } CODE_BLOCK: cargo install c2patool c2patool verify output.jpg Enter fullscreen mode Exit fullscreen mode CODE_BLOCK: cargo install c2patool c2patool verify output.jpg CODE_BLOCK: cargo install c2patool c2patool verify output.jpg - What device captured it - When and where - Every edit made after capture - A signature that breaks if a single pixel changes - 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 a useAttestedCapture hook that handles key provisioning, location prefetch, and error wrapping. - 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. - 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.