Blog

Baby Monitor Timmy'de Güvenli Eşleştirme

ECDH, SAS numarası ve şifreli sinyalleşmenin birlikte nasıl çalıştığı.

Baby Monitor Timmy ses ve görüntü iletmeye başlamadan önce iki cihazın birbirini bulması ve birbirine güvenmesi gerekir. Bu eşleştirme adımı, tüm sürecin en kritik anıdır. Burada Timmy'nin nasıl eşleştiğini, bunun arkasındaki kriptografiyi ve yakındaki bir saldırganın bağlantıyı fark edilmeden neden ele geçiremeyeceğini açıklıyorum.

Sorun: Cihazım kiminle konuştuğunu nasıl biliyor?

İki cihaz ilk kez bağlandığında temel soru şudur: A Cihazı gerçekten B Cihazıyla mı konuşuyor, yoksa araya biri mi giriyor? Kriptografide buna ortadaki adam saldırısı (MITM) denir.

Timmy bunu, Firebase üzerinden Eliptik Eğri Diffie-Hellman (ECDH) anahtar değişimi ve kullanıcının görsel doğrulamasını.

bir araya getirerek çözer. Aşağıdaki diyagram, eşleştirme akışının tamamını bir bakışta gösterir:

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
      

Eşleştirme protokolünün tam sırası — düzenlenebilir kaynak: docs/diagrams/pairing-sequence.mmd

1. Adım: Her cihaz bir anahtar çifti oluşturur

Eşleştirme ekranı açıldığında, her cihaz geçici bir ECDH anahtar çifti oluşturur; bu anahtar çifti P-256 eğrisindedir (secp256r1):

Anahtarlar, kriptografik olarak güvenli bir rastgele sayı üreteciyle (Random.secure()) oluşturulur ve yalnızca bu tek eşleştirme denemesi için geçerlidir. Her yeni deneme için yeni anahtarlar oluşturulur.

2. Adım: Açık anahtarların Firebase üzerinden paylaşılması

Timmy, iki cihazın birbirini bulmasını sağlamak için buluşma noktası olarak 4 karakterli bir kod kullanır. Bu kod Nearby Connections (Bluetooth Low Energy) aracılığıyla otomatik bulunabilir veya elle girilebilir. Kodun kriptografik bir değeri yoktur; yalnızca iki cihazın aynı Firebase Firestore belgesini bulmasını sağlar.

Her iki cihaz da kodu öğrendiğinde, her biri açık ECDH anahtarını ortak bir Firestore belgesineyazar. Ardından her cihaz, diğer cihazın açık anahtarını bu belgeden okur.

Önemli nokta: yalnızca açık anahtar gönderilir. Özel anahtar cihazdan asla ayrılmaz. Firebase trafiğini izleyen biri açık anahtarları görür, ancak bunlardan ortak gizli değeri hesaplayamaz . Bu, Eliptik Eğri Ayrık Logaritma Problemi'nin (ECDLP) zorluğuna dayanır.

3. Adım: Ortak gizli değerin hesaplanması

Her iki cihaz da birbirinin açık anahtarını edindiğinde, birbirinden bağımsız olarak aynı ortak gizli değeri hesaplar.:

sharedSecret = ECDH(myPrivateKey, remotePublicKey)
             → 32 bytes (identical on both devices)

Eliptik eğri matematiği, her cihaz yalnızca kendi özel anahtarını ve diğer cihazın açık anahtarını bilmesine rağmen iki hesaplamanın da aynı sonucu vermesini garanti eder.

4. Adım: Doğrulama numarası (SAS)

Paylaşılan gizden bir Kısa Kimlik Doğrulama Dizisi (SAS) türetilir — her iki cihazda da gösterilen iki basamaklı bir sayı:

hash   = SHA-256("sas:" + sort(pubkeyA, pubkeyB) + sharedSecret)
number = (hash[0] × 256 + hash[1]) mod 100   → 00 to 99

Her iki cihaz da aynı sayıyı gösterir — örneğin, 42. Kullanıcı, her iki ekrandaki sayıların eşleşip eşleşmediğini görsel olarak karşılaştırır ve ardından her cihazda ayrı ayrı onaylar.

Bir saldırgan bunu neden taklit edemez

