This commit is contained in:
parent
087a21eb07
commit
8fc33302e9
@ -2,15 +2,15 @@
|
||||
|
||||
## Descrizione del protocollo
|
||||
|
||||
Il protocollo TCN [@TCNCoalitionTCN2020], Temporary Contact Number, è un protocollo di tracciamento dei contatti decentralizzato, ideato dalla TCN Coalition. Quest'ultima è una comunità di persone che durante l'emergenza COVID-19 hanno sviluppato questo supporto per lo sviluppo di applicazioni per notificare l'esposizione al contagio.
|
||||
Il protocollo non richiede, informazioni personali ed è compatibile con autorità sanitarie.
|
||||
Il protocollo TCN [@TCNCoalitionTCN2020], Temporary Contact Number, è un protocollo di tracciamento dei contatti decentralizzato, ideato dalla TCN Coalition. Quest'ultima è una comunità di persone che durante l'emergenza COVID-19 hanno sviluppato questo protocollo per lo sviluppo di applicazioni per notificare l'esposizione al contagio.
|
||||
Il protocollo non richiede informazioni personali ed è compatibile con autorità sanitarie.
|
||||
I dispositivi degli utenti inviano un identificativo agli utenti vicini tramite Bluetooth e successivamente, se un utente è risultato positivo al contagio, può notificarlo ai suo contatti.
|
||||
|
||||
Per aumentare la scalabilità la TCN Coalition ha scelto di non generare randomicamente tcn, ma di generarli in modo deterministico da un seed.
|
||||
In questo modo si riduce la dimensione del report da inviare, in quanto contiene solo le informazione necessarie per calcolare i tcn e non l'elenco intero di tcn.
|
||||
L'utente può caricare diversi report di dimensioni minori in modo da non caricare l'intera cronologia dei contatti.
|
||||
|
||||
### Chiavi di autenticazione e verifica
|
||||
### Chiavi di autorizzazione e verifica
|
||||
|
||||
L'user agent crea una chiave di autorizzazione *rak* (report authorization key) e una chiave di verifica *rvk* (report verification key) attraverso la curva ellittica *Ed25519*.
|
||||
|
||||
@ -26,7 +26,7 @@ dove `H_tck` è una funzione di hash con 256 bit di output che utilizza come sep
|
||||
|
||||
Ogni report può contenere al massimo $2^{16}$ chiavi di contatto.
|
||||
|
||||
Partendo un tcn se ne può derivare il prossimo tcn come mostrato di seguito:
|
||||
Partendo da un tcn può essere ricavato il prossimo come mostrato di seguito:
|
||||
|
||||
```
|
||||
tck_i ← H_tck(rvk || tck_{i-1})
|
||||
@ -36,7 +36,7 @@ dove `||` indica una concatenazione.
|
||||
|
||||
### Numeri temporanei di contatto {#sec:tcn}
|
||||
|
||||
Per ogni tck viene generato un numero di contatto temporaneo come mostrato di seguito:
|
||||
Per ogni tck viene generato un unico numero di contatto temporaneo (*tcn*) come mostrato di seguito:
|
||||
|
||||
```
|
||||
tcn_i ← H_tcn(le_u16(i) || tck_i)
|
||||
@ -47,7 +47,7 @@ Dalla chiave rak è possibile generare la chiave rvk e la chiave tck_0, dalle qu
|
||||
|
||||
### Report {#sec:report}
|
||||
|
||||
Quando viene richiesto di caricare i dati dell'utente, è possibile eseguire l'upload di un report compatto. Infatti grazie alla derivazione deterministica, è possibile inviare tutti gli identificativi utilizzati nel periodo `j1` e `j2`, caricando unicamente la rvk, tck_{j-1}, e i due indici `j1` e `j2`.
|
||||
Quando viene richiesto di caricare i dati dell'utente, è possibile eseguire l'upload di un report compatto. Infatti grazie alla derivazione deterministica, è possibile inviare tutti gli identificativi utilizzati nel periodo `j1` e `j2`, caricando unicamente la `rvk`, `tck_{j1-1}`, e i due indici `j1` e `j2`.
|
||||
Di seguito è illustrato come costruire il report:
|
||||
|
||||
```
|
||||
@ -57,7 +57,7 @@ report ← rvk || tck_{j1-1} || le_u16(j1) || le_u16(j2) || memo
|
||||
dove `memo` è una stringa di byte di lunghezza variabile che va da 2 a 257 byte.
|
||||
Inoltre si utilizza il rak per produrre una firma `sig` per il report e verrà inviata al server la concatenazione di sig e report.
|
||||
|
||||
Poiché la rvk è contenuta all'interno del report, chiunque può verificare l'integrità del report e ricavare i vari.
|
||||
Poiché la rvk è contenuta all'interno del report, chiunque può verificare l'integrità del report e ricavare i vari tcn.
|
||||
|
||||
## Implementazione del protocollo per la JMV
|
||||
|
||||
@ -67,7 +67,7 @@ Le chiavi private e pubbliche prodotte sono state *wrappate* rispettivamente nel
|
||||
Questa scelta non solo ha permesso di utilizzare nomi dal maggiore significato rispetto al dominio applicativo, ma anche di nascondere l'implementazione della curva *Ed25519* in modo da disaccoppiare l'interfaccia della libreria crittografica da quella utilizzata per il protocollo TCN.
|
||||
|
||||
Come illustrato nella @sec:tck, a partire dalla chiave di autorizzazione è possibile ricavare la `TemporaryContactKey` iniziale[^tck-0].
|
||||
Ciò può essere fatto traverso la funzione `baseTemporaryContactKey()`, la cui implementazione è riportata nel @lst:tck-0.
|
||||
Ciò può essere fatto attraverso la funzione `baseTemporaryContactKey()`, la cui implementazione è riportata nel @lst:tck-0.
|
||||
Invece, partendo da una chiave di contatto generica, è possibile ricavare la successiva chiave di contatto attraverso il metodo `nextTemporaryContactKey()` riportato nel listato @lst:next-tck.
|
||||
|
||||
[^tck-0]: La chiave temporanea iniziale viene ricavata a partire dalla sola *rak* e da essa non è generato nessun numero temporaneo di contatto.
|
||||
@ -187,7 +187,7 @@ Entrambi i protocolli ricavano gli identificativi (*rolling proximity identifier
|
||||
I due protocolli differiscono nel numero di identificativi ricavati da ciascuna chiave; come visto nella @sec:tcn il protocollo TCN ricava un unico tcn per chiave, mentre l'altro protocollo permette di ricavare un numero imprecisato di identificativi.
|
||||
Un'ulteriore differenza risiede nella derivazioni delle chiavi, che nel protocollo TCN è deterministica, mentre in quello di Apple e Google non è specificato.
|
||||
|
||||
Oltre al protocollo, le due società, hanno fornito agli sviluppatori un API che permettesse alle applicazioni di di utilizzare il protocollo descritto nel paragrafo precedente.
|
||||
Oltre al protocollo, le due società, hanno fornito agli sviluppatori un'API che permettesse alle applicazioni di utilizzare il protocollo descritto nel paragrafo precedente.
|
||||
Sfortunatamente l'API non ci avrebbe permesso di implementare tutte e tre le modalità di funzionamento, ma solo l'ultima che si basa su un matching locale.
|
||||
Questa caratteristica, unita alle regole stringenti di utilizzo imposte della libreria[^regole-api-apple-google] ci ha condotto alla scelta di implementare le varie funzionalità in maniera indipendente.
|
||||
|
||||
@ -199,7 +199,7 @@ Dalla documentazione ufficiale non è ben chiaro se questi vincoli riguardino so
|
||||
L'interazione tra l'hardware bluetooth del dispositivo e l'applicazione è stata gestita attraverso l'impiego della libreria *Android Beacon Library* [@AndroidBeaconLibrary] che permette di gestire più facilmente le operazioni con beacon bluetooth.
|
||||
Inoltre per rendere l'applicazione più funzionale, e quindi garantirne il funzionamento anche in background o a schermo spento è stato utilizzato un *foreground service* [@ServicesOverview], che consente di mantenere in *primo piano* le operazioni di trasmissione e scansione anche quando l'applicazione non lo è.
|
||||
Data la natura variegata di Android, le diverse implementazioni del sistema operativo adoperate dai vari produttori non si comportano sempre nello stesso modo, motivo per il quale alcuni dispositivi tenderanno a terminare, o mettere in pausa ugualmente l'applicazione[^dont-kill-my-app].
|
||||
Potendo opera unicamente nello spazio utente non è stato possibile superare questi limiti.
|
||||
Potendo operare unicamente nello spazio utente non è stato possibile superare questi limiti.
|
||||
|
||||
[^dont-kill-my-app]: Molti produttori Android per aumentare la durata della batteria dei propri dispositivi tendono a stoppare e ridurre le funzionalità delle applicazioni. Maggiori dettagli possono essere trovati al seguente link \url{https://dontkillmyapp.com}.
|
||||
|
||||
@ -214,7 +214,7 @@ Per questo motivo è stata sviluppata anche una classe `BluetoothApplication` ch
|
||||
Il dispositivo dell'utente deve eseguire il broadcast di un beacon bluetooth contenete l'UUID identificativo.
|
||||
Questa operazione è stata svolta attraverso la classe `BeaconTransmitter` messa a disposizione dalla *Android Beacon Library*.
|
||||
Inoltre per la modalità di funzionamento *C* è stato necessario prevedere un meccanismo di rotazione delle chiavi.
|
||||
Questa rotazione viene settata attraverso la funzione `rotateTCN()` che sfrutta un `Handler` per programmare la rotazione dell'UUID.
|
||||
Questa rotazione viene settata attraverso la funzione `rotateTCN()` (@lst:rotate-tcn) che sfrutta un `Handler` per programmare la rotazione dell'UUID.
|
||||
|
||||
``` {.kotlin #lst:rotate-tcn caption="Codice necessario alla rotazione del tcn."}
|
||||
private fun rotateTCN() {
|
||||
@ -250,8 +250,8 @@ Anche in questo caso la scelta era limitata a poche alternative:
|
||||
- LOW
|
||||
- ULTRA_LOW
|
||||
|
||||
Com'è possibile dedurre anche dai nomi dei vari livelli, l'API non fornisce nessuna stima quantitativa[^dispositivi-non-omogenei], ma solo delle indicazioni qualitative delle intensità del segnale trasmesso.
|
||||
L'individuazione del livello più adatto è stata svolta per via sperimentale utilizzando cinque dispositivi differenti.
|
||||
Come è possibile dedurre anche dai nomi dei vari livelli, l'API non fornisce nessuna stima quantitativa[^dispositivi-non-omogenei], ma solo delle indicazioni qualitative delle intensità del segnale trasmesso.
|
||||
L'individuazione del livello più adatto è stata svolta per via sperimentale utilizzando quattro dispositivi differenti[^dispositivi-usati].
|
||||
I due livelli più alti sono stati immediatamente scartati in quanto permettevano di rilevare i beacon a distanze elevate cosa che avrebbe minato la bontà dell'applicazione.
|
||||
Con il livello ULTRA_LOW si è notato che venivano rilevate unicamente le interazioni inferiori al metro in contesti *free space*.
|
||||
Poiché l'organizzazione mondiale della sanità raccomanda una distanza di almeno un metro [@AdvicePublicCOVID19] questo livello di trasmissione non consente di rilevare contatti potenzialmente a rischio.
|
||||
@ -259,34 +259,18 @@ Per questo motivo si è scelto di utilizzare il livello LOW che permette di rile
|
||||
|
||||
[^dispositivi-non-omogenei]: D'altronde, data la natura non omogenea dei vari dispositivi Android, una stima quantitativa sarebbe stata impossibile da ottenere.
|
||||
|
||||
[^dispositivi-usati]: Sono stati usati i seguenti dispositivi; One Plus 3T con versione di Android 9, Xiaomi Mi 5 con Android 8, Xiaomi Mi A2 Lite con Android 10, Samsung Galaxy A5 con Android 7.
|
||||
|
||||
### Scansione
|
||||
|
||||
Le operazioni di scansione sono meno limitate dalle funzionalità dell'API di Android e per questo motivo c'è stata maggiore libertà di scelta.
|
||||
Le operazioni di scansione, effettuate tramite l'ausilio della classe `BeaconManager`, sono meno limitate dalle funzionalità dell'API e per questo motivo c'è stata maggiore libertà di scelta.
|
||||
In particolare è stato possibile settare sia l'intervallo temporale che deve intercorrere tra una scansione e la successiva, sia la durata della singola scansione.
|
||||
Si è scelto di far trascorrere un minuto tra una scansione e la prossima e di avere una scansione della durata di un secondo.
|
||||
Per quanto detto già in precedenza in base ai vari dispositivi e alle varie condizioni di funzionamento l'intervallo tra una scansione e la successiva potrebbe essere più ampio rispetto a quello stabilito.
|
||||
Entrambi i parametri sono stati settati tramite una costante in modo tale da poter configurare facilmente il comportamento dell'applicazione.
|
||||
|
||||
Quando l'applicazione rivela un beacon nelle vicinanze esso viene trasmesso ad un'ulteriore componente applicativa tramite l'impiego del `LocalBroadcastManager` @BroadcastsOverview.
|
||||
Quando l'applicazione rivela un beacon nelle vicinanze esso viene trasmesso ad un'ulteriore componente applicativa tramite l'impiego del `LocalBroadcastManager` [@BroadcastsOverview].
|
||||
Questa componente non consuma direttamente il beacon, ma ha il compito di smistarlo ad ulteriori componenti in base alla modalità di funzionamento dell'applicazione.
|
||||
Il codice necessario a smistare i dati di contatto è stato riportato nel @lst:contact-receiver.
|
||||
Come si può notare nella linea 2, la prima operazione consiste nel recupero dei dati di contatto dall'`Intent`, mentre dalla linea 7 si seleziona la funzione da invocare in base alla modalità di funzionamento.
|
||||
|
||||
``` {.kotlin .numberLines #lst:contact-receiver caption="Codice necessario allo smistamento dei dati di contatto."}
|
||||
// ...
|
||||
val contactData = intent?.getSerializableExtra(CONTACT_DATA_KEY)
|
||||
as ContactData?
|
||||
|
||||
val mode = getMod(context)
|
||||
|
||||
val onMode = when (mode) {
|
||||
Mode.MOD_A -> this::contactOnModeA
|
||||
Mode.MOD_B -> this::contactOnModeB
|
||||
Mode.MOD_C -> this::contactOnModeC
|
||||
}
|
||||
|
||||
onMode(context, contactData)
|
||||
```
|
||||
|
||||
Nel caso della modalità *A* il beacon viene trasmesso alla classe `NetworkReceiver` che si occupa di trasmettere il contatto al server remoto.
|
||||
Mentre nel caso delle modalità *B* e *C* il beacon viene consumato dalla classe `StoreReceiver` la quale si occupa della memorizzazione permanente del contatto all'interno di un database locale.
|
||||
@ -304,7 +288,7 @@ $$ {#eq:distanza}
|
||||
|
||||
$TxPower$ è la potenza di trasmissione nominale che si misurerebbe alla distanza di un metro dalla sorgente del segnale.
|
||||
Il valore di $TxPower$ deve essere precedentemente ricavato per ogni emettitore e deve essere inviato all'interno del beacon bluetooth.
|
||||
Lavorando con dispositivi eterogenei tra di loro non è stato possibile calcolare in modo esatto questo valore ma si è scelto di utilizzare un valore che mediamente si adattasse a tutti i dispositivi utilizzati in fase di test.
|
||||
Lavorando con dispositivi eterogenei tra di loro non è stato possibile calcolare in modo esatto questo valore, ma si è scelto di utilizzare il valore $-59$ poiché si adattava mediamente a tutti i dispositivi utilizzati in fase di test.
|
||||
|
||||
## UI
|
||||
|
||||
@ -320,7 +304,7 @@ La schermata principale dell'applicazione, riportata in @fig:ui-main, si compone
|
||||
- `TextView` che indica la modalità di funzionamento.
|
||||
- `Button` *start/stop* che consente di avviare o stoppare il servizio bluetooth.
|
||||
Questo pulsante viene abilitato unicamente se sono stati concessi i permessi di accesso alla posizione.
|
||||
- `Button` *upload*, abilitato solo nelle modalità *B* e *C*, consente all'utente di raggiungere l'activity attraverso il quale è possibile caricare sul server le informazioni locali al dispositivo (@fig:ui-upload).
|
||||
- `Button` *upload*, abilitato solo nelle modalità *B* e *C*, consente all'utente di raggiungere l'activity attraverso la quale è possibile caricare sul server le informazioni locali al dispositivo (@fig:ui-upload).
|
||||
|
||||
![Schermata principale.](fig/main.jpg){#fig:ui-main width=130}
|
||||
|
||||
@ -334,6 +318,7 @@ La gestione della persistenza è stata realizzata attraverso la libreria ***Room
|
||||
|
||||
La memorizzazione dei contatti è avvenuta tramite lo schema riportato nel @lst:contact-data.
|
||||
Questi dati vengono conservati solo nella modalità di funzionamento *B* e *C* poiché nella modalità *A* il contatto viene comunicato immediatamente al server per cui non è necessaria una memorizzazione locale.
|
||||
Per il timestamp si è scelto di utilizzare un `Long` che misura i secondi trascorsi dalla *epoch unix* e che fa riferimento al *Greenwich Mean Time* (GMT).
|
||||
|
||||
``` {.markdown #lst:contact-data caption="Schema utilizzato per la memorizzazione dei dati di contatto."}
|
||||
- `id`: Int [PrimaryKey | AutoGenerate]
|
||||
@ -347,6 +332,7 @@ Questi dati vengono conservati solo nella modalità di funzionamento *B* e *C* p
|
||||
Nella modalità *C* è necessario memorizzare anche le tck utilizzate nel corso del tempo (si veda la @sec:tck per maggiori dettagli).
|
||||
Oltre alla memorizzazione della tck, tramite un array di byte, è necessario memorizzare anche l'indice associato ad essa e il timestamp di primo utilizzo.
|
||||
Lo schema della tabella utilizzata per la memorizzazione di queste informazioni è riportato nel @lst:tck-data.
|
||||
Anche in questo caso, per quanto riguarda il timestamp, restano valide le considerazioni fatte in precedenza.
|
||||
|
||||
``` {.markdown #lst:tck-data caption="Schema utilizzato per la memorizzazione delle tck."}
|
||||
- `index`: Short [PrimaryKey]
|
||||
@ -399,13 +385,14 @@ L'applicazione, all'interno dell'architettura, svolge il ruolo di *publisher* e
|
||||
Il contenuto di questi messaggi coincide con la rappresentazione JSON dei dati di contatto illustrati nel @lst:contact-data.
|
||||
- ***Messaggi di report***:
|
||||
utilizzati esclusivamente nella modalità *C*.
|
||||
Questi messaggi trasportano come *payload* la rappresentazione esadecimale del report TCN discusso nella @sec:report e vengono inviati solo quando l'*upload* è richiesto dall'utente.
|
||||
Questi messaggi trasportano come *payload* la rappresentazione esadecimale del report TCN firmato discusso nella @sec:report e vengono inviati solo quando l'*upload* è richiesto dall'utente.
|
||||
|
||||
Anche in questo caso si è scelto di *wrappare* la libreria utilizzata all'interno di una classe sviluppata in proprio.
|
||||
Poiché l'unica funzionalità di nostro interesse è la *publish* è stato necessario scrivere un'unica funzione statica che si occupa di eseguire quest'operazione.
|
||||
Questa funzione, riportata nel @lst:mqtt-publish, permette di specificare il topic e il contenuto del messaggio da pubblicare.
|
||||
Inoltre attraverso una *lambda expression* è possibile specificare come comportarsi in caso di errori.
|
||||
Sempre dal @lst:mqtt-publish è possibile notare l'utilizzo del parametro `cleanSession` impostato a `false` e l'utilizzo dei *QoS* a livello uno, ciò si è reso necessario per garantire un corretto funzionamento con il resto dell'infrastruttura.
|
||||
Sempre dal @lst:mqtt-publish è possibile notare l'utilizzo del parametro `cleanSession` impostato a `false` e l'utilizzo dei *QoS* a livello uno.
|
||||
Queste scelte sono state necessarie per garantire un corretto funzionamento con il resto dell'infrastruttura.
|
||||
|
||||
``` {.kotlin #lst:mqtt-publish caption="Funzione wrap che consente la publicazione di un messaggio MQTT."}
|
||||
fun publish(
|
||||
@ -447,7 +434,7 @@ fun publish(
|
||||
}
|
||||
```
|
||||
|
||||
Le funzionalità di rete sono state testate attraverso l'impiego di un brocker pubblico e l'utilizzo del topic `untori`.
|
||||
Le funzionalità di rete sono state testate attraverso l'impiego di un brocker pubblico (`tcp://broker.hivemq.com:1883`) ed un'istanza locale di *ActiveMQ Artemis* inoltre è stato utilizzato il topic `untori` per la pubblicazione dei messaggi.
|
||||
Entrambi i parametri sono stati settati tramite delle costanti e quindi possono essere modificati facilmente.
|
||||
|
||||
# Riferimenti
|
||||
|
Loading…
Reference in New Issue
Block a user