Capture photos with cryptographic proof of authenticity.
SignedShot iOS SDK enables your app to capture photos with cryptographic proof that they haven't been altered since capture. It uses:
- Secure Enclave for tamper-proof key storage (P-256 ECDSA)
- SHA-256 hashing before any disk write
- Firebase App Check for device attestation (optional)
- Device registration with optional attestation
- Capture session management
- Content hashing and signing with Secure Enclave
- Sidecar JSON generation
- Keychain-based credential storage
- iOS 16.0+
- Xcode 15.0+
- Swift 5.9+
- Device with Secure Enclave (iPhone 5s or later)
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/SignedShot/signedshot-ios.git", from: "0.1.0")
]Or in Xcode: File → Add Package Dependencies → Enter the repository URL.
import SignedShotSDK
let config = SignedShotConfiguration(
baseURLString: "https://api.signedshot.io",
publisherId: "your-publisher-id"
)!
let client = SignedShotClient(configuration: config)// Register once per device
if !client.isDeviceRegistered {
let response = try await client.registerDevice()
print("Device registered: \(response.deviceId)")
}// Start session before capturing
let session = try await client.startSession()
// session.nonce - cryptographic nonce for this capture
// session.expiresAt - session expiration time// After capturing the photo...
let integrityService = MediaIntegrityService(enclaveService: SecureEnclaveService())
// Sign the image data (hashes and signs with Secure Enclave)
let integrity = try await integrityService.sign(imageData: jpegData)
// Exchange nonce for trust token
let trustToken = try await client.exchangeNonce(session.nonce)
// Generate sidecar
let sidecar = SidecarGenerator().generate(
captureId: session.captureId,
trustToken: trustToken,
mediaIntegrity: integrity
)
// Save photo and sidecar together
try jpegData.write(to: photoURL)
try sidecar.write(to: sidecarURL)For production apps, enable device attestation with Firebase App Check:
Add Firebase to your project and enable App Check in the Firebase Console.
import FirebaseCore
import FirebaseAppCheck
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Set up App Check before Firebase.configure()
let providerFactory = MyAppCheckProviderFactory()
AppCheck.setAppCheckProviderFactory(providerFactory)
FirebaseApp.configure()
return true
}
}
class MyAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
#if targetEnvironment(simulator)
return AppCheckDebugProvider(app: app)
#else
return AppAttestProvider(app: app)
#endif
}
}// Get App Check token
let appCheckToken = try await AppCheck.appCheck().token(forcingRefresh: false)
// Register with attestation
let response = try await client.registerDevice(attestationToken: appCheckToken.token)Your publisher must be configured with attestation on the backend:
curl -X PATCH https://api.signedshot.io/publishers/YOUR_PUBLISHER_ID \
-H "Content-Type: application/json" \
-d '{
"sandbox": false,
"attestation_provider": "firebase_app_check",
"attestation_bundle_id": "com.yourcompany.yourapp"
}'See the ExampleApp/ directory for a complete implementation demonstrating:
- Camera capture with AVFoundation
- Secure Enclave key management
- Firebase App Check integration
- Sidecar generation and photo export
To run the example:
cd ExampleApp
open ExampleApp.xcodeprojSources/SignedShotSDK/
├── SignedShotClient.swift # Main API client
├── CaptureService.swift # Session management
├── SecureEnclaveService.swift # Secure Enclave key operations
├── MediaIntegrityService.swift # Hashing and signing
├── Sidecar.swift # Sidecar JSON generation
├── KeychainStorage.swift # Credential storage
└── APIModels.swift # Request/response models
- Private keys never leave the device - Generated and stored in Secure Enclave
- Keys are hardware-bound - Cannot be extracted or copied
- Content hashed before disk write - Prevents tampering window
- Attestation proves device legitimacy - Firebase App Check verifies real devices
- signedshot-api - Backend API
- signedshot-validator - Verification CLI/library
MIT License - see LICENSE for details.