Sei sulla pagina 1di 86

Corso di Laurea in

Sicurezza dei Sistemi e delle Reti Informatiche

Sviluppo di una app mobile

per il problema del milionario

TESI DI LAUREA DI
RELATORE
Karrie Moore
Prof. Cimato Stelvio
Matr. 828737

Anno Accademico 2014/2015


2
Indice

1 Introduzione 5
1.1 SMC per problemi reali . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2 Scopo del progetto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Struttura della tesi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2 Secure Multi-party Computation 11


2.1 Definizioni generali . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.2 Oblivious Transfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1
2.2.1 Oblivious transfer con probabilità 2
. . . . . . . . . . . . . . 13
2.2.2 Oblivious transfer 1 su 2 . . . . . . . . . . . . . . . . . . . . . 14
2.3 Garbled Circuits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.1 Costruzione di un circuito . . . . . . . . . . . . . . . . . . . . 15
2.4 Two Party Computation . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.5 Multi-party computation . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.6 Protocolli generici basati sui circuiti . . . . . . . . . . . . . . . . . . 21

3 Due protocolli per la Secure Multi-party Computation 23


3.1 Protocollo del milionario . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.1.1 Definizione del protocollo . . . . . . . . . . . . . . . . . . . . 23
3.1.2 Esempio di utilizzo . . . . . . . . . . . . . . . . . . . . . . . . 24
3.2 Votazione di un candidato . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2.1 Algoritmo di votazione . . . . . . . . . . . . . . . . . . . . . 25
3.2.2 Esempio di utilizzo . . . . . . . . . . . . . . . . . . . . . . . . 27

4 Architettura dell’applicazione 29
4.1 Struttura generale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.1.1 Organizzazione del codice . . . . . . . . . . . . . . . . . . . . 31
4.2 Protocolli di SMC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4 INDICE

4.3 Layer di trasporto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32


4.3.1 Tipi di pacchetti . . . . . . . . . . . . . . . . . . . . . . . . . . 36

5 Implementazione 39
5.1 Tecnologie e scelte implementative . . . . . . . . . . . . . . . . . . . 39
5.2 Implementazione dei protocolli . . . . . . . . . . . . . . . . . . . . . 42
5.2.1 Le interfacce comuni ai protocolli . . . . . . . . . . . . . . . 42
5.2.2 Problema del milionario . . . . . . . . . . . . . . . . . . . . . 43
5.2.3 Votazione di un candidato . . . . . . . . . . . . . . . . . . . . 45
5.3 L’uso di Wi-Fi Direct . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
5.4 Tecnologie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.4.1 Java Cryptography Architecture . . . . . . . . . . . . . . . . 49
5.4.2 Android Wi-Fi Direct . . . . . . . . . . . . . . . . . . . . . . . 52
5.5 Librerie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.5.1 Salut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
5.5.2 LoganSquare . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
5.6 Strategie di testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.7 Prestazioni dell’applicazione . . . . . . . . . . . . . . . . . . . . . . 70
5.8 Flusso applicativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75

6 Sviluppi futuri e conclusioni 79


6.1 Sviluppi futuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
6.2 Conclusioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80

Bibliografia 81
Capitolo 1

Introduzione

La Secure Multi-party Computation (SMC), conosciuta anche come Secure Com-


putation o Multi-Party Computation (MPC), è una branca della crittografia che si
occupa di creare strategie per valutare una funzione di più argomenti che devono
essere mantenuti segreti. Un requisito fondamentale della SMC è l’assenza di una
terza parte fidata durante il calcolo, quindi non esistono eccezioni all’obbligo di
segretezza degli argomenti della funzione, gli unici a conoscere tali valori sono i
legittimi proprietari [5].
La secure multi-party computation è stata formalmente introdotta nella for-
ma della secure two-party computation (2PC) nel 1982 da Andrew Yao che con
questo lavoro ha meritato il premio Knuth [2]. La 2PC si occupa di funzioni a
due argomenti che devono essere valutate in modo sicuro, Yao nella sua ricerca
ha presentato una soluzione al problema del milionario, nel quale due milionari
vogliono scoprire chi dei due è il più ricco, senza rivelare nessun dato che possa
aiutare a determinare la ricchezza espressa dall’altro [12].
Inizialmente l’approccio di Yao è stato considerato interessante dal punto di
vista teorico ma troppo costoso dal punto di vista computazionale. Tuttavia
con l’aumentare della velocità di computazione, trasmissione e l’incremento di
memoria operativa, i problemi legati alle prestazioni di algoritmi che negli an-
ni ’80 potevano sembrare insormontabili non esistono più: al giorno d’oggi an-
che i piccoli dispositivi che ci circondano, come possono essere gli smartphone,
possiedono una grande potenza computazionale.
Negli anni le soluzioni proposte da Yao sono state migliorate ed estese ed
ora possono essere usate in problemi reali come il voto distribuito, aste online,
condivisione di firme, funzioni di cifratura/decifratura o interrogazioni private
su un insieme di dati [1].
6 Introduzione

1.1 SMC per problemi reali


Negli ultimi tempi la multy-party computation è entrata, in alcuni casi, a far parte
della vita quotidiana, ad esempio in Danimarca per l’asta delle barbabietole da
zucchero o in Estonia per le analisi di dati finanziari e le applicazioni sono in
crescita.

L’asta delle barbabietole da zucchero Uno dei primi esperimenti pratici della
secure multi-party computation è avvenuta in Danimarca nel 2008 [3] e consisteva
in un’asta di barbabietole da zucchero.
In Danimarca, diverse migliaia di agricoltori producono barbabietole da zuc-
chero, che poi vengono vendute alla società Danisco, l’unico processore di bar-
babietole da zucchero sul mercato danese. Quando l’Unione Europea ridusse
drasticamente il sostegno monetario per la produzione di barbabietola da zuc-
chero fu necessario ridefinire i contratti degli agricoltori tramite una doppia asta
a livello nazionale.
Per soddisfare tutte le parti, le offerte reali dovevano essere nascoste. Non
sarebbe stato accettabile per gli agricoltori se, per esempio, Danisco avesse agito
come unico banditore. Pertanto, la soluzione è stata quella di realizzare una dop-
pia asta elettronica utilizzando tre parti di calcolo multi-party, dove i partecipanti
al calcolo erano Danisco, DKS e il progetto SIMAP.
Nel sistema è stato configurato un server web per ricevere offerte e sono stati
istituiti tre server per effettuare il calcolo sicuro. Per inviare i dati, ogni parte-
cipante ha dovuto scaricare un programma sul proprio computer insieme alle
chiavi pubbliche dei server di calcolo. Le azioni segrete non sono state inviate
direttamente dai computer ai nodi di calcolo.
Ma ogni azione è stata cifrata con una chiave pubblica di uno dei nodi e poi
memorizzate nel database dal server web. In seguito il rappresentante di ciascuna
delle parti coinvolte ha fatto partire il calcolo inserendo la chiavetta USB, sulla
quale era stata conservata la chiave privata e inserendo la propria password sulla
propria macchina ed è stato così possibile ottenere il risultato dell’asta.

Analisi di dati finanziari Un’altra applicazione pratica che utilizza SMC è un


prototipo di sistema di reporting per un consorzio di imprese di tecnologie infor-
matiche situato in Estonia, l’Estonian Association of Information Technology and
Telecommunication o EAITL; questa associazione si occupa della raccolta dei dati
finanziari due volte l’anno per analizzare la situazione economica di un settore
industriale [4].
1.1 SMC per problemi reali 7

L’applicazione è stata già utilizzata più volte per raccogliere informazioni fi-
nanziarie. Per impedire che i dati raccolti siano accessibili al consiglio del EAITL,
in quanto ciò potrebbe ridurre il numero di aziende che accettano di sottopor-
re i propri dati, l’applicazione è stata costruita su tramite framework di Secure
Multi-party computation per garantire che i dati necessari per analisi, altamen-
te confidenziali, non possano essere divulgati. Questa è la prima applicazione
della SMC per calcoli su dati reali presenti su Internet con il calcolo di nodi di
computazione geograficamente sparsi.
Le aziende che ospitano i tre nodi di calcolo sono stati scelti dal consorzio EAI-
TL e comprendono Cybernetica, Microlink e Media Zone. Questi nodi sono stati
scelti poiché non hanno intenzione di coalizzarsi in quanto inseriscono i propri
dati confidenziali nel sistema e desiderano garantirne la privatezza.
I dati sono stati presentati attraverso un modulo di presentazione on-line che
è stato integrato nella pagina web del EAITL. I dati presentati sono stati segre-
tamente condivisi alla fonte e poi distribuiti tra le tre partiti di calcolo. Dopo
la scadenza, le parti di calcolo hanno iniziato dei protocolli di SMC e raccolto
tutti gli indicatori economici in modo indipendente. Poi gli indicatori sono stati
pubblicati nella board del EAITL come un foglio di calcolo anonimo e privo di
informazione di identificazione.
In un secondo periodo di raccolta, c’era anche un semplice sondaggio di feed-
back condotto tra i membri del consorzio, nel quale venivano chieste le motiva-
zioni ed i possibili problemi di privacy che essi ritenevano possibili nel partecipa-
re a questo sistema di raccolta dei dati. I risultati hanno mostrato che circa la metà
dei partecipanti si fidava poiché riteneva che il sistema fosse capace di preservare
la privatezza delle informazioni e dei dati immessi.

Questionario sulla soddisfazione dei dipendenti Una delle aziende del con-
sorzio EAITL citato prima, la Cybernetica AS ha usato anche un’applicazione
SMC per sottomettere agli impiegati un questionario sulla soddisfazione sul po-
sto lavorativo negli ultimi due anni.
Anche in questo caso è stato usato un framework per la secure multi-party
computation, poiché si voleva garantire che le risposte degli impiegati non ve-
nissero riportate a terze parti. Sono state scelte tre parti per la computazione tra
gli impiegati dell’azienda, in modo che non avessero intenzione di coalizzarsi e
garantissero, anche in questo caso i vincoli di privatezza dei propri dati.
I dati sono stati inviati tramite un formulario online che prevedeva una serie
di domande e le risposte segrete sono state salvate in tre differenti macchine che
8 Introduzione

agivano da nodi. Terminato il tempo, le parti della computazione hanno avviato


dei protocolli di SMC ed aggregato i dati che in seguito sono stati pubblicati senza
aggiungere alcuna informazione che permettesse l’identificazione.

1.2 Scopo del progetto


Lo scopo del progetto è quello di creare una piattaforma per il mobile, in parti-
colare per Android, sulla quale possano essere usati i protocolli di multi-party
computation. L’attuale versione si concentra sugli algoritmi proposti da Yao per
risolvere il problema del milionario nella versione a due parti ed il problema di
votazione di un candidato, ovvero un protocollo ad n parti.
Oltre ad Android si è anche deciso di usare una nuova tecnologia per le co-
municazioni tra dispositivi, denominata Wi-Fi Direct. Wi-Fi Direct permette la
comunicazione di utenti facenti parte di un gruppo su una rete priva di un punto
di accesso, questo semplifica il compito di usare l’applicazione, sia perché non è
necessario configurare la rete (come gli indirizzi IP o gli hostname dei dispositi-
vi) per effettuare scambi di dati, sia perché in qualsiasi posto ci si trovi è possibile
connettere tra loro un insieme di dispositivi.
L’obiettivo di questa tesi è quello di portare degli algoritmi spiegati spesso in
modo molto teorico su una piattaforma di uso comune come può essere Android
e quindi permettere a chi si avvicina per la prima volta alla SMC di provare in
prima persona alcuni protocolli e verificarne l’efficacia.
L’applicazione permette di costruire gruppi virtuali di utenti che vogliano par-
tecipare ad uno dei due protocolli di SMC implementati. In seguito è possibile
scegliere uno dei protocolli supportati, ovvero determinazione del più ricco tra
due milionari o votazione di un candidato e infine immettere i propri dati per il
protocollo scelto (che non verranno comunicati agli altri) ed attendere il risultato
della computazione che compare a video alla fine dell’esecuzione del protocollo.

1.3 Struttura della tesi


La tesi è strutturata in quattro parti fondamentali: la prima presenta le defini-
zioni e lo stato dell’arte della SMC, la seconda è dedicata agli algoritmi pre-
sentati da Yao nella sua prima trattazione del problema del milionario, la terza
all’architettura dell’applicazione e la quarta alla sua implementazione.
1.3 Struttura della tesi 9

Nella prima parte o capitolo 2, viene presentata un’anteprima sulla SMC, in


questa sezione vengono esplicate le proprietà che si vogliono rispettare nelle com-
putazioni sicure come la privacy degli input e la correttezza del protocollo in caso
di situazioni non ideali come le situazioni di attacco.
Vengono anche introdotti i tipi di attaccanti, o meglio di avversari, come l’av-
versario semi-onesto, disposto ad effettuare attacchi passivi, cercando di carpire
informazioni che non lo riguardano e l’avversario malizioso pronto a modificare
il flusso del protocollo attivamente per modificare il risultato della computazione.
In questo capitolo di presentazione vengono anche definiti concetti di base
come l’oblivious transfer usato per la trasmissione di segreti tra utenti che non
vogliono svelare nulla relativamente a tali segreti, ma desiderano determinare se
le informazioni delicate di cui sono in possesso sono note o sconosciute ad altri
utenti.
In seguito sono spiegati i circuiti garbled, utili per valutare funzioni in modo
sicuro tra più parti mantenendo i vincoli sulla privatezza, viene anche fatto un
esempio su come costruirli ed usarli insieme agli oblivious protocols per valutare
funzioni in modo sicuro.
Il protocollo di Yao per la soluzione del problema del milionario è un caso
particolare di soluzione di una funzione tramite questa tipologia di circuiti.
Nelle parti successive di questo capitolo sono spiegate, in modo molto ge-
nerale, la Secure Two-Party computation e Multi-Party computation, insieme ad
alcune soluzioni pratiche proposte negli ultimi anni tra cui spiccano delle solu-
zioni generiche, ad esempio i compilatori di circuiti che, a partire da una funzio-
ne descritta in linguaggi appositi, costruisce un circuito che può essere inviato e
valutato da terze parti, i cosiddetti valutatori.
Il capitolo 3 è dedicato a due protocolli famosi nella Secure Multi-party Com-
putation. Il primo protocollo suggerisce una soluzione al problema del miliona-
rio: si vuole determinare quale tra due milionari è il più ricco senza che nessuno
dei due esprima la propria ricchezza.
Il secondo protocollo si occupa del problema di votazione di un candidato, da-
to un insieme di votanti ed uno di candidati, si vuole permettere ad ogni votante
di votare per un candidato senza che nessun altro votante venga a conoscenza
del voto espresso, lo scopo finale è quello di ottenere il totale dei voti espressi per
ciascun candidato.
In questa sezione i due protocolli sono espressi formalmente e vengono mo-
strati degli esempi di funzionamento passo per passo.
I capitoli 4 e 5 della tesi contengono le informazioni legate direttamente al
10 Introduzione

progetto: viene presentata inizialmente l’architettura ad alto livello, quindi la


rete e la struttura dei dati che vengono scambiati tra i dispositivi, in seguito è
descritta l’organizzazione del codice, diviso tra codice che permette di gestire
l’interfaccia utente, codice che gestisce lo scambio di dati tra dispositivi e quello
che implementa i protocolli SMC mostrati nel capitolo precedente.
Il capitolo 5 chiarifica le scelte di implementazione e le tecnologie che sono sta-
te usate per sviluppare il progetto, le strategie di testing e le prestazioni dell’ap-
plicazione. Infine viene descritto il funzionamento dell’applicazione dal punto di
vista dell’utente.
Al termine di questi quattro capitoli principali è presente la conclusione della
tesi con i possibili sviluppi futuri.
Capitolo 2

Secure Multi-party Computation

La Secure multi-party computation ha come scopo quello di creare protocolli che


servono a computare una funzione f (x, y, · · · ) dipendente dagli input di varie
parti, senza che siano rivelati x, y, · · · o altre informazioni che possano aiutare a
rivelare le informazioni su x, y, · · · .

2.1 Definizioni generali


Nella SMC dato un numero di partecipanti p1 , p2 , . . . , pn ciascuno con un dato pri-
vato d1 , d2 , . . . , dn . Si vuole che i partecipanti computino il valore di una funzione
pubblica su tali dati privati f (d1 , d2 , . . . , dn ) tenendo il loro input di segreto.
Le due proprietà principali sono:

• Privacy degli input nessuna informazione relativa ai dati privati detenu-


ti dalle parti può essere dedotta dai messaggi inviati durante l’esecuzione
del protocollo. Le uniche informazioni che si possono dedurre sui dati pri-
vati sono quelle che si potrebbero ottenere osservando solo l’output della
funzione.

• Correttezza qualsiasi sottoinsieme proprio di parti che decidono di coaliz-


zarsi in modo da condividere informazioni o deviare il flusso del proto-
collo durante l’esecuzione del protocollo non dovrebbe essere in grado di
costringere parti oneste a emettere un risultato errato.

Questo obiettivo di correttezza si può considerare in due versione: un pro-


tocollo robusto riesce a calcolare un output corretto e garantendo ad ogni
passaggio il mantenimento della correttezza, un protocollo ad uscita preve-
12 Secure Multi-party Computation

de invece di terminare con errore se si verifica una corruzione del protocollo


in qualche fase.

