146 lines
4.4 KiB
Markdown
146 lines
4.4 KiB
Markdown
# Protocollo TCN
|
|
|
|
|
|
|
|
## Descrizione del protocollo
|
|
|
|
|
|
|
|
### Chiavi di autenticazione e verifica
|
|
|
|
|
|
### Chiave temporanea di contatto {#sec:tck}
|
|
|
|
|
|
|
|
### Numeri temporanei di contatto
|
|
|
|
|
|
|
|
### Report
|
|
|
|
|
|
|
|
## Implementazione del protocollo per la JMV
|
|
|
|
Al fine di utilizzare il protocollo precedentemente descritto all'interno dell'applicazione Android, ne è stato sviluppato un'implementazione per la *Java Virtual Machine*.
|
|
La gestione della coppia di chiavi derivate dalla curva ellittica *Ed25519* è stata affidata alla libreria ***ed25519-elisabeth*** @CryptographycafeEd25519elisabeth2020.
|
|
Le chiavi private e pubbliche prodotte sono state *wrappate* rispettivamente nelle classi `ReportAuthorizationKey` e `ReportVerificationKey`.
|
|
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.
|
|
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.
|
|
|
|
``` {.kotlin #lst:tck-0 caption="Derivazione della prima tck."}
|
|
fun baseTemporaryContactKey(): TemporaryContactKey {
|
|
val hmac = MessageDigest.getInstance("SHA-256").apply {
|
|
update(Const.H_TCK_DOMAIN_SEPARATOR)
|
|
update(key.toByteArray())
|
|
}
|
|
|
|
return TemporaryContactKey.createFromByteArray(
|
|
hmac.digest(),
|
|
0
|
|
)
|
|
}
|
|
```
|
|
|
|
``` {.kotlin #lst:next-tck caption="Generazione della prossima tck."}
|
|
fun nextTemporaryContactKey(
|
|
rvk: ReportVerificationKey
|
|
): TemporaryContactKey {
|
|
val hmac = MessageDigest.getInstance("SHA-256").apply {
|
|
update(Const.H_TCK_DOMAIN_SEPARATOR)
|
|
update(rvk.toByteArray())
|
|
update(key)
|
|
}
|
|
|
|
return TemporaryContactKey(
|
|
hmac.digest(),
|
|
index.inc()
|
|
)
|
|
}
|
|
```
|
|
|
|
Sempre a partire dalla tck è possibile ricavare il numero di contatto temporaneo (tcn) e da esso l'UUID utilizzato all'interno dei beacon bluetooth.
|
|
Questa operazione può essere eseguita mediante la funzione `deriveTemporaryContactNumber()` la cui implementazione è stata riportata nel @lst:derive-tcn.
|
|
|
|
``` {.kotlin #lst:derive-tcn caption="Derivazione del numero di contatto temporaneo."}
|
|
fun deriveTemporaryContactNumber(): TemporaryContactNumber {
|
|
val hmac = MessageDigest.getInstance("SHA-256").apply {
|
|
update(Const.H_TCN_DOMAIN_SEPARATOR)
|
|
update(index.toLeByteArray())
|
|
update(key)
|
|
}
|
|
|
|
return TemporaryContactNumber(
|
|
hmac.digest().sliceArray(0 until 16),
|
|
index
|
|
)
|
|
}
|
|
```
|
|
|
|
Un'altra componente fondamentale dell'implementazione del protocollo TCN è la classe `Report`, infatti tramite essa è possibile generare il report firmato che poi sarà inviato al server.
|
|
Inoltre questa classe mette a disposizione una serie di funzioni di utilità come `generateContactNumbers()` e `toReportData()` che facilitano l'estrazione delle informazioni contenute all'interno del report.
|
|
Infine la classe report fornisce anche un metodo statico, `readReportDataFromByteArray()`, attraverso il quale altre componenti applicative sono in grado di recuperare le informazioni di un report contenute all'interno di un array di bytes.
|
|
L'implementazione di questo metodo è riportata nel listato @lst:read-report.
|
|
|
|
``` {.kotlin #lst:read-report caption="Lettura dei dati di un report da un ByteArray."}
|
|
fun readReportDataFromByteArray(bytes: ByteArray): ReportData {
|
|
val buffer = ByteBuffer.wrap(bytes).apply {
|
|
order(ByteOrder.LITTLE_ENDIAN)
|
|
}
|
|
|
|
val rvk = ReportVerificationKey
|
|
.createFromByteArray(buffer.read(32))
|
|
val tckBytes = buffer.read(32)
|
|
val from = buffer.short
|
|
val until = buffer.short
|
|
val memoType = buffer.get()
|
|
val memoData = String(buffer.read(buffer.get().toInt()))
|
|
|
|
return ReportData(
|
|
rvk,
|
|
TemporaryContactKey
|
|
.createFromByteArray(tckBytes, from.dec()),
|
|
from,
|
|
until,
|
|
memoData
|
|
)
|
|
}
|
|
```
|
|
|
|
# Applicazione
|
|
|
|
|
|
|
|
## Bluetooth
|
|
|
|
|
|
|
|
### Trasmissione
|
|
|
|
|
|
|
|
### Scansione
|
|
|
|
|
|
|
|
### Stima della distanza
|
|
|
|
|
|
|
|
## UI
|
|
|
|
|
|
|
|
## Memorizzazione
|
|
|
|
|
|
|
|
## Rete
|
|
|