Baby Monitor Timmy аудио мен бейнені жібермес бұрын, екі құрылғы бір-бірін тауып, бір-біріне сенуі керек. Бұл жұптастыру кезеңі — бүкіл үдерістегі ең маңызды сәт. Мұнда Timmy қалай жұптасатынын, оның артында қандай криптография барын және жақын маңдағы шабуылдаушының қосылымды байқатпай басқара алмайтынын түсіндіремін.
Мәселе: менің құрылғым кіммен сөйлесіп тұрғанын қайдан біледі?
Екі құрылғы алғаш рет қосылғанда, басты сұрақ мынау: А құрылғысы шынымен B құрылғысымен сөйлесіп тұр ма, әлде арада біреу бар ма? Криптографияда бұл ортадағы адам шабуылы (MITM) деп аталады.
Timmy бұл мәселені эллиптикалық қисықтардағы Диффи — Хеллман (ECDH) кілт алмасуын Firebase арқылы жүргізіп, оны пайдаланушының көзбен тексеруімен үйлестіру арқылы шешеді..
Төмендегі диаграмма жұптастырудың толық барысын бірден көрсетеді:
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
Толық жұптастыру хаттамасының тізбегі — өңдеуге болатын бастапқы файл: docs/diagrams/pairing-sequence.mmd
1-қадам: Әр құрылғы кілттер жұбын жасайды
Жұптастыру экранын ашқанда, әр құрылғы уақытша ECDH кілттер жұбын P-256 (secp256r1) қисығында жасайды:
- Жеке кілт — тек құрылғының өзінде қалады
- Ашық кілт — Firebase арқылы алмасылады
Кілттер криптографиялық тұрғыдан қауіпсіз кездейсоқ сандар генераторының көмегімен жасалады (Random.secure())
және олар тек осы бір жұптастыру әрекеті үшін жарамды. Әр жаңа әрекет үшін жаңа кілттер жасалады.
2-қадам: Ашық кілттерді Firebase арқылы алмасу
Екі құрылғының бір-бірін табуы үшін Timmy 4 таңбалы кодты кездесу нүктесі ретінде пайдаланады. Бұл кодты Nearby Connections (Bluetooth Low Energy) арқылы автоматты түрде табуға немесе қолмен енгізуге болады. Оның криптографиялық мәні жоқ; ол тек екі құрылғының бір Firebase Firestore құжатын табуына көмектеседі.
Екі құрылғы да кодты білген соң, әрқайсысы өзінің ашық ECDH кілтін ортақ Firestore құжатынажазады. Содан кейін әр құрылғы сол құжаттан екіншісінің ашық кілтін оқиды.
Ең маңыздысы: тек ашық кілт жіберіледі. Жеке кілт құрылғыдан ешқашан шықпайды. Firebase трафигін бақылаған адам ашық кілттерді көреді, бірақ олардан ортақ құпияны есептей алмайды . Бұл эллиптикалық қисықтағы дискретті логарифм мәселесінің (ECDLP) күрделілігіне негізделген.
3-қадам: Ортақ құпияны есептеу
Екі құрылғы бір-бірінің ашық кілтін тапқаннан кейін, олар бірдей ортақ құпияны:
sharedSecret = ECDH(myPrivateKey, remotePublicKey)
→ 32 bytes (identical on both devices)
өздігінен есептейді. Эллиптикалық қисықтар математикасы екі есептеу де бірдей нәтиже беретінін қамтамасыз етеді, әр құрылғы тек өзінің жеке кілтін және екіншісінің ашық кілтін білсе де.
4-қадам: Тексеру нөмірі (SAS)
Ортақ құпиядан қысқа аутентификация жолы (SAS) алынады — екі құрылғыда да көрсетілетін екі таңбалы нөмір:
hash = SHA-256("sas:" + sort(pubkeyA, pubkeyB) + sharedSecret)
number = (hash[0] × 256 + hash[1]) mod 100 → 00 to 99
Екі құрылғыда бірдей нөмір көрсетіледі — мысалы, 42. Пайдаланушы екі экрандағы нөмірлердің сәйкес келетінін көзбен салыстырып, кейін әрбір құрылғыда жеке-жеке растайды.
Шабуылдаушы мұны неге қолдан жасай алмайды
Ортадағы адам шабуылын жасаушы Firebase-тегі кілт алмасуына араласуы керек. Нақты айтқанда, ол:
- Firestore құжатында сақталған шынайы ашық кілттерді өз кілттерімен ауыстыруы
- Әр құрылғымен бөлек ортақ құпия орнатуы
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)
SAS мәндерінің сәйкес келмеуі арқылы ортадағы адам шабуылын анықтау — өңдеуге болатын бастапқы файл: docs/diagrams/mitm-detection.mmd
Бұл жағдайда шабуылдаушы бір ортақ құпияны S_A A құрылғысымен, ал басқа ортақ құпияны S_B B құрылғысымен есептейді. Себебі S_A ≠ S_B,
құрылғылар әртүрлі тексеру нөмірлерін.
есептейді. Шабуылдаушы нөмірлерді бірдей ете алмайды, өйткені:
- Ол құрылғылардың жеке кілттерін білмейді
- SHA-256 нәтижесін кері есептеу мүмкін емес
- Кездейсоқ сәйкестік ықтималдығы небәрі 100-дің 1-і
Пайдаланушы экрандарда әртүрлі нөмірлерді көріп, жұптастырудан бас тартады. Сол сәтте шабуыл байқалады.
5-қадам: Жұптастыруды аяқтау
Пайдаланушы екі құрылғыда да тексеруді растағаннан кейін ғана жұптастыру аяқталады:
- Ортақ құпиядан 64 таңбалы жұптастыру кілті (256 бит) ортақ құпиядан алынады:
SHA-256("pair:" + sharedSecret) → pairingKey - Құжат кілті мынадан алынады:
SHA-256("doc:" + pairingKey)және Firestore құжатының кілті ретінде қызмет етеді - Шифрлау кілті мынадан алынады:
SHA-256("enc:" + pairingKey)және шифрланған сигнал алмасуға арналған AES-256-GCM кілтін береді - Екі құрылғы да бірдей жұптастыру кілтін сақтап, режим таңдау бетіне өтеді
Осы сәттен бастап барлық келесі қосылу әрекеттері (Firestore сигнал алмасуы, WebRTC орнатуы) ортақ AES-256-GCM кілтімен шифрланады. Жұптастыру кілті ешқашан серверлік бөлікке жіберілмейді; құжат идентификаторы ретінде тек оның SHA-256 хэші қолданылады.
Жүйе архитектурасы
Төмендегі диаграмма жұптастыру мен байланысқа қатысатын құрамдастарды көрсетеді:
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
Жүйе архитектурасына шолу — өңдеуге болатын бастапқы файл: docs/diagrams/pairing-architecture.mmd
Байланыс жолдары егжей-тегжейлі:
- WebRTC peer-to-peer (қалың сызық): Аудио, бейне және DataChannel құрылғылар арасында тікелей өтеді — DTLS-SRTP арқылы шифрланған. Бұл деректерді ешбір сервер көрмейді.
- Firebase Firestore (тұтас сызық): Жұптастыру деректері (ECDH кілттері) және сигнал алмасу (SDP/ICE) Firestore арқылы өтеді — AES-256-GCM көмегімен ұшынан ұшына дейін шифрланған. Firebase бұл деректерді шеше алмайды.
- STUN сервері: Екі құрылғы да тікелей peer-to-peer байланысын орнату үшін өзінің ашық IP мекенжайын анықтайды.
- TURN релесі: Тікелей қосылу мүмкін болмаса (мысалы, мобильді интернетте), таңдалған жергілікті не Cloudflare TURN сервері шифрланған медианы тасымалдайды. 24 сағатқа жарамды тіркелгі деректері Firebase Cloud Functions арқылы алынады.
- Bluetooth LE (нүктелі сызық): Nearby Connections жақындағы құрылғыларды автоматты түрде табады — тек кездесу коды жіберіледі, ешқандай кілт материалы берілмейді.
Балама: кодты қолмен енгізу
Bluetooth қолжетімсіз болса (мысалы, ескі құрылғыларда), 4 таңбалы кодты қолмен де теруге болады. Қолмен енгізуде автоматты жұптастырудағыдай ECDH кілт алмасуы мен SAS тексеруі қолданылады . Жалғыз айырмашылығы: код BLE арқылы табылмайды, оны пайдаланушы оқып, өзі тереді.
ECDH кілт алмасуы екі жағдайда да Firebase арқылы өтетіндіктен, қауіпсіздік деңгейі бірдей. 4 таңбалы код — тек кездесу нүктесі; нақты шифрлау ECDH-ден алынған 256 биттік кілтке негізделген.
Қорытынды
| Қауіпсіздік механизмі | Мыналардан қорғайды |
|---|---|
| ECDH кілт алмасуы (P-256) | Кілт алмасу трафигін тыңдау |
| Уақытша кілттер жұбы | Алға бағытталған құпиялылық — бұрынғы жұптастырулар қауіпсіз болып қалады |
| Көзбен тексерілетін нөмір (SAS) | Кілт алмасу кезіндегі ортадағы адам шабуылы (MITM) |
| Құжат кілті ретінде SHA-256 хэші | Firestore-дан кодты шығарып алу |
| AES-256-GCM шифрлауы | Сигнал алмасу деректерін тыңдау |
| Екі жақтың растауы | Пайдаланушы білмейтін біржақты жұптастыру |
| DTLS-SRTP (WebRTC) | Аудио/бейнені тыңдау |
Бұл қабаттар бір-бірін толықтырады: ECDH кілт алмасуды, тексеру нөмірі MITM-нен, AES-256-GCM сигнал алмасуды, ал WebRTC медианы қорғайды. Шабуылдаушы құрылғылар не ата-аналар байқамайтындай бұл тізбекті бірнеше жерден бұзуы керек болар еді.