Bloga dön
Security10 min read

Eşleştirme Akışı

Bu makale, iki PlainApp cihazının ilk kez nasıl güven oluşturduğunu — birbirlerini nasıl keşfettiklerini, anahtarları nasıl değiştirdiklerini ve sonrasında her sohbet mesajının, dosya transferinin ve varlık pinginin şifrelendiği paylaşılan ChaCha20 taşıma anahtarına nasıl ulaştıklarını açıklamaktadır. Bu anahtarı kullanan sohbet ve kanal mimarisi, ayrı Sohbet Mimarisi makalesinde ele alınmaktadır.

İçindekiler

Eşleştirme Neden Var {#why-pairing-exists}

PlainApp'in merkezi bir hesap sunucusu yoktur. Bu nedenle cihazlar, birbirleriyle konuşmadan önce iki soruyu yanıtlamalıdır:

  1. "Kimsin?" — Her cihaz, ilk açılışta sabit bir clientId oluşturur (Ed25519 anahtar materyalinden türetilmiş 13 karakterlik bir kimlik). Bu, yönlendirme, varlık ve kanal üyeliği için kullanılan tek tanımlayıcıdır.
  2. "Sana güvenebilir miyim?" — Bir sunucunun kimliği garanti etmediği durumlarda, bir eşin iddia ettiği kişi olduğundan emin olmanın tek yolu, bir insanın eşleştirmeyi her iki cihazda da onaylaması ve protokolün kriptografik imzaları doğrulamasıdır.

Eşleştirme tek bir yapıt üretir: veritabanında status="paired", bir ChaCha20 key (paylaşılan taşıma sırrı) ve eşin Ed25519 public_key (gelecekteki mesaj imzalarını doğrulamak için) ile bir DPeer satırı. Sohbet alt sistemindeki sonraki her protokol, bu iki alanın varlığını varsayar.

Diagram 1
1

Güven Modeli ve Kriptografi {#trust-model--cryptography}

Eşleştirme, iki bağımsız kriptografik ilkel kullanır:

İlkelAmaçYaşam Döngüsü
Ed25519 (imza)Eşleştirme isteğini ve yanıtını doğrulamak. «Bu gerçekten gönderdiğini iddia eden cihazdan geldi» doğrular ve tekrar saldırılarını önlemek için zaman damgasını bağlar.İmzalama anahtarı, cihazın uzun vadeli kimlik anahtarıdır. Açık yarısı DPeer.public_key olarak saklanır ve daha sonra her sohbet mesajı imzasını doğrulamak için PeerChatParser.decrypt tarafından kullanılır.
X25519 tarzı ECDH (anahtar anlaşması)ChaCha20 taşıma anahtarı haline gelen paylaşılan bir sır üretmek. İki cihaz, sırrı hiçbir zaman iletmeden aynı sırrı hesaplar.Eşleştirme oturumu başına kısa ömürlü anahtar çifti üretilir, paylaşılan anahtar hesaplandıktan hemen sonra atılır. Elde edilen 32 baytlık sır DPeer.key olarak saklanır ve eşleştirmenin ömrü boyunca yeniden kullanılır.

PIN, QR kodu, bant dışı kod yoktur. Güven şu şekilde kurulur:

  1. Bir insanın yanıtlayıcı cihazda Kabul'e dokunması (kullanıcı «evet, bu benim eşleştirmek istediğim cihaz» iddia ediyor).
  2. Her iki tarafın istek/yanıt üzerinde diğerinin Ed25519 imzasını doğrulaması (yanıtlayıcının oturumu başlatan cihazla konuştuğunu ve tersini kanıtlar).
  3. Her iki mesajda ±5 dakikalık zaman damgası penceresi (yakalanmış eski bir el sıkışmanın tekrarını önler).

Bu asimetri önemlidir: Tek bir insan onayı, ortadaki adam saldırısına karşı savunmasız olur (saldırgan her iki tarafla ayrı ayrı eşleşebilir). ECDH ortak anahtarı üzerindeki Ed25519 imzası bunu önler — yanıtlayıcı, isteğin oturumu başlatan aynı Ed25519 anahtarı tarafından imzalandığını doğrular ve tersi, böylece bir MITM, uzun vadeli imzalama anahtarını da kontrol etmeden kendi ECDH anahtarını şeffaf bir şekilde değiştiremez.

Bileşen Haritası {#component-map}

Tüm eşleştirme kodu discover/ paketinde bulunur (chat/peer/pair/ değil):

Diagram 2
2

Dosya konumları

BileşenYol (shared/src/commonMain/kotlin/com/ismartcoding/plain/ altında)
LANDiscoverManagerdiscover/LANDiscoverManager.kt
PairingCorediscover/PairingCore.kt
PairingInitiatordiscover/PairingInitiator.kt
PairingResponderdiscover/PairingResponder.kt
PairingSecuritydiscover/PairingSecurity.kt
PairingSessionStorediscover/PairingSessionStore.kt
PairingPeerStorediscover/PairingPeerStore.kt
PairingMessengerdiscover/PairingMessenger.kt

Keşif Aşaması {#discovery-phase}

Eşleştirme gerçekleşmeden önce cihazlar birbirlerini bulmalıdır. LANDiscoverManager, uygulama başladığında sürekli çalışır:

Diagram 3
3

Yönlendirilmiş keşif neden şifrelidir

Yayın DISCOVER'ı hassas bir şey ortaya çıkarmaz (sadece fromId=clientId), bu nedenle LAN'daki herhangi bir cihazın bunu görmesi sorun değildir. Ancak yönlendirilmiş varyant, bir cihaz zaten başka bir cihazın clientId'sini bildiğinde (örneğin eşleştirilmiş ama eşin IP'si değişti) ve onu uyandırmak istediğinde kullanılır. Hedef clientId'yi eşin paylaşılan anahtarıyla şifrelemek şu anlama gelir:

  • Doğru eş toId'nin şifresini çözebilir, kendini tanır ve yanıt verebilir.
  • LAN'daki diğer tüm cihazlar yalnızca şifreli metni görür — gönderenin hangi clientId'lere ulaşmaya çalıştığını sayamazlar.

Bu küçük ama gerçek bir gizlilik özelliğidir: Pasif LAN gözlemcileri, kimin kiminle eşleştirildiğinin grafiğini çıkaramaz.

Yanıttaki Aware bayrakları

DISCOVER_REPLY, awareSupported ve awareRunning taşır. Bunlar veritabanına kalıcı olarak kaydedilmezPeerCacher'da bellekte saklanır ve her yanıtta (ve BLE tarama-yanıtı serviceData'sından) yenilenir. Taşıma katmanı, bir Wi-Fi Aware bağlantısı denemeye mi yoksa doğrudan BLE'ye mi geçmeye karar verirken bunlara danışır.

Eşleştirme Sırası (Mutlu Yol) {#pairing-sequence-happy-path}

Her iki cihaz da aynı LAN'da olduğunda ve kullanıcı eşleştirmeyi kabul ettiğinde uçtan uca akış:

Diagram 4
4

Neden her iki taraf da eşi bağımsız olarak saklar

Başlatıcının (adım 9) ve yanıtlayıcının (adım 7) diğer cihaz için PairingPeerStore.save(...) çağırdığına dikkat edin. Bu kasıtlıdır: Her cihaz, diğerinin clientId'siyle anahtarlanan, kendi paylaşılan ChaCha20 anahtarı kopyasını ve diğerinin Ed25519 ortak anahtarını içeren bir DPeer satırıyla sonuçlanır. Merkezi bir kayıt yoktur — eşleştirme simetrik ve kendi kendine yetendir.

Yanıtlayıcı neden anahtarı önce hesaplar

Yanıtlayıcının acceptPairingRequest'i, kabul anında paylaşılan anahtarı hemen hesaplar ve kalıcı hale getirir. Bu, yanıtlayıcının yanıt başlatıcıya ulaşmadan önce şifreli trafiği almaya başlayabileceği anlamına gelir. Yanıt yolda kaybolursa, yanıtlayıcı hala eşleştirilmiştir — yalnızca başlatıcının yeniden denemesi gerekir.

Anahtar Değişimi Detayları {#key-exchange-details}

Eşleştirmenin kriptografik çekirdeği, standart bir X25519 tarzı ECDH anahtar anlaşmasıdır, ancak bunu doğrulamak için üzerine bir Ed25519 imzası eklenmiştir.

Diagram 5
5

İmza gerçekte neyi korur

İmzalı yük (toSignatureData()), sabit istek alanlarının kurallı bir birleştirmesidir: fromId, fromName, port, deviceType, ecdhPublicKey, signaturePublicKey, timestamp ve ips. ecdhPublicKey'i uzun vadeli signaturePublicKey ile birlikte imzalayarak, protokol kısa ömürlü anahtarı cihazın kimliğine bağlar. Bir saldırgan, imzayı geçersiz kılmadan kendi ECDH ortak anahtarını yolda değiştiremez — ve uzun vadeli Ed25519 anahtarını kontrol etmeden imzayı da üretemez.

Bu, ortadaki adamı yenen şeydir: Saldırgan iki cihaz arasındaki her paketi aktarsa bile, şifreli trafiği okuyamaz (çünkü hiçbir tarafın ECDH özel anahtarına sahip değildir) ve kendi ECDH anahtarlarını değiştiremez (çünkü imzalar bozulur).

Yanıtlayıcı Kabul/Red Akışı {#responder-acceptdecline-flow}

Yanıtlayıcı tarafı, bir PAIR_REQUEST geldiğinde bir UI iletişim kutusu gösterir. Kullanıcı kabul edebilir veya reddedebilir.

Diagram 6
6

Yanıtlayıcı neden kabul sırasında PairingSuccessEvent'i hemen tetikler

Yanıtlayıcının acceptPairingRequest'i PairingPeerStore.save(...) çağırır ve yanıtı göndermeden önce PairingSuccessEvent'i tetikler. Bu kasıtlıdır: Yanıt hiçbir zaman başlatıcıya ulaşmazsa (ağ sorunu), yanıtlayıcı hala eşleştirilmiştir — başlatıcı bir dahaki sefere eşleştirmeyi denediğinde, yanıtlayıcının zaten var olan DPeer satırı varlık sistemi tarafından alınır. Başlatıcı basitçe yeniden dener; yanıtlayıcının yeniden onaylaması gerekmez.

İptal Akışı {#cancel-flow}

Her iki taraf da devam eden bir eşleştirmeyi iptal edebilir.

Diagram 7
7

DPairingCancel'in yalnızca LAN tek noktaya yayın üzerinden gönderildiğine dikkat edin (başlatıcı zaten keşif aşamasından yanıtlayıcının IP'sine sahiptir), oysa red yanıtı hem LAN hem de BLE üzerinden gönderilir çünkü yanıtlayıcı, başlatıcının hangi taşıma üzerinde ulaşılabilir olduğundan emin olamaz.

Çift Kanal Teslimi (LAN + BLE) {#dual-channel-delivery-lan--ble}

Yanıtlayıcı DPairingResponse'u gönderdiğinde, bunu aynı anda hem LAN hem de BLE üzerinden yapar. Başlatıcı ilk kopyayı kabul eder ve kopyayı sessizce atar.

Diagram 8
8

BlePairingSessionStore neden var

Bir PAIR_REQUEST BLE üzerinden geldiğinde, yanıtlayıcının başlatıcı için bir LAN IP'si yoktur — yalnızca BLE MAC adresi vardır. BlePairingSessionStore, peerId → MAC eşlemesini yapar, böylece gerektiğinde yanıt BLE üzerinden geri yönlendirilebilir. Bu, yalnızca BLE yönlendirmeli istekler için doldurulan ve yanıt gönderildikten sonra temizlenen küçük, bellekte, kısa ömürlü bir eşlemdir.

Oturum ve Eş Depolama {#session--peer-storage}

Eşleştirmede iki depo yer alır, çok farklı yaşam süreleriyle:

Diagram 9
9

clientId neden tek kalıcı tanımlayıcıdır

Android, BLE MAC adresini her bağlantıda rastgeleleştirir, bu nedenle saklamak işe yaramaz. clientId, cihazın uzun vadeli Ed25519 anahtar materyalinden türetilir, bu nedenle:

  • Kararlı — uygulama yeniden yüklemelerinde (anahtar platform keystore'undadır).
  • Kendi kendini doğrulayan — bir clientId iddia eden herkes, ilgili Ed25519 özel anahtarına sahip olduğunu kanıtlamalıdır (her imzalı mesajda doğrulanır).
  • Gizliliği koruyan — BLE üzerinden keşif için yalnızca 8 baytlık bir SHA-256 öneki (shortId) yayınlanır; tam clientId yalnızca gerçekten eşleştirdiğiniz cihazlara açıklanır.

Güvenlik Özellikleri {#security-properties}

ÖzellikNasıl sağlanır
GizlilikTüm taşıma, ECDH'den türetilen paylaşılan anahtarla ChaCha20 ile şifrelenir. Anahtar, eşleştirmeden sonra iki cihazdan asla ayrılmaz.
Kimlik DoğrulamaHer imzalı mesaj (eşleştirme isteği/yanıtı, sohbet createChatItem, kanal invite/update/kick), gönderenin saklanan public_key'ine karşı Ed25519 ile doğrulanır.
BütünlükEd25519 imzaları tam istek gövdesini kapsar; herhangi bir değişiklik imzayı geçersiz kılar.
Tekrar direnci±5 dakika zaman damgası penceresi (PeerChatParser ve PairingSecurity tarafından uygulanır). ChatMessageReceiver.seenSignatures pencere içinde yinelenenleri kaldırır.
Ortadaki adam direnciKısa ömürlü ECDH ortak anahtarı, uzun vadeli Ed25519 ortak anahtarıyla birlikte imzalanır. Bir MITM, imzayı bozmadan kendi ECDH anahtarını değiştiremez.
İleri gizlilik (sınırlı)ECDH anahtar çiftleri, eşleştirme oturumu başına kısa ömürlüdür. Uzun vadeli Ed25519 anahtarının sonradan tehlikeye girmesi, geçmiş trafiğin şifresini çözemez (paylaşılan anahtar da hala gereklidir — ancak hem ECDH özel anahtarları hem de saklanan DPeer.key silinirse, geçmiş yakalamaların şifresi çözülemez).
Hizmet reddi direncionDatagram, her mesajı try/catch ile sarar, böylece bozuk bir paket keşif alıcısını öldüremez. PeerCircuitBreaker, 2 başarısızlıktan sonra 30 s süreyle güvenilmez bir taşımayı atlar.
Gizlilik (yönlendirilmiş keşif)LANDiscoverManager.discoverSpecificDevice, hedef clientId'yi eşin anahtarıyla şifreler — pasif LAN gözlemcileri kimin kiminle eşleştirildiğini sayamaz.
Kimlik kararlılığıclientId, platform keystore'undaki uzun vadeli Ed25519 anahtar materyalinden türetilir — yeniden yüklemelerde kararlı, kendi kendini doğrulayan ve bir telefon numarasına veya e-postaya bağlı olmayan.

Eşleştirmenin savunmadığı şeyler

  • Fiziksel cihaz tehlikesi. Bir saldırgan eşleştirilmiş bir cihazda root elde ederse, paylaşılan anahtarı veritabanından okuyabilir ve o eşi taklit edebilir. Paylaşılan taşıma anahtarı için donanım destekli anahtar deposu zorunluluğu yoktur (yalnızca Ed25519 imzalama anahtarı için, SignatureHelper aracılığıyla).
  • Aktif aktarma saldırıları. Kendileriyle eşleştiklerini düşünen iki cihaz arasında BLE ve LAN trafiğini aynı anda aktarabilen bir saldırgan, teorik olarak araya yerleşebilir — ancak ECDH ortak anahtarı üzerindeki Ed25519 imzası, trafiği okuyamayacakları, yalnızca aktarabilecekleri anlamına gelir. Bu, sayısal karşılaştırma olmadan Bluetooth eşleştirmeyle aynı takastır.
  • Ağ düzeyinde engelleme. Bir güvenlik duvarı UDP çoklu yayını engelleyebilir, BLE sıkıştırılabilir ve Wi-Fi Aware kullanılamayabilir. Sistem zarif bir şekilde düşer (BLE, eşleştirilmiş eşler için garanti edilen yedektir) ancak aktif olarak düşmanca bir ağı atlayamaz.

Durum Makinesi Özeti {#state-machine-recap}

Diagram 10
10

Daha Fazla Okuma

  • Sohbet Mimarisi — paylaşılan anahtarın ne için kullanıldığı: eş sohbeti gönderme/alma, kanal dağıtımı, varlık, dosya indirmeleri.
  • apitest/groups/discovery.sh — keşif ve eşleştirme API yüzeyini uçtan uca çalıştıran yürütülebilir test planı.