Considerando che in SMC non è presente una parte fidata che esegue il com-
pito di calcolare una funzione per un certo numero di parti, la definizione di
avversario al protocollo diverge molto: poiché i dati sono scambiati solo tra i
partecipanti ad un protocollo, l’avversario deve essere uno dei partecipanti.
In SMC si assume che le parti corrotte possano coalizzarsi per infrangere il
protocollo, se il numero delle parti del protocollo è n allora il numero delle parti
di avversari è denotato con t.
I protocolli e le soluzioni nel caso t < n/2 quando la maggioranza delle par-
ti è onesta prevede soluzioni molto più semplici di quelle in cui non viene fatta
questa assunzione. Quest’ultimo caso include la two-party computation dove
basta che uno solo dei due partecipanti sia corrotto e più in generale il caso in
cui ci sono un numero illimitato di partecipanti corrotti che si coalizzano per col-
pire qualche partecipante onesto. Gli avversari sono suddivisi rispetto a come
infrangono il protocollo:

• Semi-Honest detto anche passivo o partecipante curioso prevede una par-


te che coopera con altre parti per ottenere più informazioni ma non devia
attivamente dal protocollo.

I protocolli che prevedono parti semi oneste prevengono la perdita acci-


dentale di informazioni tra le parti e sono utili se l’obiettivo che si vuole
raggiungere è questo, inoltre tali protocolli sono molto efficienti e si posso-
no combinare con tecniche di cifratura per raggiungere livelli di sicurezza
più elevati.

• Malicious detto anche attivo è un partecipante che modifica il flusso del


protocollo manipolando i dati nel tentativo di imbrogliare oppure o di otte-
nere informazioni che non gli spettano. Alcuni protocolli che prevedono un
livello di sicurezza molto alto permettono di non avere utenti maliziosi e in
caso si verifichi un attacco attivo in cui il protocollo viene infranto da una
maggioranza di utenti disonesti tali protocolli terminano con errore.

I protocolli di SMC si possono suddividere in Two-Party in cui il numero di


partecipanti è due ed in Multi-party in cui il numero di partecipanti è maggiore
di due, in generale un protocollo di tipo Multi-party non è intercambiabile con
un Two Party, in quanto le tipologie di algoritmi sono molto diverse.
2.2 Oblivious Transfer 13

2.2 Oblivious Transfer


I protocolli di Oblivious Transfer [8] vengono usati per la trasmissione di messag-
gi segreti tra utenti. Supponendo che una persona abbia un segreto ma non possa
rivelarlo totalmente e nemmeno in parte, ci si trova nel caso ideale per l’utilizzo
di un dei protocolli di trasferimento oblivi, tali protocolli consentono al ricevente
di decifrare i messaggi in diverse modalità, le principali sono:

1
• Il destinatario riesce a decifrare ogni messaggio con probabilità 2
e il mit-
tente non sa se il destinatario li ha decifrati o no.

• Il destinatario riesce a decifrare uno dei messaggi che il mittente ha inviato e


il mittente non sa quale messaggio inviato è stato decifrato dal destinatario.

I protocolli che consentono questi tipi di trasmissione sono principalmente: Obli-


vious con probabilità 21 e Oblivious transfer 1 su 2 e corrispondono alle modalità
elencate sopra.

1
2.2.1 Oblivious transfer con probabilità 2

Siano Alice e Bob due utenti, Alice possiede un segreto S. Con questo protocollo
Bob computa S con probabilità 12 e Alice non sa se Bob ha calcolato S. Le fasi di
tale protocollo prevedono i seguenti passi:

1. Alice calcola un intero n come prodotto di due numeri primi n = pq e lo


invia a Bob.

2. Bob calcola un valore casuale r ∈ Zn∗ . In seguito calcola x = r2 e lo invia ad


Alice.

3. Alice conoscendo p e q può valutare le quattro radici di x e scegliere w tale


che w2 = x mod n, in seguito invia questo w a Bob.

Poiché un quadrato modulo n ha quattro radici, supponendo che esse siano r,


n − r, u e n − u, allora

• Se w = r oppure w = n − r, Bob non ottiene nessuna informazione

• Nel caso in cui w = u o w = n − u, Bob viene a verrà a conoscenza delle


quattro radici.
14 Secure Multi-party Computation

Nel secondo caso Bob può fattorizzare n, Alice dovrebbe quindi mandare S a Bob
in maniera oblivia usando questo protocollo ed usando n.
In realtà Alice manda a Bob il valore cifrato di S usando n prima dell’inizio
del protocollo. L’ideale sarebbe effettuare un passo in più prima di cominciare il
protocollo, Alice dovrebbe cifrare con n il messaggio segreto S e inviarlo a Bob,
se Bob riesce a fattorizzare n decifra il messaggio S altrimenti no.
Usando sistemi di cifratura come RSA è possibile immaginare che y = S e mod
n ed S = y d mod n quindi se Bob fattorizza n calcola d ed ottiene S.

2.2.2 Oblivious transfer 1 su 2


In questo caso Alice trasmette un gruppo di messaggi a Bob, Bob riceve solo un
sottoinsieme di questi messaggi ed Alice non sa quale sia questo sottoinsieme,
cioè non sa quali sono i messaggi effettivamente ricevuti da Bob tra quelli che lei
ha inviato.
Supponendo che ci siano due utenti Alice e Bob, Alice possiede due segreti
S1 ed S2 si vuole che alla fine del protocollo Bob riesca a conoscere uno dei due
segreti e che Alice non sappia quale dei due segreti Bob ha scoperto.
Questo protocollo di oblivious transfer è definito come segue:

1. Alice genera due coppie di chiavi pubbliche e private (E, D) e (E 0 , D0 ) poi


manda a Bob le chiavi di cifratura E ed E 0 .

2. Bob crea una chiave k e sceglie casualmente una delle due chiavi pubbliche
di Alice.

3. Bob calcola un valore y che consiste nella cifratura della chiave k cifrata con
la chiave scelta precedentemente, quindi y = E(k) o y = E 0 (k) ed invia y ad
Alice non rivelando quale chiave di cifratura ha usato.

4. Alice riceve y ma non sa se è stato ottenuto usando E o E 0 . Non avendo


informazioni sul valore di y, Alice prova a decifrare il messaggio ricevuto
con entrambe le chiavi di decifratura, quindi ottiene k1 = D(y) e k2 = D0 (y).

5. Alice invia a Bob due valori calcolati come la somma tra i segreti e le chiavi
corrispondenti: k1 ⊕ S1 e k2 ⊕ S2 .

6. Bob riesce a conoscere solo uno dei due messaggi (cifrato con la sua chiave
k) poiché se k = k1 allora recupera il messaggio S1 , altrimenti è k = k2 e
quindi recupera S2 ma non può conoscerli entrambi.
2.3 Garbled Circuits 15

Per verificare che Alice e Bob si siano comportati in modo corretto è necessario
che essi svelino i loro segreti S1 ed S2 usati durante il protocollo e gli algoritmi di
decifratura. In alternativa è possibile usare prove a conoscenza zero [10].
Il protocollo protegge da attacchi da parte di Alice, in quanto Alice non cono-
sce la chiave k usata da Bob per costruire y. Alice può risalire alle due chiavi k1 e
k2 una delle due è la chiave k usata da Bob ma non si sa quale delle due.
Il protocollo è anche sicuro contro un attacco di Bob, poiché egli potrebbe
rompere il protocollo solo se conoscesse le chiavi private di Alice.

2.3 Garbled Circuits


Il protocollo di Yao per costruire circuiti garbled prevede di trasformare qualsiasi
funzione in una funzione che possa essere valutata in modo sicuro tramite la mo-
dellazione di tale funzione in un circuito booleano e l’offuscamento degli input e
degli output di ogni porta logica.
In questo modo le parti che eseguono tale funzione non possono discernere
nessuna informazione sugli input dei valori intermedi della funzione.
Con il tempo sono state proposte numerose idee con spiegazioni su come im-
plementarle e modi per ottimizzarle [11]. La costruzione e l’utilizzo di questo ge-
nere di circuiti in versione semplificata risulta piuttosto interessante ed è spiegato
in seguito.

2.3.1 Costruzione di un circuito


Sia n un parametro sicuro e sia f (x1 , · · · , xa ; y1 , · · · yb ) una funzione che Alice e
Bob vogliono computare con xi input di Alice e yj input di Bob e sia f computa-
bile. La costruzione di un garbled circuit prevede diverse fasi:

Hard-coding Prima di effettuare una valutazione sicura di una funzione f que-


sta deve essere convertita in un circuito booleano c corrispondente in modo che
una funzione f (x, y) = c(x, y) per ogni x ed y (da notare che si può estendere que-
sto compito a funzioni con più di due input cioè f (x1 , · · · , xa ; y1 , · · · yb )). È stato
dimostrato che è sempre possibile effettuare questa operazione [7].
Si assume senza perdita di generalità che ogni porta logica richieda due fili
come input ed abbia un filo di uscita e che se un filo si dirama per fornire un
input a più porte logiche questo sia considerato come filo unico.
16 Secure Multi-party Computation

Costruzione del garbled circuit Dopo che Alice ha costruito un circuito c che
altro non è che una rappresentazione diversa di f . Lo step successivo consiste
nella costruzione di una tabella di verità garbled, in cui per ogni porta logica in c,
si genera una versione garbled in cg .
Per ogni filo wi del circuito, Alice crea due chiavi casuali Ki0 , Ki1 di lunghezza
n. L’idea è che Ki0 corrisponderà al filo wi al quale viene assegnato un valore pari
a 0, la stessa cosa accadrà a Ki1

wi
cz wk
wj

Garbling di una singola porta Per capire meglio come avviene questa operazio-
ne è possibile fare un esempio e trasformare una porta OR che sarà denominata
cOR
1 nella sua versione garbled g1OR , effettuando le seguenti operazioni:

1. Per prima cosa Alice genera i valori per questa porta logica e costruisce la
tavola di verità di c.

w0 w1 w2
0 0 0 w0
0 1 1 c1 w2
1 0 1
w1
1 1 1

2. Alice genera una chiave per ogni possibile valore della porta logica. Con
questa operazione vengono generate sei chiavi: una per ogni coppia di
booleani, per ciascuno dei tre fili del gate (i due input e l’output).

w0 w1 w2
k00 k10 k20
K0 g1 k00 , k10 g1
k00 k11 k21 K 2 k02 , k12
K1 k01 , k11
k01 k10 k21
k01 k11 k21
2.3 Garbled Circuits 17

3. A questo punto Alice cifra ogni valore di output della tabella di verità con
le chiavi usate per i corrispettivi input.
L’identificatore della porta logica serve solo come nonce ed è incluso nella
costruzione per essere sicuri che valori uguali non siano mai cifrati nello
stesso modo all’interno del circuito.

w0 w1 w2 valori garbled
k00 k10 k20 H(k00 ||k10 ||g1 ) ⊕ k20
k00 k11 k21 H(k00 ||k11 ||g1 ) ⊕ k21
k01 k10 k21 H(k01 ||k10 ||g1 ) ⊕ k21
k01 k11 k21 H(k01 ||k11 ||g1 ) ⊕ k21

4. In seguito Alice riordina in modo casuale le linee della tabella in modo


da non facilitare il compito di ricostruire la tabella e permettere a Bob di
scoprire informazioni segrete.

Il lavoro effettuato sulla prima porta logica va ripetuto in seguito su tutte le altre
porte, le uniche porte logiche che non devono essere modificate in porte garbled
sono quelle di output e quelle i cui fili di output non sono input di altre porte.

Ruolo della cifratura La cifratura copre due ruoli importanti nel protocollo.
Poiché l’output di ogni operazione di cifratura è un valore casuale (si assume che
il risultato della funzione di hash sia casuale anche se in realtà è pseudo-casuale),
tutte le correlazioni che potevano esserci tra i valori della tavola di verità origi-
nale e quella garbled non esistono più. Bob può ottenere solo una delle chiavi di
output della tavola poiché egli possiede solo la chiave per decifrare un singolo
valore del filo di output.

Invio dei valori garbled Quando Alice ha finito di generare il circuito garbled,
deve effettuare un garbling degli input della funzione, creando una mappa iA tra i
valori di input originali e quelli appena generati. Alice effettua questa operazione
rimpiazzando il primo bit dei suoi input con la chiave corrispondente al filo di
input nel circuito.

Trasferimento con oblivious transfer delle chiavi Un ostacolo in questo pro-


tocollo si trova nella fase iniziale: al fine di avviare l’esecuzione del programma,
Bob ha bisogno di fornire le chiavi iniziali di input per valutare le porte logiche
che ha ricevuto.
18 Secure Multi-party Computation

Ma Bob non può vedere nessuna chiave eccetto quelle di cui ha bisogno,
perché altrimenti avrebbe troppe informazioni sull’esecuzione del programma
e quindi più informazioni sugli input di Alice. Inoltre Alice non deve poter sco-
prire quali chiavi di input riceverà Bob, per essere lei conoscerà solo quali sono i
valori di input.
Questa situazione è risolvibile tramite un protocollo per un oblivious trans-
fer, pertanto Alice configura il trasferimento, tramite un oblivious protocol, delle
chiavi di input a Bob. Bob riceve una sola chiave per ogni filo corrispondente al
suo input, senza che Alice sappia qual è stata la sua scelta. Infine Bob inizia la
procedura utilizzando le tabelle delle porte fornite da Alice.
Una volta che Bob ha effettuato la computazione, possiede una chiave finale
K che invia ad Alice, che può comprendere se K corrisponde ad un output di 0 o
1.

2.4 Two Party Computation


La computazione sicura a due parti è particolarmente interessante, non solo per le
prospettive applicative ma anche perché possono essere applicate delle tecniche
speciali che nella versione a parti multiple non è possibile usare.
La SMC che prevede la valutazione sicura di funzioni singole e due soli parte-
cipanti è stata presentata per la prima volta da Andrew Yao insieme al problema
del milionario.
Il protocollo di Yao è sicuro contro gli avversari semi-onesti ed è estremamente
efficiente in termini di numero di round (che è costante) ed è indipendente dalla
funzione valutata.
La funzione viene infatti vista come un circuito booleano in cui gli input so-
no binari e di lunghezza fissa. Tale circuito booleano è una collezione di porte
collegate con tre tipi di fili: input del circuito, output del circuito e fili intermedi.
Ogni porta riceve due fili di input e prevede un singolo output che può essere
passato a porte multiple nel livello successivo del circuito. La valutazione del
circuito è effettuata a turno su ogni porta, assumendo che le porte siano ordinate
lessicograficamente.
La porta rappresenta una tavola logica di verità, in modo che per ogni pos-
sibile insieme di bit che vengono immessi come input la tavola assegni un unica
possibile combinazione di bit in output che è il valore del output di una porta
logica. Il risultato della valutazione dei bit è ottenuto leggendo gli output del
circuito.
2.4 Two Party Computation 19

Nella sezione precedente è stato mostrato come ottenere un circuito nascon-


dendone la struttura in modo che i due partecipanti possano conoscere solo l’out-
put di questo circuito e non possano ottenere nessun’altra informazione.
Volendo fare una considerazione ad alto livello, in cui si suppone che il cir-
cuito sia già stato costruito, si può pensare che il mittente prepari il circuito e lo
invii al destinatario che valuta il circuito conoscendo la codifica che corrisponde
all’output di entrambe le parti (mittente e destinatario).
Poi invia al mittente un’altra codifica che permette al mittente di computare
la sua parte di output. Il mittente invia la mappa degli input ricevuti in output
codificati in forma di bit al destinatario permettendo ad esso di ottenere il suo
output.
In dettaglio il garbled circuit è costruito usando uno schema a doppia chiave
simmetrica, data una porta di un circuito, tutti i suoi possibili valori di input e
output sono codificati con un numero casuale (etichetta).
I valori risultanti dalla valutazione della porta logica per ciascuna delle quat-
tro possibili paia di bit di input sono rimpiazzati con etichette casuali. La tabella
di verità delle porte consiste nella cifratura di ogni etichetta di output usando le
etichette in input come chiave.
Le posizioni di queste quattro cifrature nella tabella di verità sono randomiz-
zate quindi non viene comunicata nessuna informazione sensibile. Per valutare
correttamente ogni porta, lo schema di cifratura deve avere due proprietà:

1. Gli intervalli della funzione crittografica in nessuna delle due chiavi posso-
no essere disgiunti.

2. Deve essere possibile effettuare un controllo efficiente dato un contenuto


cifrato e una determinata chiave.

Con queste due proprietà il destinatario, dopo aver ottenuto le etichette per cia-
scun filo di input può valutare ogni porta logica cercando di trovare quale dei
quattro contenuti cifrati è stato cifrato con le sue chiavi etichetta e a quel punto
decifrare tale testo per ottenere l’etichetta del filo di output.
Questo viene fatto ignorando ciò che il destinatario ha appreso durante la
valutazione delle codifiche dei bit. I bit in input del mittente, colui che ha creato
il circuito, possono essere inviati codificati al valutatore del circuito, poiché la
codifica corrispondente ai bit di input del destinatario (valutatore del circuito)
viene ottenuta tramite un protocollo Oblivious Transfer 1 su 2.
Un protocollo di questo tipo permette al mittente in possesso di due valori C1
e C2 di inviare il valore richiesto dal destinatario (un valore in {1, 2}), in questo
20 Secure Multi-party Computation

modo il mittente non sa quale valore è stato trasferito e il destinatario apprende


solo il valore richiesto. Bisogna in ogni caso tenere conto che se una delle parti
non è onesta, essa potrebbe costruire un circuito "malizioso" che riveli l’input
dell’altro utente.

2.5 Multi-party computation


A differenza dei protocolli per la computazione con due parti, la maggior parte
dei protocolli con tre o più partecipanti fanno uso della condivisione di un segreto
o secret sharing [13].
Nei metodi basati sulla condivisione di un segreto le parti della computazione
non hanno ruoli particolari, come invece capita nella Two-party computation in
cui si hanno un creatore del circuito ed un valutatore del circuito.
I dati associati ad ogni filo sono condivisi tra le parti, in seguito un protocollo
viene usato per valutare ogni porta logica. Il circuito risultante viene chiamato
circuito aritmetico poiché consiste di porte di addizione e porte di moltiplicazione
in cui si opera su valori che hanno come dominio GF (p). Dove GF è un campo
di Galois (Galois Field) o campo finito su un primo p che corrisponde all’insieme
degli interi modulo p.
Lo secret sharing permette di distribuire un segreto tra un certo numero di
parti, dando ad ogni parte un compito da eseguire. Nella SMC sono usati tre tipi
di schemi di secret sharing:

