Quanti Immuni intorno a me?

“La cura per la noia è la curiosità. Non ci sono cure per la curiosità.”
Dorothy Parker

Chi lo avrebbe mai detto che un semplice progettino serale, nato da una idea tanto semplice quanto banale, sarebbe diventato così popolare? A furia di parlare di Immuni, infatti, avevo iniziato a guardare, incuriosito, il funzionamento del sistema di contact tracing sviluppato da Google e Apple.

Per iniziare, è bene precisare che con Immuni (ma in generale qualsiasi altra tecnologia di contact tracing e non solo…) ogni smartphone è sia ricevitore che trasmettitore di informazioni. Il protocollo d’interscambio delle informazioni tra i dispositivi vicini, che prevede la trasmissione continua di beacon BLE con MAC pseudocasuali detti RPI (Rolling Proximity Identifier) –variando approssimativamente ogni 10/15 minuti– serve a registrare anche tutta una serie di ulteriori informazioni (marca temporale, durata del contatto…). Maggiori dettagli sono descritti nell’articolo “Replay attack contro Immuni, la vulnerabilità spiegata da chi l’ha dimostrata” – AgendaDigitale.eu.

Attenzione: essendo gli indirizzi casuali, è impossibile risalire con precisione al dispositivo originario. Tentando una similitudine azzardata, è come trovarsi dentro un confessionale a parlare con uno sconosciuto che, ogni 15 minuti, cambia tonalità e timbro di voce…

I beacons

Pur se casuali, i beacon inviati identificano comunque la presenza di uno o più dispositivi. E contando quanti indirizzi univoci inviano i beacon, riesco a stimare con ragionevole precisione il numero di Immuni presenti nel raggio di azione (circa 10-12 metri).

Una situazione esemplificativa con 6 persone, di cui 3 con Immuni App installata e funzionante.

Le specifiche del Contact Tracing Bluetooth Specification v1.1 parlano di un Advertisement Payload che deve essere inviato e “ascoltato” da tutti i partecipanti (“Devices advertise and scan for the Contact Detection Service by way of its 16-bit service UUID“):

Advertisement Payload

Il codice

Ho preso un modulo ESP32 (ho scelto il TTGO ESP32 OLED, perché ha batteria e display oled da 0,96″ incluso) e iniziato a scrivere qualche riga di codice per ascoltare i beacon (fortemente ispirato agli esempi già reperibili in Rete):

void bleTask(void *pvParameters) {
  BLEDevice::init("");
  DEBUG_PRINTLN(F("BLEDevice::init() DONE !"));
  
  while(1) {
    if(BLEDevice::getInitialized()) {
      BLEScan* pBLEScan = BLEDevice::getScan(); //create new scan
      pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
      pBLEScan->setActiveScan(true);
      BLEScanResults foundDevices = pBLEScan->start(scanTime);
    } else {
      delay(5000);
      BLEDevice::init("");
    }
  }
}

ad ogni device individuato (=beacon ricevuto) viene chiamata la funzione MyAdvertisedDeviceCallbacks() che, come prima cosa, confronta l’UUID del servizio con il valore previsto dai sistemi di contact tracing:

const char* uuid = "0000fd6f-0000-1000-8000-00805f9b34fb";

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
      void onResult(BLEAdvertisedDevice advertisedDevice) {
        if(advertisedDevice.haveServiceUUID()){
            if(strncmp(advertisedDevice.getServiceUUID().toString().c_str(),uuid, 36) == 0){
                int rssi = advertisedDevice.getRSSI();
                char temp[18];             
                DEBUG_PRINTLN(F("---------------------------"));
                DEBUG_PRINT(F("RSSI: "));
                DEBUG_PRINTLN(String(rssi));
                float est_distance = 10 ^ ((-69 - (rssi))/(10 * 2));
                dtostrf(est_distance, 5,3, temp);
                DEBUG_PRINT(F("DISTANCE (mt): "));
                DEBUG_PRINTLN(String(temp));
                DEBUG_PRINT(F("ADDR: "));
             strncpy(temp,advertisedDevice.getAddress().toString().c_str(),18);
                DEBUG_PRINTLN(String(temp));
            }
        }
    }
};

A questo punto è stato divertente andare in giro e vedere, con una buona approssimazione (i dispositivi che nei 30 secondi di ogni scansione cambiano il proprio indirizzi saranno conteggiati due volte), quanti Immuni avevo intorno a me.

GPS e miniSD

Per iniziare, un semplice beacon sniffer è sufficiente per muovere i primi passi. I moduli ESP32 sono tuttavia abbastanza potenti per incorporare anche altri moduli, come un GPS per geolocalizzare e uno scrittore di schede microSD dove memorizzare i “contatti” avuti per una successiva analisi.

Pinout modulo TTGO ESP32 Oled

L’idea è quindi aggiungere un modulo GPS a una delle tre porte seriali asincrone dell’ESP32, oltre a un modulo per le schede micro SD.

Modulo GPS

Inizio dal modulo GPS, che ho collegato alla seriale 2, RX=PIN 16 e TX=PIN 17 (che vanno, rispettivamente, ai pin TX e RX sulla scheda). Si collega anche l’alimentazione a 3.3V e GND. Non serve altro, se non una libreria capace d’interpretare i messaggi NMEA, come TinyGPS++:

#include <TinyGPS++.h>
#define GPS_RX 16
#define GPS_TX 17
// The TinyGPS++ object
TinyGPSPlus gps;

String gpsLat;
String gpsLng;

Inizializzo la porta seriale a 9600 BAUD:

Serial2.begin(9600, SERIAL_8N1, GPS_RX, GPS_TX);

e, nel loop():

while(Serial2.available() > 0) {
    gps.encode(Serial2.read());
    if (gps.location.isValid()) {
      gpsLat = String(gps.location.lat(), 6);
      gpsLng = String(gps.location.lng(), 6);
      Serial.print("LAT="); Serial.print(gpsLat);
      Serial.print("LNG="); Serial.println(gpsLng);
    }
  }
Modulo per schede microSD su bus SPI

Il modulo per le schede microSD richiede 4 fili, più l’alimentazione a 5V. Ho usato i pin del bus SPI, che sono:

MISO=PIN 19
MOSI=PIN 23
SCK=PIN 18
CS=PIN 5

…ma questa parte è ancora in sviluppo 😉 stay tuned!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.