Ortadaki adam saldırganının Firebase'teki anahtar değişimini ele geçirmesi gerekir. Bunun için şunları yapması gerekir:

  1. Firestore belgesinde saklanan gerçek açık anahtarları kendi açık anahtarlarıyla değiştirmek
  2. Her cihazla ayrı paylaşılan gizler oluşturmak
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 uyuşmazlığıyla ortadaki adam saldırısının tespiti — düzenlenebilir kaynak: docs/diagrams/mitm-detection.mmd

Bu durumda saldırgan, S_A A Cihazıyla bir ortak gizli değer, B Cihazıyla ise farklı bir ortak gizli değer S_B hesaplar. Çünkü S_A ≠ S_B, cihazlar farklı doğrulama numaraları hesaplar..

Saldırgan sayıların eşleşmesini sağlayamaz, çünkü:

Kullanıcı ekranlarda farklı sayılar görür ve eşleştirmeyi iptal eder. Bu noktada saldırı görünür hâle gelmiştir.

Adım 5: Eşleştirmenin tamamlanması

Yalnızca kullanıcı her iki cihazda doğrulamayı onayladıktan sonra eşleştirme tamamlanır:

  1. Bir 64 karakterlik eşleştirme anahtarı (256 bit) paylaşılan gizden türetilir: SHA-256("pair:" + sharedSecret) → pairingKey
  2. Belge anahtarı SHA-256("doc:" + pairingKey) olarak türetilir ve Firestore belge anahtarı olarak kullanılır
  3. Şifreleme anahtarı SHA-256("enc:" + pairingKey) olarak türetilir ve şifrelenmiş sinyalleşme için AES-256-GCM anahtarını sağlar
  4. Her iki cihaz aynı eşleştirme anahtarını saklar ve mod seçimine geçer

Bu noktadan itibaren tüm bağlantı denemeleri (Firestore sinyalleşmesi, WebRTC kurulumu) paylaşılan AES-256-GCM anahtarıyla şifrelenir. Eşleştirme anahtarı asla arka uca gönderilmez; yalnızca SHA-256 özeti belge tanımlayıcısı olarak kullanılır.

Sistem mimarisi

Aşağıdaki diyagram, eşleştirme ve iletişimde yer alan bileşenleri gösterir:

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

Sistem mimarisine genel bakış — düzenlenebilir kaynak: docs/diagrams/pairing-architecture.mmd

İletişim yollarının ayrıntıları:

Alternatif: Kodu elle girme

Bluetooth kullanılamıyorsa (örneğin eski cihazlarda), 4 karakterli kod elle de girilebilir. Elle girişte aynı ECDH anahtar değişimi ve aynı SAS doğrulaması otomatik eşleştirmedeki gibi kullanılır. Tek fark, kodun BLE ile bulunması yerine kullanıcı tarafından okunup yazılmasıdır.

Her iki durumda da ECDH anahtar değişimi Firebase üzerinden gerçekleştiği için güvenlik aynıdır. 4 karakterli kod yalnızca bir buluşma noktasıdır; asıl şifreleme ECDH'den türetilen 256 bitlik anahtara dayanır.

Özet

Güvenlik mekanizması Koruduğu tehdit
ECDH anahtar değişimi (P-256) Anahtar değişimi trafiğinin dinlenmesi
Geçici anahtar çiftleri İleriye dönük gizlilik — geçmiş eşleştirmeler güvende kalır
Görsel doğrulama numarası (SAS) Anahtar değişimi sırasında ortadaki adam saldırısı (MITM)
Belge anahtarı olarak SHA-256 özeti Firestore'dan kod çıkarılması
AES-256-GCM şifrelemesi Sinyalleşme verilerinin dinlenmesi
İki taraflı onay Kullanıcı bilgisi olmadan tek taraflı eşleştirme
DTLS-SRTP (WebRTC) Ses/video dinleme

Bu katmanlar birlikte çalışır: ECDH anahtar değişimini, doğrulama numarası MITM saldırılarını, AES-256-GCM sinyalleşmeyi ve WebRTC medyayı korur. Bir saldırganın, cihazlar veya ebeveynler fark etmeden bu zinciri birkaç noktada kırması gerekir.


Diğer makaleler