• Secret sharing di Shamir

• Secret sharing replicato

• Secret sharing additivo

In tutti e tre i casi, i valori dei compiti di ogni parte sono elementi casuali in GF (p)
che si sommano al segreto in GF (p).
Ogni set di condivisioni non qualificato appare distribuito in modo casuale.
Tutti e tre gli schemi sono lineari, quindi la somma dei segreti di due parti o
la moltiplicazione di un segreto per una costante può essere fatto localmente e le
funzioni lineari possono essere, in seguito, valutate liberamente. Questo spalanca
le porte a innumerevoli problemi di sicurezza.
Il secret sharing di Shamir è uno dei primi schemi a soglia (threshold systems
[15]) per la condivisione di segreti, esso si basa sull’interpolazione polinomiale ed
è definito da una coppia di valori (t, n) dove n è il numero totale di partecipanti
2.6 Protocolli generici basati sui circuiti 21

e t è il numero di partecipanti necessari per ricostruire il segreto. A causa della


definizione stessa di schema a soglia, esso tollera un numero di avversari pari
t su n. Con l’uso della condivisione del segreto di Shamir è possibile creare un
protocollo attivamente sicuro se t < n/3 ed uno passivamente sicuro con t < n/2.
Nel caso di protocolli computazionalmente sicuri si può tollerare una soglia
di t < n/2 ed ottenere comunque una sicurezza attiva. Un sistema che usa questo
schema è il framework VIFF [18].
L’uso di schemi di secret sharing replicato è di solito associato ai sistemi di
multi-party computation passivamente sicuri (solo partecipanti curiosi o semi-
onesti) in genere composti da tre parti di cui una sola è un avversario. Tale
schema viene usato nel sistema Sharemind [14].
Lo secret sharing additivo tollera una maggioranza di parti disoneste, cioè
t < n, in questo caso si ha un protocollo MPC con abort.
Tale schema è usato da SPDZ (Smart Pastro Damgård Zakarias) [16] e dalla
versione estesa di TinyOT [17].

2.6 Protocolli generici basati sui circuiti


Volendo valutare in modo sicuro una funzione è necessario trasformarla in un
circuito formato da porte logiche di tipo XOR ed AND, spesso queste funzio-
ni consistono in algoritmi complessi formati da condizioni if e loop, quindi la
costruzione del circuito non è così immediata. Per risolvere questo problema è
stato creato un sistema denominato Fairplay [20] formato da due componenti:
una componente detta compilatore costruisce un circuito booleano a partire da
un codice ad alto livello, la seconda componente costruisce il circuito garbled ed
esegue il protocollo per valutare in modo sicuro il circuito appena generato. In
seguito è stata presentata anche una versione multi-party che usa BMR (Beaver
Micali Rogaway), protocollo che consiste nella versione sicura, a più parti del
protocollo di Yao.
In seguito sono stati creati ulteriori migliorie alle tecniche proposte da Yao,
queste possono ottimizzare i tempi di computazione, è il caso del metodo degli
XOR liberi che permette una valutazione più semplice delle porte logiche di tipo
XOR, costruendo delle tavole garbled di dimensione minore.
Ma anche di ottimizzare la sicurezza creando un protocollo a due parti che
funziona in caso di avversari maliziosi come nel caso della tecnica usata da Lin-
dell e Pinkas [19].
22 Secure Multi-party Computation

Anche come aspetto hardware si è cercato di ottimizzare la creazione di cir-


cuiti usando programmi che usano funzionalità particolari delle GPU [22].
Capitolo 3

Due protocolli per la Secure


Multi-party Computation

3.1 Protocollo del milionario


Questo protocollo deriva dal problema del milionario di Yao [12] chiamato così
in quanto permette di stabilire, chi tra i due milionari è il più ricco, senza che
nessuno dei due riveli a quanto ammonta la propria ricchezza.

3.1.1 Definizione del protocollo

Sia Ra la ricchezza di Alice ed Rb la ricchezza di Bob. Alice e Bob desiderano


conoscere se Ra ≤ Rb oppure se Ra > Rb .
Assumendo Ra , Rb ≤ 100 e che Bob abbia una chiave privata ed una pubblica.

1. Alice sceglie un numero casuale x abbastanza grande e lo cifra con la chiave


pubblica di Bob c = Eb (x), in seguito calcola V ala = c − Ra e manda tale
valore a Bob.

2. Bob computa i seguenti 100 numeri:

u ∈ N, 1 ≤ u ≤ 100 : yu = Db (V ala + u)

dove Db è l’algoritmo di de-cifratura che utilizza la chiave privata di Bob.


24 Due protocolli per la Secure Multi-party Computation

In seguito sceglie un primo p grande in maniera casuale e computa i seguen-


ti 100 numeri:

u ∈ N, 1 ≤ u ≤ 100 : zu = yu (mod p)

poi verifica che per ogni zu 6= zv e 0 < zu < (p − 1) si ha che:

|zu − zv | ≥ 2

Se ciò non è vero allora Bob sceglie un altro primo p e ricomincia.

Alla fine Bob manda ad Alice questi numeri in questo esatto ordine:

z1 , z2 , . . . , zRb , zRb +1 + 1, zRb +2 + 1, . . . , z100 + 1, p

3. Alice controlla se il numero zRa in posizione Ra rispetta la congruenza con


p. Se zRa = x(mod p) è verificato, allora Ra ≤ Rb altrimenti Rb > Ra . Alice
comunica il risultato a Bob.

4. Bob conosce il risultato.

3.1.2 Esempio di utilizzo

Sia la ricchezza di Alice Ra = 4 e la ricchezza di Bob Rb = 2. Fissata la massima


ricchezza a 4 e supponendo di utilizzare come algoritmo di cifratura RSA e chiave
pubblica di Bob 7 e chiave privata 23.

1. Alice sceglie x=39 e calcola c = EB (39) = 19 e computa c − Ra = 19 − 4 = 15


e lo spedisce a Bob.

2. Bob computa i 4 valori seguenti:

y1 = DB (15 + 1) = 26
y2 = DB (15 + 2) = 18
y3 = DB (15 + 3) = 2
y4 = DB (15 + 4) = 39
3.2 Votazione di un candidato 25

Poi Bob sceglie un primo p = 31 e calcola altri 4 valori:

z1 = 26(mod 31) = 26
z2 = 18(mod 31) = 18
z3 = 2(mod 31) = 2
z4 = 39(mod 31) = 8

In seguito verifica che la sequenza sia corretta e spedisce ad Alice la sequen-


za ottenuta Z = {26, 18, 2 + 1, 8 + 1, 31}

3. Alice controlla se il numero in posizione Ra cioè ZRa verifica l’ipotesi di


congruenza. Visto che 9 = 39 mod 31 è falso, allora Ra > Rb

3.2 Votazione di un candidato

3.2.1 Algoritmo di votazione


Supponendo che per le elezioni vi siano n candidati C = {c1 , c2 , · · · , cn } e m
votanti V = {v1 , v2 , · · · , vm }, il protocollo è definito come segue:

1. Viene scelto un numero primo p maggiore del numero degli utenti della
rete.

2. v1 il primo votante sceglie a caso n valori iniziali R = {r1 , r2 , · · · , rn } ∈ Zp .


Dove ri è il contatore dei voti di ci , quindi esiste un valore casuale in R per
ogni candidato.
In seguito v1 invia a v2 la lista dei valori iniziali R.

3. v2 incrementerà il valore di un elemento in R seguendo le sue preferenze


presenti nella lista dei candidati. Quindi se intende votare ck allora ver-
rà incrementato rk cioè l’elemento che possiede lo stesso indice. Succes-
sivamente v2 invierà ad v3 la lista dei valori R1 aggiornata con il proprio
voto.

4. la lista con le preferenze di voto R viene modificata e passata avanti da


un votante all’altro fino ad arrivare a vm . a questo punto la lista di valori
viene ripassata a v1 che esprimerà il suo voto e poi sottrarrà ai valori in Rm ,
i valori casuali scelti nella prima fase cioè R, ottenendo quindi il risultato
della votazione.
26 Due protocolli per la Secure Multi-party Computation

5. tale risultato della votazione viene infine propagato a tutti i votanti

In questo protocollo le comunicazioni tra gli utenti sono cifrate e quindi ogni
utente non vede ciò che è stato mandato agli altri utenti.
Si possono verificare le diverse situazioni in base ai due tipi di utenti:

• Utenti onesti (cioè seguono il protocollo), ma curiosi (vogliono scoprire il


voto degli altri).

• Utenti non onesti.

Nel primo caso supponendo che gli utenti non possono collaborare tra di loro e
che il votante curioso sia l’utente v3 . v3 non potrà sapere niente circa il voto degli
altri in quanto i voti che vede v3 sono mascherati dai valori iniziali in R scelti
a caso quindi non ha informazioni sul voto espresso dagli utenti precedenti, il
protocollo va bene se il votante curioso è unico.
Se i votanti curiosi sono più di uno allora è possibile ottenere qualche infor-
mazione. Supponendo, ad esempio, di avere 3 votanti indicati come v1 , v2 , v3 se
v3 ed v1 si uniscono possono scoprire il voto di v2 .
Inoltre può anche accadere che se il votante che fornisce agli altri votanti il
risultato dell’elezione (nell’esempio v1 ) non è onesto può fornire un valore di-
verso dal reale risultato dell’elezione. Questo problema può essere risolto obbli-
gando l’utente in questione a fornire una dimostrazione sulla sua correttezza, ad
esempio utilizzando una prova di tipo a conoscenza zero:

• v2 riceve Cv2 (R) cioè un array in cui tutti i valori di R sono cifrati con la sua
chiave pubblica, modifica uno dei valori di R e rimanda R1 = {r1 , r2 , . . . , ri +
1, . . . , rn }

• v3 riceve Cv3 (R1 ) cioè l’array R modificato da v2 con la sua votazione dive-
nuto R1 e poi cifrato con la chiave pubblica di v3 .

• v2 può quindi verificare che dato che v3 cifra un array di valori Cv2 (R1 ) in
cui solo uno dei valori presenti in R1 può essere cambiato il che dimostra
che l’array è stato modificato in maniera corretta.

Questa affermazione è verificabile, se è nota la chiave privata di v2 , si valutano


i valori in R1 e data la chiave privata di v3 , si verifica quale dei valori presenti
in R è stato incrementato. Quindi si può verificare se v2 ha agito correttamente
o meno. Ogni votante a turno può provare agli altri che sta agendo in maniera
corretta usando tale sistema. Quindi il protocollo soddisfa le seguenti proprietà:
3.2 Votazione di un candidato 27

1. Gli utenti non possono imbrogliare.

2. Due o più votanti curiosi riescono a scoprire i voti espressi dagli altri votan-
ti.

3.2.2 Esempio di utilizzo


Supponiamo che ci siano 3 candidati C = {c1 , c2 , c3 } e 4 votanti V = {v1 , v2 , v3 , v4 }.

• Si sceglie come primo p maggiore nel numero dei votanti (m) il numero 17.

• il primo votante v1 costruisce R = {14, 3, 1}, una lista di numeri casuali


inferiori a p, la memorizza e la invia a v2 .

• v2 esprime il suo voto incrementando R allo stesso indice del candidato,


volendo votare c3 si avrà R1 = {14, 3, 2}.

• v3 vuole votare per c1 e crea R2 = {15, 3, 2} che in seguito manda a v4 .

• v4 vota per c3 modifica R2 che diventa R3 = {15, 3, 3} e manda a v1 tale lista.

• v1 aggiunge il suo voto per c2 ed ottiene R4 = {15, 4, 3}, sottrae quindi R ad


R4 ottenendo R4 − R = {1, 1, 2}. Quindi c’è un voto per c1 , un voto per c2 e
due voti per c3 .

• v1 propaga il risultato dell’elezione R4 − R a tutti i votanti.


28 Due protocolli per la Secure Multi-party Computation
Capitolo 4

Architettura dell’applicazione

4.1 Struttura generale


L’architettura dell’applicazione è molto simile alla classica architettura client-server:
infatti è previsto che uno dei dispositivi assuma il ruolo di group-owner, ovvero
proprietario del gruppo, e decida chi far partecipare o meno alla computazione.
Gli altri partecipanti alla comunicazione prendono il nome di peer ed a seconda
del protocollo scelto possono essere uno o più. In questo senso il group-owner
può essere considerato il server mentre gli altri partecipanti come client.

Group-owner

Peer1 Peer2 Peer3 Peern

Il group-owner oltre ad avere il ruolo di creatore del gruppo di computazio-


ne, avrà anche altre responsabilità come quella di essere il primo dispositivo a
cominciare il protocollo di secure multi-party computation. Altri compiti che
spettano al group-owner sono legati alla sincronizzazione dei vari dispositivi e
nei protocolli di SMC che prevedono una struttura di comunicazione ad anello,
egli si occuperà anche di effettuare l’inoltro dei dati ricevuti da un dispositivo per
inviarli al dispositivo destinatario.
Benché l’architettura preveda due ruoli distinti, qualsiasi dispositivo quan-
do avvia l’applicazione può decidere se avviare un’istanza da group-owner o da
peer semplice. Se viene avviata un’istanza da group-owner verrà messo a dispo-
sizione un servizio sulla rete cercabile da qualsiasi peer. Se viene avviata la mo-
dalità di peer, invece, partirà la ricerca di servizi che corrispondano ai parametri
30 Architettura dell’applicazione

di ricerca selezionati (principalmente il tipo di protocollo SMC scelto). Una volta


scelto una modalità di avvio, non è più possibile cambiare tale opzione, poiché i
comportamenti di queste due modalità sono molto differenti.
L’applicazione è strutturata in modo da essere sufficientemente generica da
poter permettere a qualsiasi protocollo di essere eseguito tra un certo numero di
dispositivi è sufficiente che esso sia definito implementando le interfacce previ-
ste. Nonostante l’architettura sia molto generica e possa permettere in linea teori-
ca un qualsiasi protocollo, risulta macchinoso aggiungere nuovi protocolli: ogni
protocollo SMC prevede un insieme diverso di dati di inizializzazione e questi
dati vengono immessi in una maschera nella prima schermate dell’applicazione.
Questo significa che è necessario creare una nuova maschera di immissione da-
ti, per ogni insieme di input che possono servire ad un determinato protocollo.
L’alternativa consisterebbe di usare una schermata generica, ma si perderebbe in
semplicità e usabilità per l’utente.

Contesto mobile Il sistema si inserisce in un contesto mobile, in particolare è


strutturato per funzionare su dispositivi Android di nuova generazione (supe-
riore alla versione 4.1.2). Questa scelta è dovuta ad un insieme di funzionalità
che sono state previste da tale versione, in particolare ad una nuova tecnologia
denominata Wi-Fi Direct, spiegata in dettaglio in seguito.
La scelta del Wi-Fi Direct permette ai dispositivi di non essere legati ad una re-
te particolare per poter eseguire i propri compiti. I dispositivi di tipo Peer posso-
no effettuare una ricerca di un servizio messo a disposizione da un group owner,
una volta trovato è possibile per loro effettuare una richiesta di partecipazione
al gruppo e sarà compito del proprietario del gruppo decidere quali dispositivi
faranno parte della computazione.

Sicurezza L’applicazione permette di gestire la sicurezza in due modi distinti,


è possibile cifrare le comunicazioni tra dispositivi in caso il protocollo SMC usato
non si occupi della sicurezza e presuma di usare canali sicuri. Ma è anche pos-
sibile disattivare questa funzionalità in caso il protocollo si occupi per conto suo
della sicurezza e quindi di inviare dati che non possono essere letti da terze par-
ti. In tutti i casi viene comunque fatta una distribuzione delle chiavi pubbliche,
subito prima di cominciare con il protocollo vero e proprio.

Gestione degli errori L’applicazione prevede una gestione degli errori su due
livelli, qualsiasi errore accada su uno dei device, la computazione non può essere
4.2 Protocolli di SMC 31

portata avanti quindi l’errore viene principalmente comunicato all’utente che ha


ottenuto l’errore, ma poi viene anche inviato a tutti i dispositivi in modo che
questi possano abortire la computazione.

4.1.1 Organizzazione del codice


Il codice del progetto è suddiviso in tre parti, una relativa ai protocolli di SMC,
una relativa al layer di trasporto che contiene le tipologie di pacchetti che verran-
no inviati sulla rete ed una all’interfaccia utente su dispositivi Android, poiché
permette all’utente di usare i protocolli multi-party computation tramite un’in-
terfaccia grafica di un’applicazione eseguibile sui dispositivi Android.

Protocolli di SMC

Interfaccia utente
per Android

Layer di trasporto

4.2 Protocolli di SMC


I protocolli presentati brevemente sopra sono stati implementati separatamente
ma prevedono un insieme di funzionalità comuni. Infatti entrambi i protocolli co-
municano inviando un pacchetto di dati e prevedono un utente che dia inizio alla
comunicazione ed uno (o più) che continuano ad elaborare i dati del protocollo e
ad inviarli.
In tale senso sono stati creati un utente iniziale InitUser ed un utente secon-
dario DefaultUser (il nome deriva dal fatto che l’utente che da avvio alla compu-
tazione di per se deve agire anche come utente partecipante e quindi è anche un
DefaultUser).
L’utente standard o di default può generare un nuovo pacchetto partendo da
un pacchetto che gli è stato passato (tale funzione è idempotente), inoltre può
verificare se il pacchetto ricevuto è l’ultimo.
32 Architettura dell’applicazione

