11.13. Koppelen en binden¶
Alles wat tot nu toe is besproken verstuurt bytes onversleuteld via de radio. Iedereen met een BLE-geschikte laptop in dezelfde ruimte kan meeluisteren op de advertentiekanalen, de hopping-volgorde van een open verbinding volgen en elke lees-, schrijf- en notificatieactie die voorbijkomt uitlezen. Voor de meeste publieke sensorgegevens (batterijniveau, omgevingstemperatuur) is dat prima. Voor alles wat de twee eindpunten privé willen houden – een controleregister dat een relais activeert, een wachtwoord, een meting die niet breed verspreid mag worden – moet de verbinding versleuteld zijn, en idealiter moet de camera weten met wie hij praat.
BLE biedt beide via pairing en bonding.
11.13.1. Koppelen, binden, versleuteling¶
Drie nauw verwante begrippen:
Versleuteling is het uiteindelijke doel. Zodra de verbinding versleuteld is, is elk pakket op de datakanalen alleen ontcijferbaar door de twee eindpunten; een afluisteraar ziet ruis.
Pairing is de procedure die de twee eindpunten uitvoeren om de sleutels overeen te komen die de versleuteling gebruikt. Het is een eenmalige uitwisseling die gedeeld sleutelmateriaal oplevert dat de linklaag in zijn versleutelingsengine inplugt.
Bonding is de keuze om de sleutels na het pairen op te slaan in niet-vluchtig geheugen, zodat de volgende verbinding tussen dezelfde twee apparaten het pairen overslaat en direct naar versleuteling gaat.
In gewone taal: pairing is “stel jezelf voor”; bonding is “onthoud deze kennismaking”; versleuteling is “praat vanaf nu in het geheim”.
De pairing-stroom bovenop een open BLE-verbinding. Zodra de sleuteluitwisseling is voltooid, versleutelt de linklaag elk volgend pakket. Bonding is de extra stap waarbij de sleutels naar het flashgeheugen worden geschreven.¶
11.13.2. LE Secure Connections¶
De moderne sleuteluitwisseling die door BLE wordt gebruikt is LE Secure Connections, gebouwd op Elliptic Curve Diffie-Hellman. Beide kanten genereren een tijdelijk sleutelpaar, wisselen de publieke helften uit en combineren het resultaat met hun eigen privésleutels om bij hetzelfde gedeelde geheim uit te komen – een geheim dat een afluisteraar niet kan berekenen, zelfs niet met een volledig verslag van de uitwisseling.
De oudere LE Legacy-methode is minder veilig (een afluisteraar met de volledige uitwisseling kan de sleutel meestal achterhalen) en bestaat alleen voor achterwaartse compatibiliteit met oude randapparaten. De standaardinstelling van aioble is de moderne methode (le_secure=True); laat die staan.
11.13.3. Pairing initiëren¶
Een central pairt door aioble.DeviceConnection.pair() aan te roepen op een reeds open verbinding:
async with await device.connect() as connection:
await connection.pair(bond=True, le_secure=True, mitm=False)
# ... GATT work, now over an encrypted link ...
Nadat pair terugkeert, weerspiegelen de attributen encrypted, authenticated, bonded en key_size op de verbinding wat er onderhandeld is.
De vier nuttigste trefwoordargumenten:
bond=True– sla de resulterende sleutels op in het flashgeheugen zodat de volgende verbinding tussen dezelfde twee apparaten de pairing-handshake overslaat. StandaardTrue.le_secure=True– gebruik LE Secure Connections. StandaardTrue. Laat het aan staan.mitm=False– of man-in-the-middle-bescherming vereist moet worden. Dit vereist een out-of-band-kanaal (een numerieke code die aan de ene kant wordt weergegeven en aan de andere kant wordt bevestigd, een ingetypte toegangscode, …) zodat de gebruiker kan verifiëren dat de twee apparaten in de pairing-handshake daadwerkelijk degene zijn die hij denkt. StandaardFalse(geen MITM-bescherming – een passieve afluisteraar kan de verbinding niet lezen, maar een aanvaller die actief verbindingen omleidt zou zichzelf kunnen inkoppelen). Zet opTruevoor alles wat gevoelig is, maar besef dat dit vereist dat het randapparaat daadwerkelijk een IO-capaciteit ondersteunt.io=3– de IO-capaciteit die het apparaat claimt. De Bluetooth-specificatie definieert er vijf:0alleen weergave,1weergave + ja/nee,2alleen toetsenbord,3geen invoer geen uitvoer,4toetsenbord + weergave. Een camera zonder UI rapporteert doorgaans3; als de camera zelf een display heeft, kan de applicatie de numerieke bevestiging tonen en1gebruiken. De combinatie van de IO-capaciteiten van beide kanten bepaalt of echte MITM-bescherming haalbaar is.
Randapparaten roepen pair niet zelf aan – ze reageren op wat de central ook initieert. Of versleuteling vereist is voor een bepaalde characteristic is een eigenschap van hoe deze in de GATT-database is gedeclareerd; toegangsbits die versleuteling vereisen maken deel uit van de low-level bluetooth-API en worden momenteel niet blootgesteld via de characteristic-constructor van aioble.
11.13.4. Bonding – en waar de sleutels leven¶
Wanneer bond=True, schrijft aioble de sleutels naar een JSON-bestand op het lokale bestandssysteem. De standaardbestandsnaam is ble_secrets.json, geschreven relatief aan de huidige werkmap. Op een net opgestarte camera heeft _boot.py die map al gekozen: /sdcard wanneer een kaart is gemount, anders /flash – dus het bestand belandt op /sdcard/ble_secrets.json of /flash/ble_secrets.json. Het bestand bevat de gegevens die nodig zijn om de verbinding opnieuw te versleutelen wanneer de gebonden peer de volgende keer opnieuw verbindt, inclusief het identiteitsadres van de peer.
Eén asymmetrie om in gedachten te houden: het opslaan gebeurt automatisch naarmate sleutels veranderen, maar het laden van het bestand bij de volgende opstart niet. Roep aioble.security.load_secrets() één keer aan bij het opstarten (vóór elke pairing of advertentie) zodat eerder gebonden peers worden herkend:
import aioble
aioble.security.load_secrets() # default path: ble_secrets.json
Daarna, de volgende keer dat een gebonden peer opduikt, hergebruikt aioble de opgeslagen sleutels en gaat de verbinding versleuteld zonder verdere handshake.
Twee praktische gevolgen van het opslaan van sleutels in het flashgeheugen:
Een apparaat vergeten. Verwijder
ble_secrets.json(of verwijder de relevante invoer) om alle gebonden peers te vergeten, en pair daarna opnieuw vanaf nul.Fysieke toegang lekt sleutels. Iedereen met toegang tot het bestandssysteem van de camera kan de JSON lezen. Dit is hetzelfde soort beperking dat aan de netwerkkant naar voren kwam bij TLS-sleutels (Operaties: sleutels, verloop en probleemoplossing): gebruik sleutels per apparaat, behandel elke opgeslagen sleutel als achterhaalbaar, en vertrouw op de mogelijkheid om in te trekken (hier het verwijderen van de bond aan de central-kant) in plaats van erop dat de sleutel geheim blijft.
11.13.5. Wat versleuteling garandeert – en wat niet¶
Een pair-dan-versleutel-verbinding biedt, in volgorde van sterkte:
Vertrouwelijkheid. Altijd. Een afluisteraar kan de bytes niet lezen.
Integriteit. Altijd. Gewijzigde pakketten falen de authenticated-encryption-controle van de linklaag en worden verworpen.
Authenticatie. Alleen met
mitm=Trueen een capabele IO. Zonder die kan een man-in-the-middle die de oorspronkelijke pairing-uitwisseling onderschepte zichzelf hebben ingevoegd; zonder MITM-bescherming is er voor de twee kanten geen manier om dat te weten.
Voor de meeste cameragebruiksgevallen – een telefoon die één keer met de camera pairt en later opnieuw verbindt – is mitm=False doorgaans voldoende, omdat de oorspronkelijke pairing plaatsvindt in een gecontroleerde omgeving (de gebruiker houdt beide apparaten in dezelfde ruimte). Voor toepassingen waarbij een gepaird apparaat de camera mogelijk voor het eerst over een lange afstand of via een onvertrouwde tussenpersoon tegenkomt, is MITM de juiste instelling.
11.13.6. Wanneer pairing het verkeerde antwoord is¶
Pairing heeft een reële kostenpost: een paar seconden uitwisseling bij de eerste verbinding, permanent flashgebruik voor elk gebonden apparaat, en het herstelverhaal van “vergeet de bond” als er iets misgaat. Voor werkelijk publieke gegevens – omgevingssensormetingen die als baken worden gepubliceerd, een bord dat zijn naam toont, alles wat de wereld niet verandert door gelezen of geschreven te worden – is het juiste antwoord niet om überhaupt te versleutelen, en laat elke nabije scanner de waarden lezen.
Voor al het andere is connection.pair(bond=True) op de central de toevoeging van één regel die de verbinding verandert van een publiek kanaal in een privékanaal.