Bago magpadala ng audio at video ang Baby Monitor Timmy, kailangang mahanap at pagkatiwalaan ng dalawang device ang isa't isa. Ang pagpapares na hakbang ay ang pinakamahalagang sandali sa buong proseso. Dito ko ipapaliwanag kung paano nagpapares ang Timmy, anong cryptography ang nasa likod nito, at bakit hindi kayang agawin nang hindi napapansin ng malapit na attacker ang koneksyon.
Ang problema: Paano malalaman ng device ko kung sino ang kausap nito?
Kapag unang nagkonekta ang dalawang device, ito ang pangunahing tanong: talagang Device B ba ang kausap ng Device A, o may ibang taong nakasingit sa pagitan? Sa cryptography, tinatawag itong man-in-the-middle attack (MITM).
Nilulutas ito ng Timmy gamit ang Elliptic Curve Diffie-Hellman (ECDH) key exchange sa Firebase, na may kasamang biswal na pag-verify ng user.
Ipinapakita ng sumusunod na diagram ang buong daloy ng pagpapares sa isang tingin:
sequenceDiagram
autonumber
participant A as 📱 Device A
participant F as ☁️ Firebase
participant B as 📱 Device B
Note over A,B: Phase 1 — Discovery
A->>A: Generate ECDH key pair (P-256)
B->>B: Generate ECDH key pair (P-256)
alt Auto-Pairing (Nearby BLE)
A-->>B: BLE broadcast: SBM:XKQM
B-->>A: BLE broadcast: SBM:R7NP
Note over A,B: Lower code wins → determines creator/joiner
else Manual Pairing
A->>A: Display 4-char code
Note right of A: User reads code
B->>B: User enters code
end
Note over A,B: Phase 2 — ECDH Key Exchange
A->>F: Write public key (PubA) to meeting doc
B->>F: Write public key (PubB) to meeting doc
F-->>B: Read PubA
F-->>A: Read PubB
Note over A,B: Phase 3 — Shared Secret
A->>A: sharedSecret = ECDH(privA, PubB)
B->>B: sharedSecret = ECDH(privB, PubA)
Note over A,B: Both compute identical 32-byte secret
A->>A: SAS = SHA-256("sas:" + sort(PubA,PubB) + secret) → 2-digit number
B->>B: SAS = SHA-256("sas:" + sort(PubA,PubB) + secret) → 2-digit number
Note over A,B: Phase 4 — Visual Verification
A->>A: Display SAS: 42
B->>B: Display SAS: 42
Note over A,B: 👤 User compares numbers on both screens
A->>A: User confirms ✓
B->>B: User confirms ✓
Note over A,B: Phase 5 — Key Derivation
A->>A: pairingKey = SHA-256("pair:" + secret)
B->>B: pairingKey = SHA-256("pair:" + secret)
A->>A: docKey = SHA-256("doc:" + pairingKey)
A->>A: encKey = SHA-256("enc:" + pairingKey)
Note over A,B: ✅ Paired — all future signaling encrypted with AES-256-GCM
Buong pagkakasunod-sunod ng pairing protocol — nae-edit na source: docs/diagrams/pairing-sequence.mmd
Hakbang 1: Gumagawa ng key pair ang bawat device
Kapag binuksan ang pairing screen, gumagawa ang bawat device ng pansamantalang ECDH key pair sa P-256 curve (secp256r1):
- Isang private key — nananatili lang sa device
- Isang public key — ipinagpapalit sa Firebase
Ginagawa ang mga key gamit ang cryptographically secure random number generator (Random.secure())
at valid lang para sa iisang pagtatangkang magpares. Gumagawa ng mga bagong key
sa bawat bagong pagtatangka.
Hakbang 2: Magpalitan ng public key sa Firebase
Para mahanap ng dalawang device ang isa't isa, gumagamit ang Timmy ng 4-character na code bilang tagpuan. Maaaring awtomatikong matuklasan ang code na ito sa pamamagitan ng Nearby Connections (Bluetooth Low Energy) o manu-manong ilagay. Wala itong cryptographic na halaga; tinutulungan lang nitong mahanap ng dalawang device ang parehong Firebase Firestore document.
Kapag alam na ng parehong device ang code, isinusulat ng bawat isa ang public ECDH key nito sa isang pinagsasaluhang Firestore document. Pagkatapos, binabasa ng bawat device ang public key ng kabilang device mula sa document na iyon.
Mahalaga: ang public key lang ang ipinapadala. Hindi kailanman umaalis sa device ang private key. Makikita ng sinumang nagmamasid sa Firebase traffic ang mga public key, pero hindi nila makukuha ang shared secret mula rito. Nakasalalay ito sa hirap ng Elliptic Curve Discrete Logarithm Problem (ECDLP).
Hakbang 3: Pagkalkula ng shared secret
Kapag natuklasan na ng parehong device ang public key ng isa't isa, nakapag-iisa nilang kinakalkula ang parehong shared secret:
sharedSecret = ECDH(myPrivateKey, remotePublicKey)
→ 32 bytes (identical on both devices)
Ginagarantiya ng matematika ng elliptic curves na pareho ang resulta ng dalawang kalkulasyon, kahit sarili nitong private key at public key lang ng kabila ang alam ng bawat device.
Hakbang 4: Ang verification number (SAS)
Mula sa shared secret, kinukuha ang isang Short Authentication String (SAS) — isang dalawang-digit na numero na ipinapakita sa parehong device:
hash = SHA-256("sas:" + sort(pubkeyA, pubkeyB) + sharedSecret)
number = (hash[0] × 256 + hash[1]) mod 100 → 00 to 99
Parehong numero ang ipinapakita ng dalawang device — halimbawa, 42. Biswal na ikinukumpara ng user kung tugma ang mga numero sa dalawang screen, saka kinukumpirma sa bawat device nang magkahiwalay.
Bakit hindi ito mapeke ng attacker
Kailangang harangin ng man-in-the-middle ang key exchange sa Firebase. Partikular, kailangan nitong:
- Palitan ang totoong public key na naka-store sa Firestore document ng sarili nitong mga key
- Magtatag ng magkahiwalay na shared secret sa bawat device
sequenceDiagram
autonumber
participant A as 📱 Device A
participant M as 🕵️ Attacker (MITM)
participant B as 📱 Device B
Note over A,B: Attacker intercepts the Firebase key exchange
A->>A: Generate key pair (privA, PubA)
B->>B: Generate key pair (privB, PubB)
M->>M: Generate TWO key pairs (privM1, PubM1) + (privM2, PubM2)
A->>M: Write PubA to Firebase
M->>M: Replace PubA with PubM1
M->>B: B reads PubM1 (thinks it is PubA)
B->>M: Write PubB to Firebase
M->>M: Replace PubB with PubM2
M->>A: A reads PubM2 (thinks it is PubB)
Note over A,B: Each device computes a DIFFERENT shared secret
A->>A: secret_A = ECDH(privA, PubM2)
M->>M: secret_A = ECDH(privM2, PubA)
M->>M: secret_B = ECDH(privM1, PubB)
B->>B: secret_B = ECDH(privB, PubM1)
Note over A,M: secret_A ≠ secret_B
A->>A: SAS_A = SHA-256("sas:" + sort(PubA,PubM2) + secret_A) → 73
B->>B: SAS_B = SHA-256("sas:" + sort(PubM1,PubB) + secret_B) → 18
rect rgb(255, 230, 230)
Note over A,B: ❌ User sees DIFFERENT numbers!
A->>A: Display: 73
B->>B: Display: 18
Note over A,B: 👤 User notices mismatch → cancels pairing
end
Note over A,B: 🛡️ Attack detected — MITM cannot force SAS match (P = 1/100)
Pagtukoy ng man-in-the-middle sa pamamagitan ng hindi pagtugma ng SAS — nae-edit na source: docs/diagrams/mitm-detection.mmd
Sa kasong ito, kumukuwenta ang attacker ng shared secret S_A kasama ang Device A at ng
ibang shared secret S_B kasama ang Device B. Dahil S_A ≠ S_B,
kumukuwenta ang mga device ng magkaibang verification number.
Hindi mapagtutugma ng attacker ang mga numero dahil:
- Hindi nito alam ang private key ng mga device
- Hindi nababaligtad ang SHA-256
- Ang posibilidad ng random na pagtugma ay 1 sa bawat 100
Makakakita ang user ng magkaibang numero sa mga screen at kakanselahin ang pagpapares. Sa puntong iyon, naging kapansin-pansin na ang pag-atake.
Hakbang 5: Pagtatapos ng pagpapares
Kapag nakumpirma na ng user ang verification sa parehong device saka lang matatapos ang pagpapares:
- Isang 64-character na pairing key (256 bits) ang kinukuha mula sa shared secret:
SHA-256("pair:" + sharedSecret) → pairingKey - Kinukuha ang document key bilang
SHA-256("doc:" + pairingKey)at ginagamit bilang Firestore document key - Kinukuha ang encryption key bilang
SHA-256("enc:" + pairingKey)at nagbibigay ng AES-256-GCM key para sa naka-encrypt na signaling - Parehong sine-save ng dalawang device ang pairing key at lilipat sa pagpili ng mode
Mula rito, lahat ng susunod na pagtatangkang kumonekta (Firestore signaling, WebRTC setup) ay naka-encrypt gamit ang pinagsasaluhang AES-256-GCM key. Ang pairing key ay hindi kailanman ipinapadala sa backend; ang SHA-256 hash lang nito ang ginagamit bilang document identifier.
Arkitektura ng system
Ipinapakita ng sumusunod na diagram ang mga component na kasangkot sa pagpapares at komunikasyon:
flowchart TB
BABY["📱 Baby Phone
Baby Mode"]
PARENT["📱 Parent Phone
Parent Mode"]
BABY <==>|"🔒 WebRTC Peer-to-Peer · DTLS-SRTP
Audio · Video · DataChannel"| PARENT
BABY -.-|"🔵 Bluetooth LE · Nearby
Auto-Discovery"| PARENT
subgraph FIREBASE["☁️ Firebase (Google Cloud)"]
direction LR
AUTH["🪪 Anonymous
Authentication"]
FS["📄 Firestore
Pairing + Signaling"]
CF["⚡ Cloud Functions
getTurnCredentials"]
end
BABY <-->|"🔐 AES-256-GCM encrypted
SDP · ICE · ECDH keys"| FS
FS <-->|"🔐 AES-256-GCM encrypted
SDP · ICE · ECDH keys"| PARENT
BABY -.->|Token| AUTH
PARENT -.->|Token| AUTH
STUN["📡 STUN server
stun.cloudflare.com:3478"]
TURN["🔄 TURN relay
local or Cloudflare"]
BABY & PARENT -->|Short-lived credentials| CF
CF -->|local first, Cloudflare fallback| TURN
BABY & PARENT -.->|NAT Traversal| STUN
BABY -.->|"Relay Fallback"| TURN
TURN -.->|"Relay Fallback"| PARENT
style BABY fill:#FBF6F0,stroke:#B5734A,stroke-width:2px
style PARENT fill:#FBF6F0,stroke:#B5734A,stroke-width:2px
style FIREBASE fill:#fff5f5,stroke:#E9B44C,stroke-width:2px
style AUTH fill:#E9B44C,stroke:#2B2D42
style FS fill:#E9B44C,stroke:#2B2D42
style CF fill:#E9B44C,stroke:#2B2D42
style STUN fill:#F6E3D2,stroke:#B5734A
style TURN fill:#7BC47F,stroke:#2B2D42
Pangkalahatang-ideya ng arkitektura ng system — nae-edit na source: docs/diagrams/pairing-architecture.mmd
Mga communication path nang detalyado:
- WebRTC peer-to-peer (makapal na linya): Direktang dumadaloy ang audio, video, at DataChannel sa pagitan ng mga device — naka-encrypt gamit ang DTLS-SRTP. Walang server na nakakakita sa data na ito.
- Firebase Firestore (solidong linya): Dumadaan sa Firestore ang pairing data (ECDH keys) at signaling (SDP/ICE) — end-to-end encrypted gamit ang AES-256-GCM. Hindi ma-decrypt ng Firebase ang data.
- STUN server: Natutuklasan ng parehong device ang kanilang public IP address para makapagtatag ng direktang peer-to-peer na koneksyon.
- TURN relay: Kung hindi posible ang direktang koneksyon (hal., sa mobile data), ipinapasa ng napiling lokal o Cloudflare TURN server ang naka-encrypt na media. Kinukuha ang mga pansamantalang credential (24h) sa pamamagitan ng Firebase Cloud Functions.
- Bluetooth LE (putol-putol na linya): Awtomatikong natutuklasan ng Nearby Connections ang mga kalapit na device — meeting code lang ang ipinapadala, walang key material.
Fallback: Manu-manong paglalagay ng code
Kung hindi available ang Bluetooth (hal., sa mga lumang device), maaari ring manu-manong i-type ang 4-character na code. Ginagamit sa manu-manong paglalagay ang parehong ECDH key exchange at parehong SAS verification gaya ng awtomatikong pagpapares. Ang kaibahan lang ay binabasa at tina-type ng user ang code sa halip na matuklasan ito sa BLE.
Dahil nangyayari ang ECDH key exchange sa Firebase sa parehong kaso, magkaparehoang seguridad. Tagpuan lang ang 4-character na code; nakabatay ang totoong encryption sa 256-bit na key na nagmula sa ECDH.
Buod
| Mekanismo ng seguridad | Pinoprotektahan laban sa |
|---|---|
| ECDH key exchange (P-256) | Pakikinig sa key exchange traffic |
| Pansamantalang key pair | Forward secrecy — nananatiling ligtas ang mga dating pagpapares |
| Biswal na verification number (SAS) | Man-in-the-middle (MITM) habang nagpapalitan ng key |
| SHA-256 hash bilang document key | Pagkuha ng code mula sa Firestore |
| AES-256-GCM encryption | Pakikinig sa signaling data |
| Kumpirmasyon sa magkabilang panig | Isahang panig na pagpapares nang hindi alam ng user |
| DTLS-SRTP (WebRTC) | Pakikinig sa audio/video |
Magkakaugnay ang mga layer na ito: pinoprotektahan ng ECDH ang key exchange, pinoprotektahan ng verification number laban sa MITM, pinoprotektahan ng AES-256-GCM ang signaling, at pinoprotektahan ng WebRTC ang media. Kailangang sirain ng attacker ang chain na ito sa ilang bahagi nang hindi napapansin ng mga device o magulang.