L’utente di inizializzazione, oltre a poter generare il pacchetto successivo, può


generare anche il primo pacchetto della computazione e l’ultimo, contenente la
risposta.
Il pacchetto dati SMCProtocolPacket passato tra un utente ed un altro parteci-
pante al protocollo contiene una lista di valori grezzi, la numerazione della fase
in cui si trova ed un flag che indica se il pacchetto è quello finale.
Ad esempio per il protocollo del milionario si è scelto di usare come algorit-
mo di appoggio RSA che prevede una chiave pubblica ed una privata possedute
dall’utente secondario.

InitUser DefaultUser

Generazione packet1
pacchetto iniziale
Posso creare un nuovo pacchetto? sì.
packet2 Genera il prossimo pacchetto
a partire da packet1
...

packetN-1
Genera
il prossimo pacchetto packetN Posso creare un nuovo pacchetto? no
a partire da packetN-1 Leggi il risultato nel pacchetto
packetN

4.3 Layer di trasporto


Per essere usati su dispositivi distinti i pacchetti devono passare per una rete
fisica ed essere trasmessi ai giusti destinatari, per fare questo è stato necessario
definire un nuovo protocollo al di sopra del protocollo SMC scelto dall’utente. In
seguito ad una connessione avvenuta tra n utenti e chiusura del gruppo a nuovi
utenti, il protocollo di trasporto prevede una serie di fasi:

1. Viene effettuato lo scambio dei parametri del protocollo (tramite il Proto-


colParamsPacket), viene comunicato se il protocollo necessita di cifratura,
elenca i dispositivi che fanno parte del gruppo e prevede di inserire altri
metadati serializzati se necessari ad un determinato protocollo.
4.3 Layer di trasporto 33

2. Al pacchetto di scambio parametri inviato dall’utente iniziale, l’utente se-


condario risponde inviando un pacchetto con i dati di sicurezza del pro-
prio device (in un DeviceSecurityInfoPacket), principalmente la propria chia-
ve pubblica.

3. Una volta che tutti gli utenti secondari hanno inviato le loro informazioni
di sicurezza, allora l’utente iniziale le impacchetta (in un DevicesSecurity-
InfoPacket) e le manda a tutti gli utenti, in modo che ogni partecipante al
gruppo, conosca le chiavi pubbliche di tutti.

4. In seguito ogni utente è tenuto ad inviare un pacchetto di conferma a quello


ricevuto, in modo da sincronizzare tutti gli utenti prima di cominciare il
protocollo vero e proprio (ConfirmationPacket).

5. L’utente iniziale invia il primo pacchetto di trasporto (TransportProtocolPac-


ket) che incapsula il pacchetto con i dati del protocollo SMC. poiché durante
una sessione del protocollo, i pacchetti possono essere cifrati in alcune fasi,
ma non nella fase di risposta (in cui l’utente finale comunica a tutti l’output
del protocollo), il pacchetto di trasporto deve comunicare se il contenuto è
cifrato o meno.

6. L’utente secondario procede creando il pacchetto seguente e inviandolo al


destinatario successivo del gruppo.

7. L’algoritmo continua fino a quando si giunge all’ultimo pacchetto del pro-


tocollo, in questo caso l’utente iniziale prepara la risposta e la invia a tutti i
destinatari.
34 Architettura dell’applicazione

InitUser DefaultUser

Creazione del gruppo protocolParamsPacket


di computazione

deviceSecurityInfoPacket Invio delle informazioni


di sicurezza
In attesa delle
informazioni di sicurezza devicesSecurityInfoPacket
di tutti i dispositivi Le informazioni di sicurezza
di tutti i dispositivi
confirmationPacket
In attesa del sono state ricevute.
pacchetto di conferma Invio della conferma
transportProtocolPacket1
di avvenuta ricezione
da parte di tutti i dispositivi
transportProtocolPacket2
..
.
transportProtocolPacketN-1
Invio ultimo pacchetto
contenente il risultato transportProtocolPacketN
della computazione Lettura del risultato
della computazione

Figura 4.1: Schema del protocollo con due dispositivi


4.3 Layer di trasporto 35

InitUser DefaultUser1 DefaultUser2

protocolParamsPacket
Il gruppo di computazione protocolParamsPacket
è stato creato
deviceSecurityInfoPacket1

deviceSecurityInfoPacket2

devicesSecurityInfoPacket
In attesa delle
informazioni di sicurezza devicesSecurityInfoPacket
di tutti i dispositivi
confirmationPacket

confirmationPacket
In attesa dei pacchetti
di conferma transportProtocolPacket1
da tutti i dispositivi. transportProtocolPacket2
Invio primo pacchetto
transportProtocolPacket3

transportProtocolPacketR
Invio ultimo pacchetto
con il risultato transportProtocolPacketR
della computazione

Figura 4.2: Schema del protocollo,esempio con tre dispositivi


36 Architettura dell’applicazione

4.3.1 Tipi di pacchetti


SalutObjectPacket è il pacchetto che incapsula al suo interno gli altri pacchet-
ti, il pacchetto incapsulato viene deserializzato dal ricevente basandosi sul tipo
presente nello header.

Sender device Receiver device Type Header

Serialized packet

Figura 4.3: SalutObjectPacket

ProtocolParamsPacket Questo pacchetto viene inviato dal dispositivo che ini-


zializza la computazione quando il discovery dei dispositivi è terminato e si è già
deciso quali dispositivi faranno parte della computazione. I dispositivi facenti
parte della computazione sono inviati in un determinato ordine che sarà quello
che dovrà essere seguito in eventuali computazioni che prevedono comunicazio-
ni sequenziali.

Device 1 Device 2 

...
 Devices
 in computation


Device n-1 Device n
Is encryption on?
other serialized data ...

Figura 4.4: ProtocolParamsPacket

VotingExtraDataPacket è un esempio di pacchetto che può essere incapsulato


in ProtocolParamsPacket contenente informazioni di inizializzazione extra neces-
sarie nel protocollo di voto.

number of candidates

Figura 4.5: VotingExtraDataPacket


4.3 Layer di trasporto 37

DeviceSecurityInfoPacket è il primo pacchetto che viene inviato dai dispositivi


secondari una volta connessi al dispositivo iniziale. Contiene la chiave pubblica
di un dispositivo ed il suo identificativo. Questo serve per cifrare i contenuti che
ne hanno la necessità.
Security
Device Public Key
information

Figura 4.6: DeviceSecurityInfoPacket

DevicesSecurityInfoPacket è il pacchetto che invia il dispositivo iniziale quan-


do ha ricevuto da ogni dispositivo partecipante alla computazione le informazio-
ni di sicurezza contenute nel DeviceSecurityInfoPacket. Si tratta di una lista di
DeviceSecurityInfoPacket.

DeviceSecurityInfoPacket 1 



DeviceSecurityInfoPacket 2

 Security
... 
 information



DeviceSecurityInfoPacket n 

Figura 4.7: DevicesSecurityInfoPacket

FailurePacket contiene una ragione per cui la computazione si deve ritenere


fallita, questo pacchetto può essere generato dal dispositivo iniziale o da uno
dei dispositivi secondari, in tale caso viene inviato al dispositivo iniziale che si
preoccupa di propagarlo a tutti i dispositivi interessati.

Failure reason

Figura 4.8: FailurePacket

ConfirmationPacket quando i dispositivi secondari hanno ricevuto tutti una


copia delle informazioni di sicurezza degli altri dispositivi presenti nella comu-
nicazione, usano questo pacchetto per confermare che sono pronti a comincia-
re la computazione. Più in generale prevede di confermare un qualsiasi tipo di
pacchetto ricevuto inviato il tipo di pacchetto da confermare.
38 Architettura dell’applicazione

Type of packet to confirm

Figura 4.9: ConfirmationPacket

TransportProtocolPacket contiene al suo interno un SerializableSMCProtocolPac-


ket serializzato ed un flag che indica se tale pacchetto è stato cifrato, in modo che
si sappia se prima di deserializzarlo è necessario decifrarlo oppure può essere
usato anche così com’è.

Is encrypted?

SerializableSMCProtocolPacket

Figura 4.10: TransportProtocolPacket

SerializableSMCProtocolPacket è il pacchetto con il vero contenuto del proto-


collo di secure multi-party computation è una versione serializzabile e utilizzabi-
le per l’invio del SMCProtocolPacket originale.

phase Is last packet?



value 1 value 2 





... values





value v-1 value v

Figura 4.11: SerializableSMCProtocolPacket


Capitolo 5

Implementazione

5.1 Tecnologie e scelte implementative

L’implementazione di questa applicazione è cominciata con l’implementazione


dei protocolli presentati da Yao, tramite il linguaggio di programmazione java.
Quindi in maniera del tutto indipendente dalla piattaforma sulla quale avrebbe
dovuto essere usata.
L’implementazione dei protocolli prevede due tipologie di utenti uno con la
facoltà di iniziare il protocollo e un altro che può continuarlo e leggere il risultato
finale. Il protocollo è diviso in un certo numero di step o passi che sono deter-
minati all’inizio del protocollo e possono anche dipende da come questo è stato
configurato.
Ogni step, a parte il primo, prende come input un insieme di dati, raccolti in
una struttura denominata pacchetto e produce come output un altro pacchetto;
durante la produzione di tale pacchetto i dati vengono aggiornati con i risultati
della computazione specifica del protocollo, ma soprattutto viene incrementato il
numero di fase.
In questo modo è sempre possibile sapere come generare il pacchetto succes-
sivo ad pacchetto che si trova ad una certa fase. Il primo step, invece, crea il
pacchetto iniziale senza prendere alcun pacchetto come parametro.
La produzione di un nuovo pacchetto da parte dell’utente è un’operazione
idempotente, nel senso che anche se un pacchetto uguale viene inviato più volte,
l’utente che lo riceve produrrà sempre lo stesso output.
Questo avviene perché non viene mantenuto nessuno stato dei pacchetti al-
l’interno del protocollo di secure multi-party computation.
40 Implementazione

La presentazione generica dei tipi di utente possibili e l’uso dei pacchetti per i
protocolli specifici sarà spiegata in dettaglio nella sezione Implementazione dei
protocolli.
Per testare il funzionamento dei protocolli senza avere ancora una struttura
applicativa vera e propria sulla quale eseguirli, sono stati effettuati numerosi test
di unità in cui si simulavano gli utenti comunicanti verificando che ogni step del
protocollo producesse un output corretto.
La maggior parte dei test dell’applicazione sono orientati a garantire la cor-
rettezza dei protocolli, per i dettagli è necessario vedere la sezione Strategie di
testing.
In seguito si è cercato di portare l’implementazione dei protocolli in un am-
biente specifico, ovvero in Android. Il porting dei protocolli è stato molto facile
poiché la piattaforma Android prevede già l’uso di applicazioni java che sono in
pratica la maggior parte di quelle presenti negli store.
I problemi che si sono presentati, indipendentemente dalla piattaforma, sono
stati principalmente due e cioè:

1. Permettere la comunicazione tra diversi dispositivi in cui ciascuno rappre-


senta un utente del protocollo SMC.

2. Costruire un’interfaccia grafica che permetta di gestire gli aspetti di co-


municazione tra dispositivi e di gestione del protocollo di computazione
sicura.

La comunicazione tra dispositivi si può effettuare in modalità diverse, ovvero


usando delle connessioni su una rete wifi e accordandosi sugli indirizzi IP facenti
parte di una computazione, oppure usare il bluetooth e costruire una piconet in
cui il dispositivo iniziale diventa master e gli altri dispositivi sono slave.
Le possibilità sono numerose, ciascuna con i suoi pregi ed i suoi difetti, si è
deciso di puntare su una tecnologia nuova denominata Wi-Fi Direct.
Tale tecnologie ha come principale inconveniente quello di essere supportato
solo sui dispositivi Android più nuovi, ma presenta numerosi vantaggi tra cui si
può ricordare il fatto di essere slegati da una rete Wi-Fi preesistente e di suppor-
tare la pubblicazione e ricerca di servizi senza l’utilizzo diretto dell’indirizzo IP.
Per ulteriori dettagli è possibile consultare la sezione Android Wi-Fi Direct.
La gestione di una rete di questo tipo risulta un po’ complessa anche per ope-
razioni molto semplici di pubblicazioni di servizi e ricerca degli stessi, per tale
motivo si è preferito usare la libreria Salut che prevede una gestione semplifi-
5.1 Tecnologie e scelte implementative 41

cata della rete Wi-Fi Direct. Si veda la sezione apposita per informazioni più
specifiche.

Una volta scelto il mezzo per la comunicazione tra dispositivi è risultato ne-
cessario costruire una gerarchia di pacchetti per effettuare le varie comunicazioni,
le tipologie di pacchetti sarebbero state necessarie anche se si fosse scelta una
diversa infrastruttura di comunicazione, motivo per cui l’elenco dei pacchetti
possibili è stato già presentato all’interno del capitolo dedicato all’architettura
dell’applicazione.

In Wi-Fi Direct esiste un dispositivo che è quello che costruisce un gruppo di


comunicazione e pubblica dei servizi, tale dispositivo ha dei compiti particolari è
anche quello che inizializza il protocollo SMC in una seconda fase.

Il dispositivo che inizializza sia il gruppo all’interno della rete, sia il protocol-
lo di SMC ha un altro ruolo importante all’interno dell’applicazione, si occupa
anche di ricevere tutti i pacchetti e di inoltrarli al dispositivo corrispondente (si
veda L’uso di Wi-Fi Direct per un approfondimento).

Tutti i pacchetti passano per il device iniziale, motivo per cui la sicurezza po-
trebbe essere minata, per evitare questo inconveniente i pacchetti che devono
rimanere privati sono cifrati con la chiave pubblica del destinatario.

Questo viene fatto usando l’infrastruttura standard messa a disposizione dalla


JCA la Java Cryptography Architecture, presente anche su Android. Una breve
presentazione delle funzionalità messe a disposizione dalla JCA si trova nella
sezione relativa alle tecnologie.

I pacchetti scambiati tra un dispositivo e l’altro sulla rete prima di essere in-
viati vengono serializzati in un formato per lo scambio dei dati plain text deno-
minato JSON, per fare questo si è usata la libreria LoganSquare.

LoganSquare è una delle librerie più veloci nel trasformare oggetti java in
strutture json e viceversa. Nella sezione relativa alle librerie è possibile trovare
delle informazioni su essa.

L’ultimo aspetto da considerare è quello relativo all’interfaccia utente che è la


parte più complessa, perché deve permettere all’utente di cercare altri dispositivi
sulla rete e di eseguire la computazione tra essi, cercando di restare chiara per l’u-
tente che la sta usando, una descrizione relativa al flusso applicativo per l’utente
è presente nella omonima sezione.
42 Implementazione

5.2 Implementazione dei protocolli


I protocolli di SMC prevedono sempre due tipi di dispositivi, quello che comincia
la computazione e quello che la continua.
A volte questi due ruoli si sovrappongono ad esempio nel protocollo del mi-
lionario, il dispositivo che ha cominciato una computazione potrà anche conti-
nuarla, come si vede dall’interfaccia: il dispositivo che inizializza la computazio-
ne ha anche a sua disposizione il metodo generateNextPacket. Questo verrà usato
finché non sarà finita la computazione.

5.2.1 Le interfacce comuni ai protocolli


La parte centrale del progetto è contenuta nel package it.unimi.ssri.smc.protocols.
A questo livello si trova la definizione di InitUser e DefaultUser.
Queste due classi contengono al loro interno i metodi che servono all’uten-
te che vuole partecipare ad una computazione di un protocollo SMC. Come gli
stessi nomi suggeriscono DefaultUser ha al suo interno un insieme di metodi per
effettuare operazioni generiche come generare il pacchetto con i valori dello step
successivo dato un pacchetto appena ricevuto. È presente anche un metodo per
sapere se si è giunti al termine del protocollo.
public interface DefaultUser {
// il protocollo gestisce di per sé la privatezza?
boolean isSecured();
// genera il pacchetto dello step successivo del protocollo
SMCProtocolPacket generateNextPacket(SMCProtocolPacket
packetReceived);
// ha responso positivo se esistono step successivi.
boolean hasNextPacket(SMCProtocolPacket packetReceived);
// restituisce il risultato della computazione in forma leggibile
String getVerboseResult(SMCProtocolPacket packetWithResult);
}

InitUser estende il DefaultUser e quindi mette a disposizione di chi lo usa


gli stessi metodi, ma in più ha il compito di generare il primo pacchetto della
computazione conoscere il numero di partecipanti ad essa.
public interface InitUser extends DefaultUser{
int getGroupSize();
SMCProtocolPacket generateInitializationPacket();
}
5.2 Implementazione dei protocolli 43

Per come sono strutturate queste interfacce si capisce che il funzionamento


del protocollo seguirà un flusso per cui InitUser genera il primo pacchetto di dati,
il primo DefaultUser genera il secondo, questo rispetto al protocollo scelto po-
trà inviare tale pacchetto a InitUser o ad un altro DefaultUser e così via, finché
hasNextPacket non sarà più vero.

InitUser DefaultUser
generate
Initialization packet1
Packet()
packet2 hasNextPacket? true
generateNextPacket(packet1)

...

packetN-1
generate
NextPacket packetN
(packetN-1) hasNextPacket? false
getVerboseResult(packetN)

5.2.2 Problema del milionario


