11.13. Pairing e bonding¶
Tutto quanto trattato fino a qui sposta byte via radio in chiaro. Chiunque disponga di un laptop con supporto BLE nella stessa stanza puo ascoltare sui canali di advertising, seguire la sequenza di hopping di una connessione aperta e leggere ogni lettura, scrittura e notifica che vi transita. Per la maggior parte dei dati pubblici dei sensori (livello della batteria, temperatura ambiente) questo va bene. Per qualunque cosa i due endpoint vogliano mantenere privata – un registro di controllo che arma un rele, una password, una misura che non dovrebbe essere trasmessa a tutti – il collegamento deve essere cifrato e, idealmente, la camera deve sapere con chi sta parlando.
BLE fornisce entrambe le cose attraverso il pairing e il bonding.
11.13.1. Pairing, bonding, cifratura¶
Tre concetti strettamente correlati:
La cifratura e l’obiettivo finale. Una volta che il collegamento e cifrato, ogni pacchetto sui canali dati e decifrabile solo dai due endpoint; un intercettatore vede solo rumore.
Il pairing e la procedura che i due endpoint eseguono per concordare le chiavi usate dalla cifratura. E uno scambio una tantum che produce materiale di chiave condiviso che il link layer collega al proprio motore di cifratura.
Il bonding e la scelta di persistere le chiavi in una memoria non volatile dopo che il pairing e terminato, in modo che la connessione successiva tra gli stessi due dispositivi salti il pairing e passi direttamente alla cifratura.
In parole povere: il pairing e «presentarsi»; il bonding e «ricordarsi questa presentazione»; la cifratura e «parlare in privato d’ora in poi».
Il flusso di pairing sopra una connessione BLE aperta. Una volta completato lo scambio di chiavi, il link layer cifra ogni pacchetto successivo. Il bonding e il passo aggiuntivo di scrivere le chiavi sulla flash.¶
11.13.2. LE Secure Connections¶
Lo scambio di chiavi moderno usato da BLE e LE Secure Connections, basato su Elliptic Curve Diffie-Hellman. Entrambe le parti generano una coppia di chiavi temporanea, si scambiano le meta pubbliche e combinano il risultato con le proprie chiavi private per arrivare allo stesso segreto condiviso – un segreto che un intercettatore non puo calcolare nemmeno con una registrazione completa dello scambio.
Il metodo piu vecchio LE Legacy e meno sicuro (un intercettatore con lo scambio completo puo di solito recuperare la chiave) ed esiste solo per retrocompatibilita con vecchie periferiche. L’impostazione predefinita di aioble e il metodo moderno (le_secure=True); mantienila.
11.13.3. Avvio del pairing¶
Un central avvia il pairing chiamando aioble.DeviceConnection.pair() su una connessione gia aperta:
async with await device.connect() as connection:
await connection.pair(bond=True, le_secure=True, mitm=False)
# ... GATT work, now over an encrypted link ...
Dopo che pair ritorna, gli attributi encrypted, authenticated, bonded e key_size sulla connessione riflettono cio che e stato negoziato.
I quattro argomenti keyword piu utili:
bond=True– salva le chiavi risultanti sulla flash in modo che la connessione successiva tra gli stessi due dispositivi salti l’handshake di pairing. PredefinitoTrue.le_secure=True– usa LE Secure Connections. PredefinitoTrue. Lascialo attivo.mitm=False– se richiedere la protezione man-in-the-middle. Questo necessita di un canale fuori banda (un codice numerico visualizzato su un lato e confermato sull’altro, una passkey digitata, …) cosi che l’utente possa verificare che i due dispositivi nell’handshake di pairing siano effettivamente quelli che pensa. Il valore predefinito eFalse(nessuna protezione MITM – un intercettatore passivo non puo leggere il collegamento, ma un attaccante che reindirizza attivamente le connessioni potrebbe inserirsi nel pairing). Impostalo aTrueper qualunque cosa sensibile, ma tieni presente che richiede che la periferica supporti effettivamente una capacita di IO.io=3– la capacita di IO che il dispositivo dichiara. La specifica Bluetooth ne definisce cinque:0solo display,1display + si/no,2solo tastiera,3nessun input nessun output,4tastiera + display. Una camera senza interfaccia utente tipicamente riporta3; se la camera stessa ha un display, l’applicazione potrebbe mostrare la conferma numerica e usare1. La combinazione delle capacita di IO dei due lati decide se sia ottenibile una vera protezione MITM.
Le periferiche non chiamano pair da sole – rispondono a qualunque cosa il central avvii. Se la cifratura sia richiesta per una data caratteristica e una proprieta di come essa viene dichiarata nel database GATT; i bit di accesso che richiedono la cifratura fanno parte dell’API di basso livello bluetooth e attualmente non sono esposti tramite il costruttore di caratteristiche di aioble.
11.13.4. Bonding – e dove risiedono le chiavi¶
Quando bond=True, aioble scrive le chiavi in un file JSON sul filesystem locale. Il nome file predefinito e ble_secrets.json, scritto relativamente alla directory di lavoro corrente. Su una cam appena avviata _boot.py ha gia scelto quella directory: /sdcard quando una scheda e montata, /flash altrimenti – quindi il file finisce in /sdcard/ble_secrets.json o /flash/ble_secrets.json. Il file contiene le voci necessarie per cifrare nuovamente il collegamento la prossima volta che il peer in bonding si riconnette, incluso l’indirizzo identita del peer.
Un’asimmetria da tenere a mente: il salvataggio avviene automaticamente man mano che le chiavi cambiano, ma il caricamento del file al boot successivo no. Chiama aioble.security.load_secrets() una volta all’avvio (prima di qualunque pairing o advertising) cosi che i peer precedentemente in bonding vengano riconosciuti:
import aioble
aioble.security.load_secrets() # default path: ble_secrets.json
Dopodiche, la volta successiva che un peer in bonding si presenta, aioble riutilizza le chiavi memorizzate e il collegamento diventa cifrato senza ulteriore handshake.
Due conseguenze pratiche della memorizzazione delle chiavi sulla flash:
Dimenticare un dispositivo. Elimina
ble_secrets.json(o rimuovi la voce pertinente) per dimenticare tutti i peer in bonding, poi esegui di nuovo il pairing da zero.L’accesso fisico espone le chiavi. Chiunque abbia accesso al filesystem della camera puo leggere il JSON. Questo e lo stesso tipo di vincolo emerso sul fronte di rete con le chiavi TLS (Operazioni: chiavi, scadenza e risoluzione dei problemi): usa chiavi per dispositivo, tratta qualunque chiave memorizzata come recuperabile e fai affidamento sulla possibilita di revoca (qui, rimuovere il bond sul lato central) piuttosto che sul fatto che la chiave rimanga segreta.
11.13.5. Cosa garantisce la cifratura – e cosa non garantisce¶
Un collegamento pairing-poi-cifratura offre, in ordine di robustezza:
Riservatezza. Sempre. Un intercettatore non puo leggere i byte.
Integrita. Sempre. I pacchetti modificati falliscono il controllo di autenticazione-cifratura del link layer e vengono scartati.
Autenticazione. Solo con
mitm=Truee una capacita di IO adeguata. Senza di essa, un man-in-the-middle che ha intercettato lo scambio di pairing originale potrebbe essersi inserito; senza protezione MITM non c’e modo per i due lati di saperlo.
Per la maggior parte dei casi d’uso della camera – un telefono che esegue il pairing con la camera una volta, poi si riconnette in seguito – mitm=False e di solito sufficiente, perche il pairing originale avviene in un ambiente controllato (l’utente tiene entrambi i dispositivi nella stessa stanza). Per applicazioni in cui un dispositivo accoppiato potrebbe incontrare la camera per la prima volta a lunga distanza o tramite un intermediario non fidato, MITM e l’impostazione corretta.
11.13.6. Quando il pairing e la risposta sbagliata¶
Il pairing ha un costo reale: qualche secondo di scambio alla prima connessione, un uso persistente della flash per ogni dispositivo in bonding e la procedura di recupero del «dimentica il bond» se qualcosa va storto. Per dati genuinamente pubblici – letture di sensori ambientali pubblicate come beacon, un’insegna che mostra il proprio nome, qualunque cosa che non cambi il mondo per il fatto di essere letta o scritta – la risposta corretta e non cifrare affatto, e lasciare che qualunque scanner nelle vicinanze legga i valori.
Per tutto il resto, connection.pair(bond=True) sul central e l’aggiunta di una riga che trasforma il collegamento da un canale pubblico a uno privato.