diff --git a/Android-Secure-Capture-%26-Timestamp-%E2%80%93-Technical-Blueprint.md b/Android-Secure-Capture-%26-Timestamp-%E2%80%93-Technical-Blueprint.md new file mode 100644 index 0000000..fbb79b8 --- /dev/null +++ b/Android-Secure-Capture-%26-Timestamp-%E2%80%93-Technical-Blueprint.md @@ -0,0 +1,175 @@ +## 1. Product vision + +A minimal **Android app (Kotlin)** that can, on user demand, **capture video + audio in the background**, stream it live through **WebRTC** to a backend, and locally buffer a loss‑tolerant copy. On the server side we **hash** each media chunk and immediately obtain a **qualified timestamp (QTSP)** or blockchain attestation, preserving an end‑to‑end, court‑ready chain of custody. + +--- + +## 2. Functional requirements + +|  ID | Requirement | Notes | +| ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | +|  FR‑1 | User can start/stop a secure recording session from a single UI toggle. | Must show foreground notification due to Android 13+ background recording rules. | +|  FR‑2 | App records **front or rear camera** and **microphone** simultaneously. | 1080 p @ 30 fps baseline. | +|  FR‑3 | App survives screen‑off / app switch (uses **Foreground Service**). | "MediaProjection + CameraX" or pure CameraX route. | +|  FR‑4 | Each encoded frame is sent via **WebRTC data/media channel** to server. | SRTP for privacy. | +|  FR‑5 | If network is lost, chunks are stored encrypted in app sandbox and retried with **WorkManager**. | | +|  FR‑6 | Server receives RTP, hashes every GOP with SHA‑256, requests timestamp, stores tuple *(hash, RFC 3161 TST, chunk path)* in DB + S3‑like object store. | | +|  FR‑7 | App exposes a "Verify" screen: download TST receipt & proof for any session, recompute local hash, and show green / red indicator. | | + +--- + +## 3. High‑level architecture + +``` +┌───────────────┐ SRTP / ICE ┌──────────────────┐ +│ Android App │ ─────── peer connection ─► │ Signalling + │ +│ Kotlin + │ ◄────── (TURN fallback) ◄─ │ Media SFU/Router│ +│ Foreground │ │ (Janus / Pion) │ +│ Service │ REST/WebSocket │ │ +└──────▲────────┘ │ └─────────▲────────┘ + │ local AES‑256 store │ SHA‑256(chunk) │ gRPC + │ (Room + SQLCipher) ▼ ▼ +┌──────┴────────┐ ┌───────────────┐ ┌───────────────┐ +│ WorkManager │ │ Hasher + │ TSP │ Qualified │ +│ retry queue │ │ TimeStamper │◄────►│ TS Authority │ +└───────────────┘ └───────────────┘ └───────────────┘ +``` + +* **Media path**: CameraX → MediaCodec (H.264) → `SurfaceTexture` → WebRTC **VideoTrack**. +* **Audio path**: `AudioRecord` (OPUS) → WebRTC **AudioTrack**. + +--- + +## 4. Android implementation details + +### 4.1 Permissions & privacy + +* `CAMERA`, `RECORD_AUDIO`, `FOREGROUND_SERVICE_CAMERA`, `POST_NOTIFICATIONS` (Tiramisu+). +* Runtime request flow wrapped in coroutine `suspend fun requestPermissions()`. + +### 4.2 Foreground RecordingService + +```kotlin +@ForegroundService +class RecordingService : Service() { + private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob()) + override fun onStartCommand(i: Intent?, flags: Int, startId: Int): Int { + startForeground(NOTIF_ID, buildNotif()) + scope.launch { startCaptureSession() } + return START_STICKY + } + private suspend fun startCaptureSession() { + val camera = CameraXInitializer(cameraSelector).open() + val rtcClient = WebRtcClient(iceServers) + val videoSrc = CameraXVideoSource(camera) + rtcClient.addTrack(videoSrc.track) + rtcClient.addTrack(MicAudioSource().track) + rtcClient.connect(signalServer) + } + override fun onDestroy() { + scope.cancel(); + super.onDestroy() + } +} +``` + +*Notification must be **user‑dismissible** and display recording timer — meets Android policy.* + +### 4.3 Local buffering & WorkManager + +```kotlin +class ChunkWriter(private val ctx: Context){ + suspend fun saveChunk(bytes: ByteArray){ + val encrypted = crypto.encrypt(bytes) + room.chunkDao().insert(ChunkEntity(ts=now(), blob=encrypted)) + } +} +``` + +`PeriodicWorkRequest` checks DB → upload to server via REST → on success delete row. + +--- + +## 5. Server‑side pipeline (Golang example) + +```go +// Media handler (Pion SFU hook) +func onRTPPacket(pkt *rtp.Packet){ + chunkBuf.Write(pkt.Payload) + if gopFinished(pkt){ + h := sha256.Sum256(chunkBuf.Bytes()) + tst, _ := tspClient.Timestamp(h[:]) + store.Save(chunkBuf.Bytes(), h[:], tst) + chunkBuf.Reset() + } +} +``` + +*Timestamp sources*:  + +1. **QTSP (eIDAS)** – Camerfirma TSA, FNMT, Poste Italiane, etc. +2. **Blockchain fallback** – embed hash in Bitcoin OP\_RETURN; use public API for proof. + +--- + +## 6. Performance & energy + +| Component | Trade‑off | Recommendation | +| ------------------------- | --------------------------------------------------------- | ------------------------------------------------------- | +| CameraX vs. MediaRecorder | CameraX gives **Surface** for WebRTC; slightly higher CPU | Acceptable on devices ≥ Snapdragon 730 | +| Video codec | H.264 Baseline profile | Widely HW‑accelerated, 1 Mbps @1080p 30fps ≈ 2 h ≈ 1 GB | +| Audio | OPUS 48 kHz 16 kbps | Low bandwidth, good quality | +| Encryption | SRTP inline; local AES‑256 | negligible on ARMv8 AES‑NI | + +--- + +## 7. Security considerations + +* **Zero‑Config Keys**: generate on first run, stored in Android Keystore. +* **Pinning**: TLS cert pin to signalling + REST host. +* **Tamper‑evident log**: every state change appended to SQLCipher DB with incremental hash chain. + +--- + +## 8. Roadmap + +1. **P0** – Local capture + save MP4. +2. **P1** – Add WebRTC streaming via public TURN. +3. **P2** – Server hash + QTSP integration. +4. **P3** – Verification UI + export proof bundle (ZIP: video + JSON hash + TST). +5. **P4** – Battery optimisation, Doze‑mode job scheduling. + +--- + +## 9. References / Tooling + +* *CameraX* Jetpack lib. +* *WebRTC‑KMP* for multiplatform client. +* **Pion SFU** (Go) or **Janus** (C) backend. +* **RFC 3161** Time‑Stamp Protocol. +* **ETS I EN 319 421** QTSP TSA policy. +* **SQLCipher** for on‑device encrypted DB. +* **gRPC** for low‑latency hash receipt. + +--- + +### Appendix A – Minimal Client ↔ Server handshake (pseudo‑sequence) + +``` +User taps Record + │ + ├─► RecordingService.startForeground() + │ ├─ CameraX open & startPreview + │ ├─ WebRtcClient.createOffer() + │ └─ Signal via WebSocket + │ +Signalling Server ↔ offers/answers ICE + │ +RTP/RTCP flow + │ +Hasher splits GOP → SHA‑256 → TSA → OK + │ +Server sends `hashReceipt` JSON over data‑channel ➜ App shows ✅ +``` + +*End of document*