Il problema del milionario viene risolto tramite due classi, la prima classe è Init-
Millionaire e la seconda SecondMillionaire. InitMillionaire può generare il primo
pacchetto, per fare questo genera un numero casuale molto grande (x), lo cifra
con la chiave pubblica del secondo milionario (c) e sottrae la propria ricchezza (r).
Il valore ottenuto verrà inserito nel primo pacchetto della computazione, ovvero
quello in cui la fase ha valore uno.
@Override
public SMCProtocolPacket generateInitializationPacket(){
...
SMCProtocolPacket smcProtocolPacket = new SMCProtocolPacket();
smcProtocolPacket.setPhaseint(1);
if(x == null){ // x is a very large number
x = new BigInteger(256, new Random());
}
RSAIntegers rsaCypherToB = new RSAIntegers(mod_b, E_b);
BigInteger c = rsaCypherToB.encrypt(x);
44 Implementazione

BigInteger val_a = c.subtract(r);


smcProtocolPacket.getValues().add(0,val_a);
return smcProtocolPacket;
}

Il primo device o InitMillionaire genera anche il terzo e ultimo pacchetto della


computazione, per fare questo controlla se il numero r-esimo della sequenza nel
pacchetto appena ricevuto è congruo a x mod p, se non lo è allora è esso stesso il
più ricco, altrimenti è SecondMillionaire il più ricco.
private SMCProtocolPacket
generatePhase3Packet(SMCProtocolPacket phase2Packet){
...
SMCProtocolPacket phase3packet = new SMCProtocolPacket();
BigInteger p = phase2Packet.getValues().get(dim_u);
if(!x.mod(p).equals(phase2Packet.getValues().get(r.intValue()-1))){
phase3packet.getValues().add(BigInteger.ZERO);
imRicherValue = true;
} else{
phase3packet.getValues().add(BigInteger.ONE);
imRicherValue = false;
}
phase3packet.setPhaseint(3);
phase3packet.setLastPacket(true);
...
}

Il SecondMillionaire genera il secondo pacchetto della comunicazione e legge il


risultato della computazione nel terzo pacchetto che riceve. Il secondo pacchetto
è di fondamentale importanza, poiché viene generata una lista di numeri in cui
zu = yu (mod p) in cui per ogni zu 6= zv e 0 < zu < (p − 1)
private SMCProtocolPacket generatePhase2Packet(SMCProtocolPacket
phase1Packet){
BigInteger val_a = phase1Packet.getValues().get(0);
RSAIntegers rsa = new RSAIntegers();
rsa.setPrivateKey(mod_b, D_b);
List<BigInteger> y_u_array = new ArrayList<BigInteger>();
for(int u = 1; u <= dim_u; u++){
BigInteger y_u = rsa.decrypt(val_a.add(new BigInteger(""+u)));
y_u_array.add(y_u);
}
List<BigInteger> z_u_array = generateZ_u(y_u_array);
SMCProtocolPacket phase2packet = new SMCProtocolPacket();
phase2packet.setPhaseint(2);
for(int u = 0; u< z_u_array.size();u++){
5.2 Implementazione dei protocolli 45

BigInteger z_u = z_u_array.get(u);


if(r.compareTo(BigInteger.valueOf(u)) >0){
phase2packet.getValues().add(z_u);
}else {
phase2packet.getValues().add(z_u.add(BigInteger.ONE));
}
}
phase2packet.getValues().add(p);
return phase2packet;
}

In caso il pacchetto ricevuto da SecondMillionaire sia l’ultimo (quello nella fase tre)
allora risulta possibile leggere il risultato della computazione.
public boolean imRicher(SMCProtocolPacket phase3Packet){
...
return !phase3Packet.getValues().get(0).equals(BigInteger.ZERO);
}

Nel protocollo del milionario non è necessaria la cifratura e quindi l’imple-


mentazione di DefaultUser.isSecured() restituisce vero, per quanto riguarda invece
l’implementazione di InitUser.getGroupSize(), questa restituisce il valore 2, visto
che il protocollo è definito per 2 utenti.

5.2.3 Votazione di un candidato


Nel caso di votazione di un candidato i tipi di dispositivi sono due: InitVoter
e CommonVoter. L’inizializzazione del dispositivo iniziale prevede più parame-
tri rispetto ad un dispositivo secondario, infatti oltre al voto scelto dallo stesso
utente, verranno passati anche il numero di candidati ed il numero di votanti. Il
numero di votanti per limitazione del protocollo (segretezza del voto) deve essere
maggiore di 2.
Il primo pacchetto generato contiene una lista di numeri generati casualmente
lunga quanto il numero di candidati da votare. Tale lista è memorizzata per usi
futuri.
for(int i = 0; i< n_candidates; i++){
candidates_vote.add(BigInteger.probablePrime(10, new Random()));
}

In seguito il device iniziale genererà anche l’ultimo pacchetto, per fare questo
aggiungerà prima il suo voto alla lista, incrementando di uno il valore all’indice
corrispondente al voto e poi sottrarrà i valori generati nella fase iniziale.
46 Implementazione

private SMCProtocolPacket generateLastPacket(SMCProtocolPacket


lastPacket){
...
BigInteger newValueForIndex =
newcandidates_vote.get(my_vote).add(BigInteger.ONE);
newcandidates_vote.set(my_vote, newValueForIndex);

SMCProtocolPacket smcProtocolPacket = new SMCProtocolPacket();


for(int i= 0; i< newcandidates_vote.size(); i++){
BigInteger finalVoteForPosition =
newcandidates_vote.get(i).subtract(candidates_vote.get(i));
smcProtocolPacket.getValues().add(finalVoteForPosition);
}
...
}

Nello stesso metodo viene fatto anche un controllo per verificare che un utente
non abbia barato aggiungendo più di un voto durante il suo turno.
...
BigInteger c = BigInteger.ZERO;
for(BigInteger bi : smcProtocolPacket.getValues()){
c = c.add(bi);
}
if(c.intValue() != n_voters ){
throw new IllegalArgumentException("Wrong number of voters: "
+ c.intValue() + " expected " + n_voters);
}

Il CommonVoter ha tra i suoi compiti quello di generare uno dei pacchetti


successivi al primo, incrementando di uno il valore all’indice corrispondente al
voto.
public SMCProtocolPacket
generateNextPacket(SMCProtocolPacket packetReceived){
...
SMCProtocolPacket packetToSend = new SMCProtocolPacket();
packetToSend.getValues().addAll(packetReceived.getValues());
BigInteger newValueForIndex =
packetReceived.getValues().get(my_vote).add(BigInteger.ONE);
packetToSend.getValues().set(my_vote, newValueForIndex);
packetToSend.setPhaseint(packetReceived.getPhaseint()+1);
return packetToSend;
}

Se si tratta dell’ultimo pacchetto del protocollo il risultato può essere letto trami-
te il metodo readVotingResult o per avere un risultato leggibile è presente anche
5.2 Implementazione dei protocolli 47

il metodo definito nell’interfaccia: getVerboseResult(SMCProtocolPacket packetWith-


Result).
Il risultato corrisponde semplicemente ad una lista di valori in cui l’indice
corrisponde al candidato e il valore a tale indice indica i voti ricevuti.
In questo protocollo i messaggi che vengono passati tra un device e l’altro
sono in chiaro, se un utente malevolo volesse intercettare tutti i pacchetti, potreb-
be tramite una semplice operazione di sottrazione capire a chi corrisponde ogni
voto. Per questo motivo il metodo DefaultUser.isSecured() è falso.
L’implementazione di InitUser.getGroupSize() restituisce il numero di votanti
che è stato usato in fase di inizializzazione.
48 Implementazione

5.3 L’uso di Wi-Fi Direct


Per far comunicare un dispositivo con l’altro è stato usato un framework che si
appoggia su wifi-direct. Wifi-direct prevede che ci sia un dispositivo principale
proprietario di un gruppo di dispositivi e che in quanto tale possa decidere chi
far entrare nel gruppo e chi no. Il gruppo può essere anche implicitamente creato
tramite la creazione di un servizio di rete identificato da un nome.
A causa di questa implementazione, i dati passano tutti per il dispositivo ini-
ziale (initDevice), che in quanto tale svolge anche il compito di proprietario del
gruppo.
Mentre per il protocollo del milionario non si nota alcuna differenza nello
scambio di pacchetti, poiché i pacchetti spettano sempre all’initDevice o al default-
Device, per il protocollo di votazione viene simulata una rete ad anello.

1. il dispositivo iniziale (A) manda ad un secondo dispositivo (B) un pacchetto

2. il secondo dispositivo (B) deve mandare un pacchetto ad un terzo dispositi-


vo (C), quindi specifica nel pacchetto stesso (SalutObjectPacket che incapsula
il pacchetto col protocollo) che il destinatario in realtà è il terzo dispositivo
(C) infine cifra il pacchetto con la chiave pubblica di tale dispositivo e lo
invia al dispositivo iniziale (A).

3. il dispositivo iniziale riceve il pacchetto non destinato a lui e lo inoltra al


destinatario corretto altrimenti lo legge.

A B C

...

...
packet1ForC
Il pacchetto è per me? no
Inoltra il packet1ForC
pacchetto a C

Figura 5.1: Dettaglio tecnico: inoltro dei pacchetti al destinatario corretto


5.4 Tecnologie 49


sender: B receiver: C 


type: SerializableSMCProtocolPacket Header


is encrypted? TRUE 







SerializableSMCProtocolPacket Serialized packet





Figura 5.2: Esempio di un pacchetto SalutObjectPacket inviato ad A ma verrà


inoltrato a C

5.4 Tecnologie

5.4.1 Java Cryptography Architecture


I servizi crittografici di Android si basano sulla Java Cryptography Architecture
(JCA). JCA è un framework disponibile in Java sin dalla versione 1.1 ed è parte
del package java.security, JCA fornisce dei servizi crittografici di base come block
cyphers, message digests, digital signatures, etc.
JCA definisce due entità principali: l’engine ed il provider. L’engine definisce
una API che permette ad un applicazione o ad un servizio di usare un cypher o
un message digest. Un provider fornisce delle implementazioni concrete degli
engine.

Engine

Una classe engine fornisce l’interfaccia per un particolare servizio di crittografia.


Tali servizi rientrano in una delle seguenti categorie:

1. Operazioni di crittografia come ad esempio codifica, decodifica, firma e


verifica ed hash

2. Generazione o conversione di materiale di crittografia ad esempio chiavi e


parametri degli algoritmi.

3. Gestione e mantenimento degli oggetti di crittografia come chiavi e certifi-


cati.
50 Implementazione

Un engine è inoltre definito in modo astratto ed indipendente da una specifica


piattaforma hardware o software.
Ad esempio l’interfaccia Key rappresenta delle chiavi opache che possono es-
sere utilizzate nelle operazioni crittografiche ma che non forniscono l’accesso alla
key material (raw key bytes). Questo permette alle stesse classi JCA di operare
sia con implementazioni di algoritmi software, che memorizzano la chiave in me-
moria, sia con algoritmi hardware che lavorano con chiavi memorizzate su una
smart card.
Ogni classe Engine presenta un certo numero di factory methods statici chia-
mati getInstance():
static EngineClassName getInstance(String name)
static EngineClassName getInstance(String name, String provider)
static EngineClassName getInstance(String name, String provider)

La prima variante è quella da preferire nella maggior parte dei casi, in quanto
si lascia JCA decidere il "miglior" provider da utilizzare. La seconda e terza va-
riante consentono di richiedere un’implementazione da uno specifico provider.
Tutte le varianti infine lanciano una checked exception (omessa) se l’implemen-
tazione non è disponibile.
Ad esempio è possibile richiedere il digester SHA-256 tramite l’engine Messa-
geDigest nel seguente modo:
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");

Come si vede nell’esempio, l’argomento "name" equivale al nome dell’algo-


ritmo che si vuole utilizzare, tale crea un mapping con una trasformazione o
un algoritmo di crittografia particolare, oppure specifica una strategia di imple-
mentazione. Nell’esempio sopra si vede che il mapping è diretto, ma è possibile
anche specificare una serie di algoritmi da usare in combinazione, ad esempio
"SHA1WithRSA" che significa che SHA1 sarà usato per l’hashing e RSA per la
firma.
Lo standard di composizione dei nomi è descritto nella documentazione uffi-
ciale di java ([25]).

Provider

Ogni provider implementa un certo numero di Engine. JCA mantiene interna-


mente un registro dinamico di tutte le implementazioni di Engine disponibili.
Prima di utilizzare un Engine questo deve essere registrato tramite un provi-
der. Inoltre il registry mantiene, per ogni provider, un intero che rappresenta
5.4 Tecnologie 51

la precedenza: quindi se un certo engine è implementato da più provider, verrà


selezionato quello con precedenza maggiore.
Esistono due modi principali per registrare un provider: statico e dinamico.
Nella registrazione statica si fa uso del file security.properties con una riga for-
mattata come segue:
security.provider.n=FullyQualifiedClassName

dove n rappresenta la precedenza. Come si può vedere la registrazione statica


richiede la modifica del file delle proprietà di sicurezza del sistema con l’aggiunta
di una voce per il provider.
Questo file delle proprietà è chiamato security.properties ed è presente al-
l’interno del jar di sistema core non può quindi essere modificato pertanto la
registrazione statica dei provider al momento non viene supportata da Android.
Nella registrazione dinamica invece si fa uso della classe Security, che mette a
disposizione un metodo statico chiamato insertProviderAt:
static {
int orderOfPreference = 42;
Security.insertProviderAt(new MyProvider(), orderOfPreference);
}

Esiste inoltre il metodo iaddProvider per aggiungere nella prima posizione


disponibile il provider.

Providers

Tramite la classe Security è possibile accedere ai Provider registrati:


Provider[] providers = Security.getProviders();

Android presenta tre provider di base: Harmony, Bouncy Castle, AndroidO-


penSSL.

Harmony

Il primo si chiama Harmony e deriva da Apache Harmony, una implementazio-


ne del JRE ormai dismessa, tale provider fornisce un’implementazione limitata
di JCA (denominata Crypto) che si limita a fornire le implementazioni di servizi
crittografici come hashing, random generation e digital signatures. Questo pro-
vider è ancora incluso in Android, al fine di preservare la retro compatibilità, ma
ha la priorità più bassa tra tutti i provider JCA.
52 Implementazione

Bouncy Castle

Bouncy Castle [23] è stato l’unico provider JCA completo disponibile prima di
Android 4.0. La versione presente in Android è, tuttavia, una versione modificata
del provider Bouncy Castle:

• alcuni algoritmi, modi e parametri sono stati rimossi in quanto non suppor-
tati dalla reference implementation di Java

• alcuni algoritmi insicuri, come MD2 e RC2 sono stati rimossi

• MD5 e SHA1 sono forniti come implementazione nativa (JNI) per migliora-
re le performances

Questa versione ridotta di Bouncy Castle ha causato alcuni problemi di up-


grade, una possibile alternativa è rappresentata dal progetto Spongy Castle [24]
Questo progetto offre una versione stock di Bouncy Castle, il cui cambia il name-
space (org.bouncycastle.* a org.spongycastle.*) per evitare conflitti di classpath con
quello di Android. Infine per assicurarsi che venga usato questo provider occorre
caricarlo con priorità massima (1):
static {
int priority = 1;
Security.insertProviderAt(
new org.spongycastle.jce.provider.BouncyCastleProvider(),
priority
);
}

AndroidOpenSSL

Questo provider JCA continua la strategia di portare in codice nativo gli Engine
con problemi di performance, come già visto per Bouncy Castle.
AndroidOpenSSL quindi usa la libreria nativa OpenSSL, tramite JNI, per for-
nire implementazioni di tutti gli engine. Questo provider a partire da Android
4.4 è stato marcato come default, a priorità 1.

5.4.2 Android Wi-Fi Direct

La storia

Inizialmente chiamato Wi-fi p2p, Wi-Fi Direct è uno standard che permette a di-
versi dispositivi di collegarsi l’uno con l’altro senza la necessità di un access point.
5.4 Tecnologie 53

È utilizzato in molti ambiti dal trasferimento di file alle comunicazioni tra diver-
si dispositivi. Uno dei vantaggi di Wi-fi Direct è la sua capacità di permettere
connessioni tra dispositivi generici.
Normalmente le reti wifi prevedono la presenza di access point che hanno
principalmente tre compiti:

• supporto fisico alla rete cablata e wireless

• bridging e routing tra dispositivi di una rete

• servizi di provisioning per aggiungere e rimuovere dispositivi sulla rete.

La maggior parte delle reti wifi è configurata in "infrastructure mode" dove


l’access point (AP) è il punto centrale della wifi al quale tutti i dispositivi si col-
legano, la modalità "ad-hoc" fa comunicare un dispositivo con l’altro passando
sempre per l’access point.
Wi-Fi Direct funziona in modo diverso: permette ad un certo numero di di-
spositivi di comunicare l’uno con l’altro senza richiedere un AP dedicato, infat-
ti all’inizio del setup viene deciso quale dei devices deve assumere il ruolo di
"access point".
Con un numero crescente di dispositivi che usano il wifi, il modello di rete
con un router semplice e dei dispositivi intelligenti che si collegano ad esso ha
cominciato ad avere più successo, questo però ha portato anche a dei problemi di
sofisticazione degli hotspot. Per risolvere questo problema ci sono stati numerosi
tentativi di semplificare alcuni degli aspetti dello step di setup.
Un esempio comune di soluzione ai problemi di sofisticazione è il sistema
di Wi-Fi Protected Setup che è stato incluso in molti access point a partire dal
2007, poco dopo all’introduzione dello standard. Questo sistema permette agli
AP di essere configurati immettendo un pin o un altro tipo di identificativo du-
rante la connessione, in alcuni casi questo viene fatto semplicemente premendo
un bottone.
Tale sistema usa tale informazione per inviare al computer dei dati al dispo-
sitivo che con tali dati riesce a completare il setup della rete e a collegarsi ad
internet. Dal punto di vista dell’utente è sufficiente un solo click invece di scher-
mate complicate e spesso non del tutto comprese in cui inserire un insieme di
configurazioni.
All’inizio il modello di setup protetto era stato creato solo per semplificare la
connessione tra un access point e dei dispositivi che volevano farne uso, princi-
palmente per accedere ad internet. Esso permetteva poteva anche aiutare il di-
spositivo a trovare e configurare nu servizio sulla rete come una stampante o uno
54 Implementazione

scanner. Per fare questo, però, erano stati creati tutta una serie di protocolli co-
me Universal Plug and Play (UPnP), Devices Profile for Web Services (DPWS)
e Zero Configuration Networking (ZeroConf). Questi protocolli permettevano
ai dispositivi di collegarsi ad altri dispositivi della stessa rete senza effettuare un
setup o meglio il setup veniva fatto automaticamente ad insaputa dell’utente.

Col tempo è diventato comune per gli smartphones ed altri dispositivi por-
tatili includere il wifi come funzionalità standard. Il processo di aggiungere la
funzionalità di wifi su un piccolo dispositivo ha permesso ad essi di poter trova-
re stampanti, telecamere e scanner sulla rete, senza la necessità di avere un filo
per collegarsi ad essi.

La necessità di collegarsi ad un dispositivo senza avere un hub di mezzo che


permettesse tale connessione ha fatto in modo che le reti ad-hoc diventassero
sempre più utilizzate. UPnP e Bonjour rispondono a questi canoni d’uso ma
sono dei protocolli proprietari e non tutti o dispositivi ne fanno uso. Wi-fi Direct
direct permette ai dispositivi di collegarsi a numerose periferiche ma anche di
effettuare delle connessioni tra loro.

Wi-Fi Direct principalmente comprende un access point di tipo software che


deve supportare Direct. Il soft-AP prevede una versione di un Wi-Fi Protected
Setup basato su un pulsante o un pin. Ma il livello di sicurezza del setup dipende
dal ruolo che deve avere la connessione, si va da un semplice peering ad esempio
tra una macchina fotografica digitale ed un computer che vuole prendere le foto
dalla sua memoria, ad un telefono che deve fare data tethering e permettere una
connessione. È per questo che lo standard include anche funzionalità di sicurezza
come WPA2 e di controllo degli accessi.

Wi-Fi Direct però ha alcune limitazioni, infatti i dispositivi possono effettua-


re connessioni one-to-one o one-to-many ma il vantaggio è che non tutti i de-
vices collegati alla rete devono essere certificati Wi-fi Direct. Il programma di
certificazione Wi-fi Direct è sviluppato ed amministrato dalla Wi-Fi Alliance e le
specifiche sono disponibili sul sito ufficiale.

Google ha annunciato il supporto a Wi-Fi Direct in Android 4.0 nell’ottobre


del 2011, anche se alcuni dispositivi più vecchi che usavano Android 2.3 come il
Samsung Galaxy 2 avevano dei moduli di supporto proprietari per usare questa
tecnologia. Il Galaxy Nexus del novembre 2011 è stato il primo device android in
cui era inclusa un’implementazione di questa funzionalità.
5.4 Tecnologie 55

Implementazione su Android

Android implementa tutte le funzionalità previste dal Wi-fi Direct, in particolare


permette di registrare un’applicazione per l’uso del Wi-fi Direct, creando quindi
un canale per gli usi futuri semplicemente richiedendo il Wi-fi Direct manager:
mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(this, getMainLooper(), null);

È possibile richiedere la lista dei peers usando il WifiP2pManager e passando


un listener che deciderà come comportarsi se il servizio fallisce durante la sua
inizializzazione oppure se ha successo.
mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
// Qui deve essere inserito il codice che si vuole eseguire
// quando l’inizializzazione del discovery ha avuto buon fine.
// Questo metodo spesso viene lasciato vuoto poiché
// non è questa la callback che si occupa
// di gestire i dispositivi trovati durante il discovery.
}

@Override
public void onFailure(int reasonCode) {
// Questo codice viene chiamato se l’inizializzazione
// del discovery non ha avuto buon fine.
// Spesso è necessario comunicare all’utente che cosa
// non ha funzionato in modo che esso possa
// intraprendere una qualche azione.
// ad esempio se il telefono è in modalità aereo
// l’utente dovrà procedere a riattivare la rete.
}
});

Infine è importante registrare l’applicazione agli eventi del BroadcastReceiver,


in modo da intercettare gli eventi che si hanno nella rete. Questo si fa creando una
classe a parte e passando una serie di callback che dovranno essere implementate
dall’activity che ne fa uso oppure facendo in modo che l’activity estenda diretta-
mente il BroadcastReceiver. In ogni caso sarà necessario implementare il metodo
onReceive occupandosi degli eventi di rete più comuni.
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
56 Implementazione

// Qui si controlla se il wi-fi è abilitato


// e lo si notifica all’activity preposta
} else if
(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
// Se questo evento è stato prodotto
// allora è possibile chiamare
// WifiP2pManager.requestPeers()
/ per avere la lista dei peers correnti
} else if
(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action))
{
// Qui ci si occupa dello stato delle connessioni e delle
disconnessioni
} else if
(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action))
{
// Se lo stato di connessione del dispositivo è cambiato
// e si vuole intraprendere un’azione
// il codice deve trovarsi in questo punto.
}
}

L’evento WIFI_P2P_PEERS_CHANGED_ACTION in particolare verrà chiama-


to solo se è stato fatto partire il servizio per la ricerca dei peers, in questo caso
sarà possibile richiedere la lista dei peers in modo asincrono, ovvero passando
alla chiamata requestP eers un listener che contiene la chiamata onPeersAvaila-
ble(WifiP2pDeviceList peerList). Un esempio potrebbe essere:
if (mManager != null) {
PeerListListener peerListListener = new PeerListListener() {
@Override
public void onPeersAvailable(WifiP2pDeviceList peerList) {
// Si aggiungono i peers della nuova ricerca
peers.clear();
peers.addAll(peerList.getDeviceList());
// In caso ci sia un’AdapterView per listare i peers
// questa viene notificata dei cambiamenti
// Se si ha una ListView dei peers disponibili
// essa va notificata del cambiamento
((WiFiPeerListAdapter) getListAdapter()).notifyDataSetChanged();
if (peers.size() == 0) {
Log.d(WiFiDirectActivity.TAG, "Nessun dispositivo trovato.");
}
}
}
5.4 Tecnologie 57

mManager.requestPeers(mChannel, myPeerListListener);
}

Quando si conoscono i peers, è possibile decidere di collegarsi ad uno di essi


tramite la chiamata connect messa a disposizione dal WifiP2pManager:
// device è un peer ottenuto dalla lista di peers WifiP2pDeviceList
WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
mManager.connect(mChannel, config, new ActionListener() {
@Override
public void onSuccess() {
// L’azione ha avuto successo
}

@Override
public void onFailure(int reason) {
// L’azione è fallita
}
});

Esiste un listener per mettersi in ascolto sui cambiamenti di stato della connes-
sione, si tratta di
WifiP2pManager.ConnectionInfoListener, un’interfaccia che presenta la callback
onConnectionInfoAvailable() che viene chiamata quando lo stato di una connessio-
ne cambia. In caso ci siano dispositivi multipli che si collegano ad un singolo
peers, uno dei dispositivi deve essere designato come "group owner".
@Override
public void onConnectionInfoAvailable(final WifiP2pInfo info) {

// L’InetAddress può essere recuperato dall’oggetto WifiP2pInfo.


InetAddress groupOwnerAddress =
info.groupOwnerAddress.getHostAddress());

// Dopo la negoziazione del gruppo si può determinare l’owner del


gruppo.
if (info.groupFormed && info.isGroupOwner) {
// Qui si può inserire il codice specifico per l’owner del gruppo.
// Spesso si crea una ServerSocket
// in ascolto per eventuali connessioni.
} else if (info.groupFormed) {
// Codice di un dispositivo non owner che
// sarà client della connessione
// che aprirà una semplice Socket verso l’owner.
58 Implementazione

}
}

Se si stabilisce una connessione tra peers, in seguito risulta possibile trasferire


dati tra i vari dispositivi connessi tramite sockets. Quindi creando una Server-
Socket, una socket che si mette in attesa di connessioni su una specifica porta e
si blocca appena ne arriva una e richiama il metodo accept() (quindi è necessario
usare un thread a parte, in termini pratici una AsynkTask). In seguito si crea un
Socket sui client, che usa l’indirizzo e la porta del ServerSocket per collegarsi ad
esso. Gli scambi di dati sulla socket vengono fatti tramite stream di byte.

Servizi su Wi-Fi Peer-To-Peer

Un altro modo di usare wi-fi Peer-To-Peer consiste nell’usare il Service Discovery,


questa modalità permette di fare una ricerca di servizi messi a disposizione da
dispositivi nelle vicinanze, senza doversi collegare ad una rete. Questa capacità
permette la comunicazione tra applicazioni che non necessariamente si trovano
su una rete o sono collegate ad un hotspot.
In questa modalità uno dei device si occupa di registrare un servizio, che pos-
siede un insieme di proprietà come il nome del servizio, il nome dell’istanza del
servizio ed una mappa di proprietà con il loro valore.
private void startRegistration() {
// Si crea una mappa con le informazioni del proprio servizio:
Map record = new HashMap();
record.put("listenport", String.valueOf(SERVER_PORT));
record.put("buddyname", "John Doe" + (int) (Math.random() * 1000));
record.put("available", "visible");
// Qui sono presenti le informazioni di servizio:
// le informazioni dell’istanza, il tipo di servizio, il tipo di
protocollo
// _protocol._transportlayer ed una mappa contenente
// le informazioni che andranno inviati ai dispositivi che si
collegheranno
WifiP2pDnsSdServiceInfo serviceInfo =
WifiP2pDnsSdServiceInfo.newInstance("_test", "_presence._tcp",
record);
// Qui si aggiunge il servizio locale
// inviando le informazioni di servizio, il canale e il listener
// che sarà usato per decidere cosa fare in caso di successo o
fallimento.
mManager.addLocalService(channel, serviceInfo, new ActionListener() {
@Override
5.4 Tecnologie 59

public void onSuccess() {


// Il metodo ha avuto successo. In generale non serve aggiungere
codice qui
// Si potrebbe voler fare un update dell’interfaccia utente
// o loggare l’esito.
}

@Override
public void onFailure(int arg0) {
// In caso di fallimento bisogna controllare se il codice di
errore
// è di tipo P2P_UNSUPPORTED, ERROR oppure BUSY.
}
});
}

Per effettuare il discovery dei servizi vicini, si hanno a disposizione due call-
back che vanno usate insieme.
La prima WifiP2pManager.DnsSdTxtRecordListener permette di mettersi in ascol-
to dei records, in pratica si riescono a scoprire le informazioni inserite nella map-
pa di proprietà registrate insieme al servizio. Le informazioni di record possono
essere gestite come si preferisce ad esempio salvandone una parte.
final HashMap<String, String> buddies = new HashMap<String, String>();

DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {


@Override
public void onDnsSdTxtRecordAvailable
(String fullDomain, Map record, WifiP2pDevice device) {
Log.d(TAG, "DnsSdTxtRecord available -" + record.toString());
buddies.put(device.deviceAddress, record.get("buddyname"));
}
};

Per avere informazioni più rilevanti sul servizio, si crea un WifiP2pManager


.DnsSdServiceResponseListener che riceve una descrizione attuale ed un’informa-
zione di connessione. Tale listener in genere viene richiamato insieme al prece-
dente, in modo da poter usare le informazioni di record registrate con il listener
dei record.
DnsSdServiceResponseListener servListener =
new DnsSdServiceResponseListener() {

@Override
public void onDnsSdServiceAvailable(String instanceName,
60 Implementazione

String registrationType,
WifiP2pDevice resourceType) {
// Se si conosce il "buddyname" caricato dalla callback dei record
// Si effettua un update del nome del dispositivo.
if(buddies.containsKey(resourceType.deviceAddress)){
resourceType.deviceName =
buddies.get(resourceType.deviceAddress)
} else {
resourceType.deviceName = resourceType.deviceName;
}

// Se si vuole mostrare all’utente il risultato trovato,


// si potrebbe prevedere
// un frammento con una lista che mostra gli utenti trovati.
WiFiDirectServicesList fragment =
(WiFiDirectServicesList) getFragmentManager()
.findFragmentById(R.id.frag_peerlist);
WiFiDevicesAdapter adapter =
((WiFiDevicesAdapter) fragment.getListAdapter());
adapter.add(resourceType);
adapter.notifyDataSetChanged();
Log.d(TAG, "onBonjourServiceAvailable " + instanceName);
}
};

Il manager prende questi due listener come parametri prima di aggiungere


una richiesta di aggiunta del servizio
mManager.setDnsSdResponseListeners(channel, servListener, txtListener);

serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(channel, serviceRequest, new
ActionListener() {
@Override
public void onSuccess() {
// La richiesta ha avuto successo!
}

@Override
public void onFailure(int code) {
// In caso di fallimento bisogna controllare se il codice di errore
// è di tipo P2P_UNSUPPORTED, ERROR oppure BUSY.
}
});

In seguito è possibile cominciare il discovery dei servizi


5.5 Librerie 61

mManager.discoverServices(channel, new ActionListener() {

@Override
public void onSuccess() {
// l’operazione ha avuto successo
}

@Override
public void onFailure(int code) {
// L’operazione è fallita
if (code == WifiP2pManager.P2P_UNSUPPORTED) {
Log.d(TAG,
"P2P non è supportato su questo dispositivo");
} else if( code == WifiP2pManager.BUSY) {
Log.d(TAG,
"Il sistema è occupato: non può processare la richiesta");
} else if( code == WifiP2pManager.ERROR) {
Log.d(TAG,
"Operazione fallita a causa di un errore interno");
}
...
}
});

5.5 Librerie

5.5.1 Salut
Come visto precedentemente le API messe a disposizione da Google per gestire
il Wi-Fi Direct richiedono molto codice infrastrutturale, per ovviare a questo pro-
blema visto che lo scopo principale del progetto non consiste nel Wi-Fi P2P si è
usata la libreria Salut. Salut è un wrapper delle API di Android per il Wi-Fi P2P,
permette con metodi piuttosto semplici di creare un servizio per il trasferimen-
to di dati denominato SalutServiceData e di poter leggere i dati inviati ad esso
tramite un SalutDataReceiver.
SalutDataReceiver dataReceiver =
new SalutDataReceiver(myActivity, salutDataCallback);
SalutServiceData serviceData =
new SalutServiceData(SERVICE_NAME, PORT, instanceName);
// L’instanceName dovrebbe essere
// un nome leggibile che viene mostrato all’utente
62 Implementazione

Questi due oggetti dentro servono a creare un’istanza dell’oggetto Salut.


Salut network = new Salut(dataReceiver, serviceData,
new SalutCallback() {
@Override
public void call() {
Log.e(TAG, "Questo device non supporta WiFi Direct.");
}
});

La creazione di questo oggetto cela al suo interno la creazione di un’istanza


di un WifiP2pManager e l’inizializzazione di un canale. L’oggetto Salut mette
poi a disposizione tutti i metodi necessari a trasferire dati tra diversi dispositivi,
ad esempio è possibile avviare un servizio semplicemente chiamando il meto-
do startN etworkService, questo prenderà come argomenti una serie di callback,
che corrisponderebbero a quelle che si avrebbero con Wi-Fi Direct effettuando
una manager.addLocalService seguita da una manager.addServiceRequest ed una
manager.discoverServices.
network.startNetworkService(new SalutDeviceCallback() {
@Override //onDeviceRegistered =Callback
public void call(SalutDevice defaultDevice) {
// è stato trovato un device durante il discovery
}
}, new SalutCallback() {
@Override
public void call() {
// l’operazione è andata a buon fine.
Log.i(TAG,
"Il servizio di rete è stato avviato con successo");
}
}, new SalutCallback() {
@Override
public void call() {
// codice da eseguire se l’operazione è fallita
}
});

Su un altro dispositivo invece sarà possibile effettuare il discovery del servizio


attivato, avviando una ricerca che continuerà finché non viene fermata.
network.discoverNetworkServices(new SalutDeviceCallback() {
@Override
public void call(SalutDevice device) {
Log.d(TAG, "Connesso dispositivo " + device.deviceName);
}
5.5 Librerie 63

}, callContinously);

In caso si utilizzi questa modalità di ricerca dei servizi è necessario terminare


il discovery con il metodo network.stopServiceDiscovery Ma è anche possibile
lanciare un discovery con un certo timeout, in modo che la ricerca sia interrotta
dopo un certo lasso di tempo.
network.discoverNetworkServicesWithTimeout(new SalutCallback() {
@Override
public void call() {
// sono stati trovati dei dispositivi
// la lista si trova in network.foundDevices
Log.d(TAG, "I dispositivi trovati sono i seguenti"
+ network.foundDevices.toString());
}
}, new SalutCallback() {
@Override
public void call() {
// codice da eseguire se non sono
// stati trovati dispositivi con servizi disponibili
// Ad esempio è possibile chiedere all’utente
// se desidera continuare la ricerca o interromperla.
}
}, TIMEOUT_MSEC);

Per effettuare una classica connect, una volta trovato un host con il servi-
zio che si stava cercando è sufficiente usare il metodo registerWithHost messo
a disposizione dall’oggetto Salut.
network.registerWithHost(possibleHost, new SalutCallback() {
@Override
public void call() {
Log.d(TAG, "Questo dispositivo si è registrato all’host.");
}
}, new SalutCallback() {
@Override
public void call() {
Log.d(TAG, "La registrazione all’host è fallita");
}
});

L’apertura e chiusura delle socket, viene nascosta da questa libreria, facendo


in modo che la comunicazione avvenga tramite i metodi sendT oDevice, sendT oAllDevice
e sendT oHost, dove per Host si intende il dispositivo che ha avviato il servizio,
mentre per Device si intende il dispositivo che si è registrato all’host.
Message myMessage = new Message();
64 Implementazione

network.sendToAllDevices(myMessage, new SalutCallback() {


@Override
public void call() {
// codice in caso di fallimento
}
});

network.sendToDevice(deviceToSendTo, myMessage, new SalutCallback() {


@Override
public void call() {
// codice in caso di fallimento
}
});

network.sendToHost(myMessage, new SalutCallback() {


@Override
public void call() {
// codice in caso di fallimento
}
});

I dati inviati verranno poi letti attraverso il listener onDataReceived(Objectdata)


presente nella callback di SalutDataCallback passato inizialmente in costruzione
al SalutDataReceiver.
@Override
public void onDataReceived(Object data) {
Log.d(TAG, "Sono stati ricevuti dei dati sulla rete");
if(data instanceof Message){
try {
Message newMessage =
LoganSquare.parse((Message) data, Message.class);
Log.d(TAG, newMessage.description);
// Altro codice che si serve dei dati ricevuti
} catch (IOException ex) {
Log.e(TAG, "Fallimento durante il parsing dei dati.");
// gestione del fallimento
}
}
}

Come si può vedere la gestione dell’invio di dati sulla rete risulta molto sem-
plificata grazie a questa libreria. Non è più necessario gestire tutte le chiamate
che richiede l’API standard di Wi-Fi P2P ma è sufficiente creare dei servizi, col-
legarsi ad essi ed in seguito inviare i dati tra un device e l’altro, senza avere la
5.5 Librerie 65

necessità di usare direttamente le socket.


Uno dei difetti della libreria Salut è che è strettamente collegata ad un’altra
libreria denominata LoganSquare che ha il compito di serializzare/deserializzare
dati. Quest’ultima verrà presentata successivamente.

5.5.2 LoganSquare

Android nella sua versione più pura mette a disposizione delle classi di utilità
per leggere gli stream in formato Json. È infatti possibile scorrere uno stream
serializzato e leggere i valori che appartengono a determinate chiavi, siano questi
numeri, stringhe o sotto-strutture più complesse. Questa modalità di leggere il
json è molto efficiente perché permette di andare a leggere di volta in volta solo
le parti di json che sono di interesse, scartando quelle che potrebbero non essere
utili. Tuttavia per ogni json che arriva è necessario scrivere del codice ad-hoc, per
ogni situazione di interesse e può diventare pesante, in determinati casi.
Una libreria spesso usata per non doversi occupare di scorrere il json e costrui-
re degli oggetti con i valori trovati è GSON. GSON è molto più avanzata rispetto
al parsing manuale, prevede solo due metodi f romJson() e toJson(), con il pri-
mo metodo dato uno stream e una classe di destinazione per convenzione tutti i
campi con un certo nome dentro il json vengono copiati nell’oggetto, cercando di
rispettare i tipi ed andando in profondità nelle sotto classi contenute nella classe
principale. Il secondo metodo, invece, data una classe permette di ottenere un
json che rispetti la struttura gerarchica della stessa classe.
Usando GSON non è necessario che le classi siano particolari, se una classe
risulta complessa è possibile registrare un TypeAdapter, cioè una classe che de-
scriva un comportamento particolare per la serializzazione e per la deserializza-
zione. In questo modo è anche possibile modificare il comportamento di default
del serializzatore di GSON.
Una soluzione diversa è quella invece adottata da LoganSquare, in cui le classi
che si possono serializzare sono solo quelle annotate, questo permette al processo
di de/serializzazione di essere molto più veloce perché il lavoro più lungo di
mapping tra un eventuale json e la classe viene fatto a compile time. Quando
è necessario scrivere i valori dei campi di un uno stream json su una classe, la
logica da seguire è già conosciuta.
L’annotazione può essere fatta sull’intera classe, decidendo che strategia se-
guire (ad esempio tutti i campi non privati) e poi decidendo quali campi ignorare.
66 Implementazione

@JsonObject(fieldDetectionPolicy =
FieldDetectionPolicy.NONPRIVATE_FIELDS)
public class MyClass {

public String format;


@JsonField(name = "differentFieldName")
public int imageId;

@JsonIgnore
public int nonJsonField;

// questo campo viene ignorato perché è privato


private int privateIntIgnored;
...
}

Oppure i campi da mappare vengono annotati uno per uno, questo risulta
molto più controllabile e sicuro, perché si può essere certi che qualsiasi cosa venga
mappata automaticamente è stata decisa dallo sviluppatore
@JsonObject
public class MyClass {

@JsonField
public String format;
@JsonField(name = "differentFieldName")
public int imageId;

public int nonJsonField;


private int privateIntIgnored;
...
}

Come per la libreria GSON è possibile definire dei TypeConverter personaliz-


zati per le conversioni più complesse, questi convertitori possono essere passati
come parametro dell’annotazione
@JsonObject
public class ModelObject {
@JsonField(typeConverter = YourConverter.class)
public Date speciallyConvertedDate;
}

Tramite LoganSquare.parse(inputStream, M yClass.class) e


LoganSquare.serialize(myClass) è possibile ottenere gli stessi risultati che si
hanno con f romJson e toJson della libreria GSON in tempi molto minori.
5.6 Strategie di testing 67

5.6 Strategie di testing


Alcune parti dell’applicazione sono state testate intensivamente, nel caso dei pro-
tocolli la copertura è quasi totale e prevede un insieme di test che vanno a co-
prire le casistiche che si potrebbero verificare in caso i pacchetti generati siano
malformati.
Nel codice dei diversi protocolli si vede che tutti i metodi che generano pac-
chetti lanciano un’eccezione se uno dei parametri necessari a completare il lavoro
non è presente.

Problema del milionario Dentro InitMillionaire.generateInitializationPacket(), un


metodo che genera la prima serie di dati per la computazione, si controlla che la
ricchezza dell’utente stesso sia stata impostata, ma anche che la chiave di cifratura
dell’altro utente (SecondMillionaire) sia stata impostata durante l’inizializzazione:
visto che si usa RSA saranno necessari modulo e chiave.
public SMCProtocolPacket generateInitializationPacket(){
if(r == null || E_b == null || mod_b == null){
throw new IllegalArgumentException("r or E_b or mod_b is null");
}
...
}

Anche un pacchetto in una fase sbagliata per un determinato utente (sia que-
sto un’ estensione di InitUser o DefaultUser) viene considerato sbagliato. Ad esem-
pio InitMillionaire tra le sue fasi prevede solo di ricevere un pacchetto in fase 2
(e di generare il primo pacchetto). L’eccezione lanciata è abbastanza parlante e
permette di identificare nel log il problema che si è verificato.
switch (packetReceived.getPhaseint()) {
case 0:
throw new IllegalArgumentException
("Please call generateInitializationPacket() for this phase");
case 1:
throw new IllegalArgumentException("1 is a Wrong phase for init
user!");
case 2:
return generatePhase3Packet( packetReceived);
default:
throw new IllegalArgumentException("Wrong phase for this
protocol!");
}
68 Implementazione

Analoghi controlli sulle fasi sono fatti anche in SecondMillionaire, InitVoter e


CommonVoter. Nei test sono state controllate queste fasi. All’interno della classe
MillionaireProblemTest l’attenzione si concentra sul creare degli esempi verosimili
di dati generati dai dispositivi di una computazione per poi vedere non solo che
il risultato sia corretto, ma anche che i pacchetti generati contengono ad ogni fase
del protocollo i valori attesi, un esempio può essere il test della seconda fase,
questo è una codifica dell’esempio presentato nella parte teorica di questa tesi.
@Test
public void phase2isCorrect() {
InitMillionaire mp_a = new InitMillionaire(new BigInteger("4"), 4);
mp_a.setB_pubkey(new BigInteger("7"), new BigInteger("55"));
mp_a.setX(new BigInteger("39"));
SMCProtocolPacket packet1 = mp_a.generateInitializationPacket();

SecondMillionaire mp_b =
new SecondMillionaire(new BigInteger("2"), 4);
mp_b.setB_privkey(new BigInteger("23"), new BigInteger("55"));
mp_b.setP(new BigInteger("31"));
SMCProtocolPacket packet2 = mp_b.generateNextPacket(packet1);
Assert.assertEquals(2, packet2.getPhaseint());

List<Integer> valuesInt = new ArrayList<>();


for(BigInteger biginteger : packet2.getValues()){
valuesInt.add(biginteger.intValue());
}
Assert.assertEquals(Arrays.asList(26,18,3,9,31), valuesInt);
}

È stato anche testato il settaggio manuale di alcuni parametri, l’implementa-


zione del protocollo del milionario permette al secondo utente di settare manual-
mente il valore del numero primo p, ma questo valore non viene usato se non è
un valore adatto alla computazione, si veda SecondMillionaire.isGoodPrime(...) per
il dettaglio di funzionamento.

Votazione di un candidato Nel protocollo di voto i test risultano più complessi


poiché le parti della computazione sono almeno tre. I controlli sulle fasi sono
dinamici e dipendono dal numero di votanti, se i votanti sono n, il primo device
della computazione si aspetterà di ricevere un nuovo pacchetto alla fase n. Il test
VotingProblemTest.phase4IsTooSoon() controlla appunto che non si verifichi questa
situazione:
@Test(expected = IllegalArgumentException.class)
5.6 Strategie di testing 69

public void phase4IsTooSoon() {


InitVoter mp = new InitVoter(2,5,1);
SMCProtocolPacket packet0 = mp.generateInitializationPacket();

CommonVoter su1 = new CommonVoter(1);


SMCProtocolPacket packet1 = su1.generateNextPacket(packet0);
Assert.assertEquals(2,packet1.getPhaseint());
Assert.assertEquals(2,packet1.getValues().size());

CommonVoter su2 = new CommonVoter(1);


SMCProtocolPacket packet2 = su2.generateNextPacket(packet1);
Assert.assertEquals(3,packet2.getPhaseint());
Assert.assertEquals(2,packet2.getValues().size());

mp.generateNextPacket(packet2);
}

Nel protocollo di voto durante l’ultima fase, quando viene generato il pacchet-
to con il risultato della votazione si ha un controllo per verificare che non siano
state fatte manipolazioni dell’array.
In pratica avendo un array composto da una serie di numeri casuali ai quali
è sono stati aggiunti uno o più numeri è possibile, una volta sottratti i numeri
casuali generati durante l’inizializzazione, facendo una semplice somma dei voti
è possibile verificare che questa sia equivalente al numero di votanti: ad ogni
votante spetta un solo voto e tutti devono votare.
@Test(expected = IllegalArgumentException.class)
public void endingPhaseWithManipulationFail2() {
InitVoter mp = new InitVoter(2,3,1);
SMCProtocolPacket packet0 = mp.generateInitializationPacket();

CommonVoter su1 = new CommonVoter(1);


SMCProtocolPacket packet1 = su1.generateNextPacket(packet0);

CommonVoter su2 = new CommonVoter(0);


SMCProtocolPacket packet2 = su2.generateNextPacket(packet1);
packet2.getValues().set(1,BigInteger.ZERO);
mp.generateNextPacket(packet2);
}

Supponendo che uno dei votanti sappia per qualche motivo qual è il voto di
un altro votante, questo potrebbe sapere quale valore modificare e quindi togliere
uno o più voti ad un candidato ed aggiungerlo ad un altro. Questo equivarrebbe
a prendere dei fogli da un urna e aggiungerli ad un’altra, questa manipolazione
70 Implementazione

è destinata a non essere rilevata, anche se si suppone che vista la segretezza dei
voti tale sofisticazione non possa avvenire.
@Test
public void endingPhaseWithCleverManipulationCanNotFail() {
InitVoter mp = new InitVoter(2,3,1);
SMCProtocolPacket packet0 = mp.generateInitializationPacket();
// first user
CommonVoter su1 = new CommonVoter(1);
SMCProtocolPacket packet1 = su1.generateNextPacket(packet0);
// second user
CommonVoter su2 = new CommonVoter(1);
SMCProtocolPacket packet2 = su2.generateNextPacket(packet1);
//doing manipulation
packet2.getValues().set(0,
packet2.getValues().get(0).add(new BigInteger("2")));
packet2.getValues().set(1,
packet2.getValues().get(1).subtract(new BigInteger("2")));
mp.generateNextPacket(packet2);
}

Anche se il protocollo del milionario inizialmente prevedeva una implementa-


zione di RSA codificata nella classe RSAIntegers, per semplicità e visto che l’appli-
cazione android usava l’implementazione di RSA di java.security.KeyPair le chia-
vi usate sono quelle generate tramite il KeyPairGenerator, sono stati fatti dei test
per verificare che anche con queste chiavi di dimensione maggiore funzionasse
ancora tutto. I test per questi controlli sono contenuti in MillionaireProblemDefaul-
tKeygenTest e sono molto simili a quelli del MillionaireProblemTest.

5.7 Prestazioni dell’applicazione


Le prestazioni dei protocolli implementati possono essere valutate in diversi mo-
di. È possibile tramite i test unitari avere un’idea abbastanza precisa delle tem-
pistiche legate all’esecuzione di un protocollo, che sia nel caso del protocollo del
milionario che in quello dei votanti consiste di un’esecuzione di pochi secondi.
Diversa è la questione quando i protocolli vengono inseriti nel contesto del-
l’applicazione mobile, infatti oltre ai tempi per il discovery di dispositivi, la co-
struzione dei gruppi di computazione ed il setup, si aggiungono alcune latenze
dovute alla rete e alla comunicazione dei messaggi tra un dispositivo e l’altro.
Nel caso di test di performance effettuati sui dispositivi, bisogna togliere tutti
i tempi con attese di input da parte dell’utente e quindi considerare i tempi di
5.7 Prestazioni dell’applicazione 71

avvio del servizio, creazione del gruppo di computazione e i tempi trascorsi tra
l’invio del primo pacchetto del protocollo di SMC e l’invio del pacchetto con il
risultato.
Tutti i tempi sono stati presi sul dispositivo che inizializza la computazione,
in quanto esso ha una visuale più completa dei pacchetti che passano per la rete.

Protocollo del milionario in questo protocollo le parti che devono comunicare


sono due, quindi creare un gruppo per Wi-Fi Direct e scambiare le configurazioni
come la chiave pubblica dei dispositivi partecipanti richiede poco tempo, meno di
un paio di secondi sulla maggior parte dei dispositivi testati. I tempi per ottenere
una risposta una volta iniziato il protocollo sono di circa 4 secondi.

4298

ZENPHONE  2 1979

297

3600

NEXUS  9 1395

121

2322

NEXUS  6P 1543

198

3249

NEXUS  5 1542

220

0 500 1000 1500 2000 2500 3000 3500 4000 4500

TEMPO  TRA  I NVIO  PRIMO  PACCHETTO  E  I NVIO  SOLUZIONE  (MS)


TEMPO  CREAZIONE  E  CONFIGURAZIONE  RETE  DI  CALCOLO  (MS)
TEMPO  AVVIO  SERVIZIO  SU  WI-­‐FI  DIRECT  (MS)

Figura 5.3: Tempi per il protocollo del milionario

Protocollo di voto come nel protocollo del milionario, i tempi per l’avvio del
servizio rimangono al di sotto di 1s. Il tempo di creazione del gruppo aumenta
72 Implementazione

all’aumentare di partecipanti al protocollo. Dal numero di partecipanti dipende


anche il tempo per portare a termine il protocollo, poiché un maggior numero
di dispositivi implica un maggior numero di pacchetti scambiati e quindi più
latenze causate dal passaggio dei dati sulla rete.
Nell’esempio a tre parti i tempi dei setup per poter iniziare il protocollo si
attestano intorno ai 3s. Mentre si arriva anche a 7s per ottenere il risultato in caso
di rete molto trafficata.
Nell’esempio a quattro parti invece i tempi possono arrivare a 9s per l’esecu-
zione dell’intero protocollo, mentre il setup nel caso migliore si riesce a conclu-
dere in 3s.
5.7 Prestazioni dell’applicazione 73

6744

ZENPHONE  2 2880

184

5446

NEXUS  9 2659

264

5587

NEXUS  6P 2496

180

4743

NEXUS  5 2381

234

0 1000 2000 3000 4000 5000 6000 7000

TEMPO  TRA  I NVIO  PRIMO  PACCHETTO  E  I NVIO  SOLUZIONE  (MS)


TEMPO  CREAZIONE  E  CONFIGURAZIONE  RETE  DI  CALCOLO  (MS)
TEMPO  AVVIO  SERVIZIO  SU  WI-­‐FI  DIRECT  (MS)

Figura 5.4: Tempi per il protocollo di voto a tre partecipanti

8515

ZENPHONE  2 3980

211

6916

NEXUS  9 4178

170

7773

NEXUS  6P 3203

234

7339

NEXUS  5 4596

325

0 1000 2000 3000 4000 5000 6000 7000 8000

TEMPO  TRA  I NVIO  PRIMO  PACCHETTO  E  I NVIO  SOLUZIONE  (MS)


TEMPO  CREAZIONE  E  CONFIGURAZIONE  RETE  DI  CALCOLO  (MS)
TEMPO  AVVIO  SERVIZIO  SU  WI-­‐FI  DIRECT  (MS)

Figura 5.5: Tempi per il protocollo di voto a quattro partecipanti


74 Implementazione

Confronto protocolli come anticipato alcuni tempi sono costanti e non dipen-
dono dal tipo di protocollo, altri tempi come quelli di costruzione del gruppo di
computazione dipendono dai partecipanti alla computazione ed infine l’esecu-
zione del protocollo dipende sia dal numero di partecipanti al protocollo, sia dal
protocollo stesso: infatti un protocollo che prevede molte fasi durerà più a lungo
di uno che ne prevede poche. Nel caso del protocollo di voto il numero di fasi
dipende direttamente dal numero di partecipanti quindi le due variabili ovvero
numero di partecipanti e numero di fasi del protocollo, collidono.

AVVIO  SERVIZIO  SU  WI-­‐FI  DIRECT CREAZIONE  E  CONFIGURAZIONE  RETE  DI  CALCOLO
INVIO  PRIMO  PACCHETTO  E  I NVIO  SOLUZIONE

12000

10000

8000 7635

6000
5630

4000

3367

3989
2000

2604

1614

209 216 235


0
TEMPI   MEDI  PR OTOCOLLO   DEL   TEMPI   MEDI  VOTAZ I ONE   CON   3   TEMPI   MEDI  VOTAZ I ONE   CON   4  
MI LI ONARI O   (MS) PAR TECI PANTI   (MS) PAR TECI PANTI   (MS)

Figura 5.6: Tempi dei protocolli a confronto


5.8 Flusso applicativo 75

5.8 Flusso applicativo


Quando l’applicazione viene lanciata dall’utente, egli è invitato a compilare un
insieme di caselle dentro una maschera che servirà a decidere quale protocollo
lanciare e con quali modalità.

Figura 5.7: Prima schermata protocollo del milionario a sinistra e protocollo di


voto a destra

La prima casella permette di inserire il nome del dispositivo durante la com-


putazione, questo verrà mostrato in seguito agli altri dispositivi durante la fase
di discovery in cui si formerà il gruppo di utenti della computazione.
In seguito viene scelta la modalità di avvio: è possibile scegliere tra la modalità
di dispositivo inizializzatore e dispositivo secondario.
Questa scelta comporta una diversa visualizzazione della maschera di voto
ed in seguito un discovery di tipo diverso. È possibile scegliere a questo punto
il protocollo, la scelta ricade tra il protocollo del milionario ed il protocollo di
voto. Appena viene selezionato uno dei due protocolli viene anche mostrata la
maschera corrispondente: il protocollo del milionario mostra sempre una sola
casella, ovvero il numero di milioni posseduti dal milionario, mentre la maschera
del voto è variabile e dipende dalla modalità di avvio.
76 Implementazione

Se la modalità di avvio per il protocollo di voto è quella di utente inizializza-


tore verranno mostrate, in aggiunta alla casella di voto, le caselle con la scelta del
numero di dispositivi facenti parte alla computazione detti anche votanti (tre o
più) e il numero di candidati da votare.
Quando le caselle sono state tutte compilate correttamente viene avviata un
nuova schermata con il discovery dei dispositivi. Se il dispositivo ha scelto una
modalità di avvio come utente secondario, vedrà una lista di dispositivi inizializ-
zatori ai quali è possibile connettersi (di solito uno solo).

Figura 5.8: Schermata con il discovery dei dispositivi

Se il dispositivo è un utente inizializzatore vedrà una lista di dispositivi che si


stanno connettendo ad esso, sarà quindi possibile selezionarne un certo numero
(uno nel caso del milionario e il numero di votanti nel caso del protocollo di voto)
e premere il tasto avanti per cominciare la computazione.
5.8 Flusso applicativo 77

La schermata di computazione è semplicemente una schermata che mostra


qual è lo stato di invio dei pacchetti e alla fine mostra il risultato della computa-
zione.

Figura 5.9: Prima schermata protocollo del milionario a sinistra e protocollo di


voto a destra

Se in un qualsiasi momento una delle operazioni effettuate non è andata a


buon fine all’utente che ha avuto l’errore viene mostrato subito il problema veri-
ficatosi, mentre agli altri utenti viene comunicato che la computazione è fallita a
causa di un errore prodotto in un certo device.
78 Implementazione

Prima schermata
con inserimento dati

nome dispositivo
durante la
computazione

scelta della
modalità di avvio

scelta del
protocollo

mostra maschera modalità di


con inserimen- sì avvio è come voto protocollo
to voto, numero utente inizia- scelto?
votanti e candidati lizzatore?

milionario
no
mostra casella per
inserimento milioni
mostra casella per
inserimento voto
immissione
dei milioni

immissione vai a scherma-


immissione ta con discovery
votanti e
del voto dei dispositivi
candidati

Figura 5.10: Flusso applicativo durante l’immissione dei dati: nel primo rettan-
golo è possibile vedere, la parte comune, ai due protocolli, in quella arancione si
vede la parte relativa al protocollo di voto ed in quella blu quella del protocollo
del milionario.
Capitolo 6

Sviluppi futuri e conclusioni

6.1 Sviluppi futuri

L’applicazione mobile presentata in questa tesi vuole proporsi come una base sul-
la quale possano essere aggiunti altri tipi di protocolli a due o più parti; quindi
guardando agli sviluppi futuri, sarebbe interessante includere nel codice applica-
tivo un framework generico di SMC per estendere le possibilità computazionali.
Usando un framework di questo genere è possibile creare nuovi protocolli che
risolvono nuovi problemi, riusando l’infrastruttura implementata per questa tesi
che si occupa già di gestire dettagli tecnici come il networking e le interazioni tra
dispositivi.
Di framework per effettuare computazioni sicure ne esistono diversi, il più
noto dei quali è SPDZ [16], scritto in Java. Le difficoltà che si potrebbero riscon-
trare nella sua integrazione riguardano principalmente l’adattamento all’uso nel
mobile, poiché il loro utilizzo è previsto su una JVM standard e non su quella di
Android.
Fortunatamente negli ultimi tempi sono stati presentati nuovi framework SMC
per Android, ad esempio PCF [36] che però è solo two-party o una derivazio-
ne recente di Fairplay per il mobile [37] che usa come linguaggio SFDL (Secure
Function Definition Language) usato anche nella versione originale di Fairplay o
infine la libreria Whitewash [38] che permette di delegare una parte del lavoro ad
un sistema esterno.
Per supportare protocolli SMC generici si dovrebbe trovare un modo per ge-
nerare una schermata di immissione di dati usabile che tenga conto dei dati
necessari come input per effettuare la computazione.
80 Sviluppi futuri e conclusioni

Infatti, nell’applicazione sviluppata per questa tesi, l’interfaccia utente è spe-


cializzata nel mostrare e validare i campi solo per i due protocolli previsti: il
protocollo del milionario ha una sua schermata per l’immissione del numero di
milioni posseduti e il protocollo di voto ne ha un’altra che oltre all’immissione
del voto richiede il numero di partecipanti ed i candidati.

6.2 Conclusioni
Il mobile computing con il passare del tempo sta diventando sempre più comune
e con esso anche la necessità di nuove tecniche di calcolo privacy-preserving,
necessarie per consentire agli utenti di usufruire di applicazioni mobile, senza il
rischio di esporre informazioni private e mantenendo un alto grado di sicurezza.
Nell’ambito mobile, in particolare, le informazioni da proteggere sono nume-
rose: basti pensare al contenuto della rubrica o alle e-mail della casella di po-
sta e non per ultime le applicazioni in ambito bancario che permettono in pochi
passaggi di effettuare pagamenti dal proprio dispositivo.
Molti protocolli di SMC forniscono già gli strumenti per valutare funzioni in
modo sicuro sulle piattaforme desktop, dove la potenza di calcolo è abbondante
e non limitata da consumi di batteria. Purtroppo sono poche le piattaforme e
soluzioni che usano tali protocolli sulle piattaforme mobile.
Quindi la SMC può potenzialmente offrire un modo per preservare la priva-
tezza anche in ambito mobile, l’unico problema rimane l’efficienza di esecuzione.
Infatti per la valutazione di funzioni semplici la soluzione che prevede la costru-
zione protocolli appositi costruendo garbled circuits può essere considerata buo-
na, soprattutto se ci si trova in un contesto di calcolo in cui gli altri partecipanti
sono semi-onesti o curiosi.
Il problema nasce con la costruzione di circuiti molto grandi, per risolvere pro-
blemi più complessi, in questo caso il costo computazionale della costruzione di
un circuito diventa proibitivo sui dispositivi mobile nei quali si tenta di ottimiz-
zare i consumi e la durata della batteria piuttosto che aumentare le prestazioni
(e.g. clock della cpu e ram).
Una soluzione che è stata sperimentata è quella di unire circuiti garbled agli
schemi di cifratura omomorfica ([27], [26]). La cifratura omomorfica permette di
effettuare dei calcoli su degli input che sono stati cifrati per poi decifrare il risul-
tato che grazie alle proprietà del cifrario scelto corrisponde allo stesso risultato
che si otterrebbe operando sugli input non cifrati.
6.2 Conclusioni 81

Gli schemi di cifratura omomorfica sono ottimi per il processore ma pessimi


per la rete e la batteria: i testi cifrati sono molto lunghi e gli schemi di cifratura
a chiave pubblica possono pesare in modo significativo sul consumo di banda in
caso di funzioni complesse.
In un lavoro recente [28] è stato mostrato come incorporare pre-computazioni
sui token hardware per migliorare l’efficienza sui dispositivi mobili in ambienti
semi-onesti.
Tuttavia oltre al costo di valutazione dei protocolli SMC è stato dimostra-
to ([29], [30]) che anche con significative ottimizzazioni il compito di compilare
circuiti su un dispositivo mobile può essere lo stesso molto costoso.
Le nuove ricerche sull’ottimizzazione della SMC considerano anche l’ipote-
si della Server-assisted cryptography che consiste nel delegare una parte della
computazione su sistemi esterni [31] o ad un sistema cloud [33]. La crittografia
omomorfica è stata utilizzata per consentire l’outsourcing sicuro nelle applicazio-
ni di data mining [34] e per risolvere i problemi più comuni sui grafi [35], ma non
esistono soluzioni generiche che permettono di usare questa strategia in qualsiasi
caso. Altre modalità di delega di parte della computazione prevedono di effettua-
re la generazione del circuito ad un sistema esterno o di effettuare la valutazione
del garbled circuit [32].
Il futuro della SMC sembra procedere parallelamente in direzioni divergenti:
da una parte si ha l’integrazione di soluzioni che delegano parte della compu-
tazione a servizi esterni, dall’altra si tenta di ottimizzare la computazione, sfrut-
tando hardware specializzato o rendendo più performante quello generico. La
valutazione sicura di funzioni complesse sta diventando quindi una realtà anche
sui dispositivi mobile.
82 Sviluppi futuri e conclusioni
Bibliografia

[1] Wenliang Du and Mikhail J. Attalah, Secure multi-problem computation pro-


blems and their applications: A review and open problems, Tech. Report CE-
RIAS Tech Report 2001-51, Center for Education and Research in Informa-
tion Assurance and Security and Department of Computer Sciences, Purdue
University, West Lafayette, IN 47906, 2001.

[2] http://www.sigact.org/Prizes/Knuth/1996.html

[3] Peter Bogetoft, Dan Lund Christensen, Ivan Damgård, Martin Geisler, Tho-
mas Jakobsen, Mikkel Krøigaard, Janus Dam Nielsen, Jesper Buus Nielsen,
Kurt Nielsen, Jakob Pagter, Michael Schwartzbach, and Tomas Toft. 2009.
Secure Multiparty Computation Goes Live. In Financial Cryptography and Da-
ta Security, Roger Dingledine and Philippe Golle (Eds.). Lecture Notes In
Computer Science, Vol. 5628. Springer-Verlag, Berlin, Heidelberg 325-343.
DOI=http://dx.doi.org/10.1007/978-3-642-03549-4_20

[4] Dan Bogdanov, Riivo Talviste, Jan Willemson. Deploying secure multi-party
computation for financial data analysis (Short Paper). In Angelos Keromytis,
editor, Financial Cryptography and Data Security, LNCS 7397, pp. 57-64.
Springer, 2012.

[5] Joe Kilian. Secure Computation

[6] A. Shamir, R. Rivest, and L. Adleman, Mental Poker, Technical Report


LCS/TR-125, Massachusetts Institute of Technology, April 1979

[7] O. Goldreich, S. Micali, and A. Wigderson. How to play any mental game.
In Proceedings of the nineteenth annual ACM symposium on Theory of
computing, pages 218–229. ACM, 1987.

[8] Michael O. Rabin. How to exchange secrets by oblivious transfer. Technical


Report TR-81, Aiken Computation Laboratory, Harvard University, 1981
84 BIBLIOGRAFIA

[9] Ishai, Y.; Prabhakaran, M.; Sahai, A. (2008). Founding Cryptography on Obli-
vious Transfer – Efficiently 5157: 572–591. doi:10.1007/978-3-540-85174-5_32

[10] Quisquater, Jean-Jacques; Guillou, Louis C.; Berson, Thomas A. (1990). How
to Explain Zero-Knowledge Protocols to Your Children. Advances in Cryptology
– CRYPTO ’89: Proceedings 435: 628–631.

[11] Peter Snyder. Yao’s Garbled Circuits: "Recent Directions and Implementa-
tions"

[12] Yao, A. C. (1982). Protocols for secure computations

[13] M. Ito, A. Saito, and T. Nishizeki. Secret sharing schemes realizing general ac-
cess structures. In Proc. IEEE Global Telecommunication Conf., Globecom 87,
pages 99–102, 1987

[14] D. Bogdanov, S. Laur, J. Willemson, Sharemind: A Framework for Fast Privacy-


Preserving Computations, ESORICS ’08 Proceedings of the 13th European
Symposium on Research in Computer Security: Computer Security, Pages
192 - 206

[15] Adi Shamir. 1979. How to share a secret. Commun. ACM 22, 11 (November
1979), 612-613. DOI=http://dx.doi.org/10.1145/359168.359176

[16] I. Damgård, V. Pastro, N. Smart and S. Zakarias, Multiparty computation from


somewhat homomorphic encryption, Crypto 2012, vol. Springer LNCS 7417, pp.
643-662, 2012

[17] J. Nielsen, P. Nordholt, C. Orlandi and S. Burra, A new approach to practical


active-secure two-party computation, Crypto 2012, vol. Springer LNCS 7417,
pp. 681-700, 2012

[18] I. Damgard, M. Geisler, M. Krøigaard, and J. B. Nielsen, Asynchronous multi-


party computation: theory and implementation, in PKC’09, ser. LNCS, vol. 5443.
Springer, 2009, pp. 160–179.

[19] Y. Lindell and B. Pinkas, An efficient protocol for secure two-party computation in
the presence of malicious adversaries, Eurocrypt 2007, vol. Springer LNCS 4515,
pp. 52-78, 2007.

[20] A. Ben-David, N. Nisan and B. Pinkas, FairplayMP: a system for secure multi-
party computation, ACM CCS 2008, pp. 257-266, 2008
BIBLIOGRAFIA 85

[21] B. Pinkas, T. Schneider, N. Smart and S. Williams, Secure two-party com-


putation is practical, Asiacrypt 2009, vol. Springer LNCS 5912, pp. 250-267,
2009

[22] T. Frederiksen and J. Nielsen, Fast and maliciously secure two-pary computation
using the GPU, ACNS 2013, vol. Springer LNCS 7954, pp. 339-356, 2013

[23] https://www.bouncycastle.org/java.html

[24] https://rtyley.github.io/spongycastle/

[25] http://docs.oracle.com/javase/7/docs/technotes/guides/
security/StandardNames.html

[26] Gentry, C., Fully homomorphic encryption using ideal lattices, in Proceedings of
the Annual ACM Symposium on Theory of Computing, 2009.

[27] Rivest, R., Adleman, L., and Dertouzos, M., On data banks and privacy homo-
morphisms, in Proceedings of the IEEE Annual Symposium on Foundations
of Computer Science, 1978.

[28] Demmler, D., Schneider, T., and Zohner, M., Ad-hoc secure two-party compu-
tation on mobile devices using hardware tokens, in Proceedings of the USENIX
Security Symposium, 2014.

[29] Mood, B., Letaw, L., and Butler, K., Memory-efficient garbled circuit generation
for mobile devices, in Proceedings of the IFCA International Conference on
Financial Cryptography and Data Security (FC), 2012.

[30] Kreuter, B., Mood, B., shelat, a., and Butler, K., PCF: A portable circuit for-
mat for scalable two-party secure computation, in Proceedings of the USENIX
Security Symposium, 2013.

[31] Beaver, D., Server-assisted cryptography, in Proceedings of the workshop on


New security paradigms (NSPW), 1998.

[32] Kamara, S., Mohassel, P., and Riva, B., Salus: A system for server-aided secure
function evaluation, in Proceedings of the ACM conference on Computer and
communications security (CCS), 2012.

[33] Green, M., Hohenberger, S., and Waters, B., Outsourcing the Decryption of ABE
Ciphertexts, in Proceedings of the USENIX Security Symposium, 2011.
86 BIBLIOGRAFIA

[34] Kerschbaum, F., Collusion-resistant outsourcing of private set intersection, in


Proceedings of the ACM Symposium on Applied Computing, 2012.

[35] Blanton, M., Steele, A., and Alisagari, M., Data-oblivious graph algorithms
for secure computation and outsourcing, in Proceedings of the ACM SIGSAC
Symposium on Information, Computer and Communications Security, 2013.

[36] Kreuter, Benjamin, et al. PCF: A Portable Circuit Format for Scalable Two-Party
Secure Computation. Usenix Security. Vol. 13. 2013. APA

[37] Benjamin Mood, Lara Letaw, and Kevin Butler. Memory-efficient garbled cir-
cuit generation for mobile devices, Financial Cryptography and Data Security.
Springer Berlin Heidelberg, 2012. 254-268.

[38] Carter, Henry, Charles Lever, and Patrick Traynor. Whitewash: Outsourcing
garbled circuit generation for mobile devices. Proceedings of the 30th Annual
Computer Security Applications Conference. ACM, 2014.

Potrebbero piacerti anche