UNIVERSITÀ DEGLI STUDI DI UDINE -...

98
UNIVERSITÀ DEGLI STUDI DI UDINE Dipartimento di Ingegneria Elettrica, Gestionale e Meccanica Corso di Laurea in Ingegneria Gestionale Tesi di Laurea IMPLEMENTAZIONI DIDATTICHE DI ALGORITMI DI CIFRATURA PER SICUREZZA INFORMATICA Relatore: Laureando: Prof. Pier Luca Montessoro Pierpaolo Basso ANNO ACCADEMICO 2013/2014

Transcript of UNIVERSITÀ DEGLI STUDI DI UDINE -...

Page 1: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

UNIVERSITÀ DEGLI STUDI DI UDINE

Dipartimento di Ingegneria Elettrica, Gestionale e Meccanica

Corso di Laurea in Ingegneria Gestionale

Tesi di Laurea

IMPLEMENTAZIONI DIDATTICHE DI ALGORITMI DI CIFRATURA PER SICUREZZA INFORMATICA

Relatore: Laureando: Prof. Pier Luca Montessoro Pierpaolo Basso

ANNO ACCADEMICO 2013/2014

Page 2: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per
Page 3: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

Alla mia famiglia e a Veronica

Page 4: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per
Page 5: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

I  

Sommario La confidenzialità dei dati è uno dei requisiti essenziali nell'ambito della sicurezza informatica. Oggi, infatti, milioni di persone usano la rete per fare acquisti, per l’home banking e per molte altre applicazioni che richiedono la condivisione di informazioni personali. In tutti questi casi le comunicazioni avvengono attraverso canali pubblici, cioè non sicuri. La crittografia svolge, quindi, un ruolo fondamentale nel prevenire l’estrazione non autorizzata di informazioni da tali comunicazioni. In questa tesi viene realizzata l’implementazione di due algoritmi di cifratura che consentono una comunicazione sicura (cioè criptata) attraverso un canale pubblico: l’algoritmo Diffie-Hellman e l’algoritmo RSA. Innanzitutto, entrambi gli algoritmi saranno analizzati dal punto di vista teorico allo scopo di comprenderne le finalità e i contenuti. Dopodichè verrà presentata la loro implementazione in linguaggio C e C++. Per ciascuno di essi sarà, inoltre, proposto un esempio di utilizzo nella cifratura delle comunicazioni che avvengono attraverso la rete. L’attenzione sarà focalizzata principalmente sulla versione in C++ che verrà puntualmente confrontata con quella in linguaggio C. Il prodotto finale della tesi è costituito dall’insieme di classi e di librerire realizzate per implementare i due algoritmi e dai programmi per utilizzarle.

Page 6: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

II  

Page 7: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

III  

Indice Sommario I Indice III Indice delle figure V Introduzione VII 1 Linguaggio e librerie utilizzate 1 1.1 Scelte di progetto 1 1.2 Installazione del compilatore e delle librerie in Windows 3 1.2.1 Installazione del compilatore C/C++ in ambiente Cygwin 3 1.2.2 Installazione libreria GMP 4 1.3 Libreria udpsocketlib 6 2 Algoritmo Diffie-Hellman 11 2.1 Descrizione 11 2.1.1 Sicurezza 12 2.2 Scambio della chiave di cifratura: classe Dh 14 2.2.1 Funzioni crittografiche della classe Dh 17 2.3 Comunicazione criptata: libreria DhDataLib 19 2.4 Esempio di utilizzo 21 2.5 Confronto con la versione in C 24 3 Algoritmo RSA 27 3.1 Descrizione 27 3.1.1 Correttezza dell’algoritmo 28 3.2 Generazione delle chiavi di cifratura: classe Rsa 30 3.3 Comunicazione criptata: libreria RsaDataLib 34 3.4 Esempio di utilizzo 36 3.5 Confronto con la versione in C 39 Conclusioni 43 Bibliografia 45 Appendici 47 File in C++ 47 ClassDh.hpp 47 ClassDh.cpp 48 DhDataLib.hpp 53 DhDataLib.cpp 53 ClassRsa.hpp 56 ClassRsa.cpp 57 RsaDataLib.hpp 61

Page 8: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

IV  

RsaDataLib.cpp 61 File in C 64 DhLib.h 64 DhLib.c 65 DhDataLib.h 69 DhDataLib.c 70 Dh_c.c 73 Dh_s.c 74 RsaLib.h 75 RsaLib.c 76 RsaDataLib.h 81 RsaDataLib.c 81 Rsa_s.c 85 Rsa_c.c 86

Page 9: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

V  

Indice delle figure Figura 1.1 – Cygwin Setup 4 Figura 1.2 – Schema comunicazione via UDP 6 Figura 2.1 – Scambio di chiavi Diffie-Hellman 11 Figura 2.2 – Funzioni per lo scambio della chiave 15 Figura 3.1 – Funzioni per la creazione delle chiavi 31

Page 10: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

VI  

Page 11: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

VII  

Introduzione Lo scopo di questa tesi è di implementare in linguaggio C e C++ gli algoritmi crittografici Diffie-Hellman e RSA e di realizzare le librerie e i programmi necessari al loro utilizzo per cifrare le comunicazioni che avvengono attraverso la rete. È importante sottolineare la finalità didattica del lavoro svolto: per permettere la comprensione degli algoritmi sopracitati, tutto il codice è stato scritto in modo tale da presentare in dettaglio i passaggi da essi previsti. Nel primo capitolo vengono descritte le motivazioni che hanno portato all’utilizzo dei linguaggi di programmazione appena citati e gli strumenti necessari per la realizzazione della tesi. Il secondo capitolo è interamente dedicato all’algoritmo Diffie-Hellman. Innanzitutto l’algoritmo viene descritto in dettaglio e vengono analizzati i requisiti fondamentali per la sua sicurezza. Dopodichè viene illustrata la classe Dh che implementa in C++ sia l’algoritmo che le funzioni di cifratura e decifratura dei dati. Infine, viene descritta la libreria DhDataLib che consente di realizzare comunicazioni criptate grazie alla classe Dh. L’ultima parte del capitolo comprende i programmi (scritti in C++) che utilizzano questi strumenti e il confronto con la versione realizzata in linguaggio C. Il terzo capitolo, infine, è dedicato all’algortimo RSA. Anche in questo caso, come per il Diffie-Hellman, nella prima parte del capitolo si ha la descrizione dell’algortimo RSA e l’analisi della sua sicurezza. Dopodichè vengono illustrate la classe Rsa (scritta in linguaggio C++) che implementa l’algoritmo e la libreria RsaDataLib che la utilizza per cifrare le comunizioni in rete. Nell’ultima parte del capitolo vengono descritti i programmi (in C++) che utilizzano questi strumenti e viene analizzata la versione realizzata in linguaggio C.

Page 12: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

VIII  

Page 13: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

1  

1 Linguaggio e librerie utilizzate 1.1 Scelte di progetto Il linguaggio di programmazione utilizzato per l’implementazione degli algoritmi di crittografia trattati in questa tesi è il C++. Questa scelta è dettata da alcune caratteristiche offerte dal tale linguaggio che saranno illustrate brevemente in questo capitolo. Tuttavia, poiché lo scopo della tesi è un utilizzo didattico degli algoritmi implementati, è stata realizzata una versione parallela in C rivolta a chi non avesse studiato il C++. Data la natura didattica dell’implementazione, inoltre, i programmi realizzati (sia in C che in C++) sono stati sviluppati in modo tale da presentare esplicitamente tutti i passaggi degli algoritmi di cifratura: le operazioni svolte vengono, quindi, opportunamente evidenziate per permettere di comprendere il funzionamento degli algoritmi stessi. Gli algoritmi di crittografia richiedono la gestione di numeri interi molto grandi, non rappresentabili con i tipi di dato standard messi a disposizione da linguaggi di programmazione come il C e il C++. È stato, quindi, necessario l’utilizzo della libreria GMP (GNU Multiple Precision Arithmetic Library). Essa permette di lavorare agevolmente con numeri interi, razionali e in virgola mobile ponendo come unico limite la memoria disponibile del calcolatore. L’overloading degli operatori del C++ permette una naturale integrazione della libreria GMP. I tipi di dato introdotti da tale libreria possono, quindi, essere trattati allo stesso modo di quelli standard senza la necessità di utilizzare funzioni specifiche per le operazioni aritmetiche, logiche e di input/output, contrariamente a quanto accade in C. Tutto ciò si traduce in una maggiore semplicità e leggibilità del codice scritto in C++. Questo può essere considerato uno dei motivi per cui si è deciso di utilizzare tale linguaggio. Un’ulteriore motivazione alla scelta del C++ è rappresentata dalla gestione ottimale delle stringhe di caratteri offerta da questo linguaggio, aspetto rilevante nella programmazione connessa alla crittografia. Questa caratteristica è ancora più evidente nel confronto col C, linguaggio in cui la gestione delle stringhe è limitata ai soli vettori di caratteri. La scelta del C++ è stata dettata, inoltre, da motivazioni riguardanti la sicurezza. Le classi introdotte dal C++ supportano il principio dell'Information Hiding (nascondere le informazioni), comune ai linguaggi di programmazione Object-Oriented. All’interno di una classe, infatti, possono essere presenti sia sezioni pubbliche sia private. I dati e i metodi contenuti nella sezione pubblica di una classe sono gli unici accessibili dall’esterno. Le funzioni e i dati presenti nella sezione privata, invece, sono accessibili solamente ai metodi di classe, mentre risultano invisibili all’esterno. È quindi possibile proteggere le chiavi di cifratura e le altre variabili inserendole nella sezione privata della classe. Così facendo le chiavi di cifratura non sono direttamente accessibili dall’esterno ma possono essere generate, modificate e utilizzate solamente attraverso i metodi pubblici della classe. Questo determina un livello di sicurezza più elevato e una maggiore robustezza dal punto di vista dell’ingegneria del software.

Page 14: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

2  

Nella realizzazione della tesi è stato necessario utilizzare altre due librerie, oltre alla già citata GMP:

• La libreria udpsocketlib, appartenente alla libreria socketlib sviluppata dal prof. Montessoro. Quest’ultima è una libreria di funzioni per la scrittura semplificata di applicazioni client/server con i protocolli TCP e UDP. Gli algoritmi implementati prevedono, infatti, la presenza di due parti che devono generare e scambiare una chiave di crittografia attraverso la rete (quindi un canale non sicuro) per poi condividere dati cifrati. È stata quindi utilizzata la libreria udpsocketlib per permettere alle due parti di dialogare attraverso la rete tramite il protocollo UDP. In conformità con tale libreria, possiamo pensare a esse come a un client e a un server che comunicano.

• La libreria OpenSSL, utilizzata per generare numeri primi pseudo-casuali da 512 e da 1024 bit.

Le principali funzioni utilizzate delle librerie GMP e OpenSSL saranno analizzate, se necessario, nei capitoli successivi, non appena le si incontrerà nel codice scritto. Viceversa, si ritiene opportuno descrivere più in dettaglio le funzioni della libreria udpsocketlib utilizzate per lo scambio di dati in rete attraverso il protocollo UDP. Questo argomento verrà trattato nel punto 1.3.

Page 15: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

3  

1.2 Installazione del compilatore e delle librerie in Windows Per l’implementazione degli algoritmi considerati in C/C++, ma più in generale per la realizzazione di programmi scritti in tali linguaggi, un primo passo fondamentale è l’installazione del compilatore e dei pacchetti necessari al suo funzionamento. Il compilatore, infatti, è fondamentale per tradurre il codice scritto in un programma eseguibile. In ambiente Windows la scelta è stata di installare il compilatore Cygwin GNU C/C++. Nel processo d’installazione, come vedremo tra breve, è possibile selezionare tra i diversi pacchetti disponibili anche la libreria OpenSSL. La presenza del compilatore, infine, è fondamentale per poter installare la libreria GMP che rappresenta una componente di grande rilevanza per la realizzazione della tesi. Le operazioni fondamentali da eseguire sono, nell’ordine:

• Installazione del compilatore Cygwin GNU C/C++, compresa la libreria OpenSSL.

• Installazione della libreria GMP. Per quanto riguarda la libreria “socketlib”, è sufficiente scaricarla dal sito del docente [1] e includere i file sorgenti necessari, ovvero “udpsocketlib.hpp” e “udpsocketlib.cpp” per il C++ e “udpsocketlib.h” e “udpsocketlib.c” per il C. 1.2.1 Installazione del compilatore C/C++ in ambiente Cygwin Innanzitutto è necessario collegarsi al sito di Cygwin [2] per ottenere i file di installazione. È necessario, quindi, scaricare il programma d’installazione “setup.exe” nella versione corretta per la propria architettura, 32 o 64 bit. Fatto ciò, si deve avviare il setup e selezionare la voce “Install from Internet” (ovviamente è richiesta una connessione a internet per scaricare i pacchetti necessari). Dopodiché è sufficiente avanzare senza modificare nulla fino alla schermata “Select packages”. In questa pagina è necessario selezionare alcuni pacchetti aggiuntivi rispetto alla configurazione di default prevista dal programma d’installazione. In particolare, devono essere selezionati i seguenti pacchetti all’interno delle corrispondenti categorie:

• nella categoria “Devel”: cmake, gcc-core, gcc-g++, gdb, git, make • nella categoria “Interpreters”: m4 • nella categoria “Net”: openssl-devel

Per selezionare questi pacchetti aggiuntivi basta espandere la relativa categoria, individuare il pacchetto desiderato e cliccare una sola volta su “Skip”, così da far apparire il numero indicante l’ultima versione disponibile.

Page 16: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

4  

Vediamo un esempio in figura 1.1:

Questa configurazione permette, quindi, di installare il compilatore GNU C/C++ (gcc-core, gcc-g++), la libreria OpenSSL (openssl-devel) e alcuni componenti aggiuntivi necessari per un corretto funzionamento. Una volta aggiunti i pacchetti indicati è sufficiente avanzare senza modificare nulla fino a quando il download e l’installazione saranno terminati. Nella pagina immediatamente successiva a quella di selezione dei pacchetti, ovvero la pagina con titolo “Resolving dependancies”, è fondamentale che sia selezionata l’opzione “Select required packages”. L'installazione crea così un'icona, un collegamento indicato con "Cygwin Terminal", che consente di eseguire una shell (finestra di comandi) in cui è possibile utilizzare alcuni comandi Unix e il compilatore C/C++. 1.2.2 Installazione libreria GMP La libreria GMP può essere reperita dal sito di GMP[3]. Dopo aver scaricato ed estratto gli archivi, si deve aprire la shell “Cygwin Terminal”, installata come visto in precedenza. Si deve ora cambiare il direttorio corrente (tramite il comando “cd”) spostandosi nella cartella contenente i file della libreria GMP appena estratti. Per maggior chiarezza, si deve spostare il direttorio corrente nella cartella della libreria GMP

Figura 1.1 - Cygwin Setup

Page 17: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

5  

contenente il file “configure”. A questo punto si deve digitare nel terminale il comando “./configure --enable-cxx ”, premere invio e attendere il completamento dell’operazione. Dopodiché si deve fare lo stesso col comando “make”. Per verificare la corretta esecuzione delle operazioni precedenti si deve digitare “make check” nel terminale e premere invio. Terminati i diversi test avviati dal comando precedente, se non sono stati riscontrati errori, si deve digitare “make install” nel terminale e attendere il completamento di quest’ultima operazione. La libreria GMP dovrebbe, così, essere correttamente installata per entrambi i linguaggi C e C++.

Page 18: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

6  

1.3 Libreria udpsocketlib Il protocollo UDP (User Datagram Protocol) è un protocollo di livello di trasporto non orientato alla connessione. Il protocollo UDP si appoggia direttamente sopra IP, i dati vengono inviati in forma di datagram e non ne è assicurata né l’effettiva ricezione né l'arrivo nell'ordine in cui vengono trasmessi. Non viene gestito, inoltre, né il riordinamento dei pacchetti né la ritrasmissione di quelli non ricevuti. Di conseguenza il protocollo UDP è considerato non affidabile. In compenso è molto veloce ed efficiente: minimizza i ritardi poiché non si ha ritrasmissione e riordinamento dei dati ed essendo non connesso non presenta overhead dovuto ai pacchetti di servizio necessari per stabilire, mantenere e chiudere una connessione. Queste caratteristiche fanno sì che l’UDP sia particolarmente conveniente quando si opera su rete locale. La probabilità estremamente bassa di perdita di dati che contraddistingue le reti locali permette, infatti, di sfruttare appieno la rapidità e l’efficienza del protocollo. Le reti locali rappresentano esattamente l’ambito applicativo per cui sono stati implementati gli algoritmi trattati in questa tesi. Di conseguenza, nei programmi realizzati si è deciso di utilizzare il protocollo UDP per lo scambio di dati in rete. Come detto, i socket UDP supportano una comunicazione di tipo datagram. Tutto ciò che avviene, quindi, in una comunicazione attraverso socket UDP è la trasmissione di un pacchetto da un client a un server o viceversa, secondo lo schema in figura 1.2.

Come illustrato in figura 1.2, un server UDP, dopo aver creato il socket tramite la funzione socket, esegue la primitiva bind per associare un indirizzo di rete al socket stesso. Un client UDP, invece, deve creare solamente il socket. Dopodiché entrambe le parti utilizzano direttamente le funzioni sendto e recvfrom per inviare e ricevere dati.

Figura 1.2 - Schema comunicazione via UDP

client socket()

recvfrom()

sendto()

server socket()

bind()

sendto()

recvfrom()

Page 19: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

7  

Nelle applicazioni realizzate in questa tesi, come detto in precedenza, ci si è serviti della libreria udpsocketlib per utilizzare i socket UDP. È opportuno, quindi, analizzare le funzioni messe a disposizione da tale libreria per permettere a un client e a un server di comunicare in rete attraverso il protocollo UDP secondo lo schema visto. Innanzitutto il server esegue la funzione create_udp_server di cui riportiamo di seguito il codice. 1      int  create_udp_server(char  *ip_address,  int  port)  2      {  3              int  sk;  4              struct  sockaddr_in  srv;  5              /*  create  a  socket  descriptor  */  6              if  ((sk  =  socket(AF_INET,  SOCK_DGRAM,  0))  <  0)  7              {  8                      error_handler("socket()  [create_udp_server()]");  9                      return  -­‐1;  10            }  11            /*  fill  the  (used)  fields  of  the  socket  address  with  12                  the  server  information  (local  socket  address)  */  13            bzero((char  *)  &srv,  sizeof(srv));  14            srv.sin_family  =  AF_INET;  15            srv.sin_addr.s_addr  =  inet_addr(ip_address);  16            srv.sin_port  =  htons(port);  17            /*  add  the  local  socket  address  to  the  socket  descriptor  */  18            if  (bind(sk,  (struct  sockaddr  *)  &srv,  sizeof(srv))  <  0)  19            {  20                    error_handler("bind()  [create_udp_server()]");  21                    return  -­‐1;  22            }  23            return  sk;  24    }   Da notare la chiamata alla primitiva socket (linea 6), la quale crea il socket e i cui parametri specificano:

• La famiglia di protocolli da usare. “AF_INET” indica il protocollo IPv4. • Il tipo di servizio. “SOCK_DGRAM” indica l’utilizzo dei datagram. • Il protocollo da usare con il socket. “0” indica che il protocollo usato è

quello di default per la combinazione di dominio e tipo specificata dagli altri due parametri.

La funzione socket, restituisce un intero (assegnato a sk) che sarà usato per i riferimenti al socket stesso. Dopodiché viene eseguita la funzione bind (linea 21) che associa al socket un indirizzo di rete costituito dall’indirizzo IPv4 del server e dalla porta locale su cui attende i dati. Questi dati sono inseriti all’interno di una struct sockaddr (linee 14÷16) passata come parametro alla funzione bind insieme al riferimento sk al socket. A questo punto, il client esegue la funzione create_udp_client con cui viene creato il socket (linea 5) attraverso la primitiva socket nello stesso modo visto per il server.

Page 20: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

8  

Il codice della funzione è riportato di seguito. 1 int  create_udp_client(void)  2      {  3              int  sk;  4              /*  create  a  socket  descriptor  */  5              if  ((sk  =  socket(AF_INET,  SOCK_DGRAM,  0))  <  0)  6              {  7                      error_handler("socket()  [create_udp_client()]");  8                      return  -­‐1;  9              }  10            return  sk;  11    }    Client e server possono, quindi, utilizzare le funzioni di libreria udp_send e udp_receive per scambiare dati tra loro. Riportiamo di seguito il codice di entrambe. Da notare in udp_send l’utilizzo della funzione sendto (linea 12) i cui parametri principali sono: una struct sockaddr_in ska in cui sono stati inseriti l’indirizzo IPv4 e la porta del destinatario (linee 8÷10), il riferimento al socket sk e la stringa buffer da inviare. 1      int  udp_send(int  sk,  char  *buffer,  char  *ip_address,  int  port)  2      {  3              struct  sockaddr_in  ska;  4              int  msg_len  =  strlen(buffer);  5              /*  fill  the  (used)  fields  of  the  socket  address  with  6                  the  server  information  (remote  socket  address)  */  7              bzero((char  *)  &ska,  sizeof(ska));  8              ska.sin_family  =  AF_INET;  9              ska.sin_addr.s_addr  =  inet_addr(ip_address);  10            ska.sin_port  =  htons((unsigned  short)  port);  11  12            if  (sendto(sk,  buffer,  msg_len,  0,  (struct  sockaddr  *)  &ska,  

sizeof(ska))  !=  msg_len)  13            {  14                    error_handler("sendto()  [udp_send()]");  15                    return  0;  16            }  17            return  1;  18    }   In udp_receive si osserva la chiamata della funzione recvfrom (linea 24). I parametri più rilevanti sono: il numero intero sk (riferimento al socket), la stringa di caratteri buffer in cui saranno inseriti i dati ricevuti e la struct reply_to_socket_address in cui è memorizzato l’indirizzo del mittente. 1      int  udp_receive(int  sk,  char  *buffer)  2      {  3              int  dim;  4              len_of_reply_to_socket_address  =  sizeof(reply_to_socket_address);  5              if  ((dim  =  recvfrom(sk,  buffer,  BUFSIZ,  0,  (struct  sockaddr  *)  

&reply_to_socket_address,  (int  *)  &len_of_reply_to_socket_address))  <  0)  

6              {  

Page 21: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

9  

7                      error_handler("recvfrom()  [udp_receive()]");  8                      return  -­‐1;  9              }  10            buffer[dim]  =  '\0';  11            return  dim;  12    }    Quest’ultimo dato, inoltre, è usato della funzione udp_reply per rispondere al mittente dell’ultimo pacchetto ricevuto. Nel codice si nota, infatti, come alla funzione sendto è passata la struct reply_to_socket_address (linea 5). 1      int  udp_reply(int  sk,  char  *buffer)  2      {  3              int  msg_len  =  strlen(buffer);  4              if  (sendto(sk,  buffer,  msg_len,  0,  (struct  sockaddr  *)  

&reply_to_socket_address,  len_of_reply_to_socket_address)  <  0)  5              {  6                      error_handler("sendto()  [udp_reply()]");  7                      return  0;  8              }  9              return  1;  10    }   È importante, quindi, notare come, a differenza della funzione udp_send, a udp_reply non è passato alcun indirizzo di rete come parametro. Questa può, quindi, essere usata solamente a seguito della ricezione di un pacchetto per rispondere al mittente. Terminato lo scambio di dati tra client e server, entrambe chiamano la funzione close_udp_socket. La funzione close chiude il socket creato e rilascia tutte le risorse ad esso allocate (linea 3). 1      int  close_udp_socket(int  sk)  2      {  3              if  (close(sk)  !=  0)  4              {  5                      error_handler("close()  [close_udp_socket()]");  6                      return  0;  7              }  8              return  1;  9      }  

Page 22: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

10  

Page 23: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

11  

2 Algoritmo Diffie-Hellman 2.1 Descrizione L’algoritmo Diffie-Hellman è stato proposto nel 1976 da Whitfield Diffie e Martin E. Hellman, due crittografi statunitensi, nell’articolo “New Directions in Cryptography” [4]. Questo algoritmo ha rappresentato una soluzione innovativa ad uno dei problemi classici della crittografia, ovvero la distribuzione delle chiavi di cifratura. Uno dei principali ambiti applicativi della crittografia è la garanzia della privacy. La criptazione delle comunicazioni che avvengono attraverso un canale non sicuro (pubblico) diventa, quindi, fondamentale per prevenire l’estrazione non autorizzata di informazioni da esse. Di conseguenza, è necessario che le parti in comunicazione condividano una chiave crittografica che non sia nota a nessun altro. Si presenta, dunque, il problema della generazione e della distribuzione di tale chiave. Questo può essere risolto inviando la chiave di cifratura in anticipo alle parti coinvolte attraverso un canale sicuro come ad esempio un corriere o la posta raccomandata. Tuttavia, i ritardi e i costi introdotti da questa modalità di distribuzione non sono accettabili nella maggior parte delle applicazioni pratiche, specialmente in ambito commerciale. L’algoritmo proposto nell’articolo [4] offre un approccio differente al problema, eliminando, di fatto, la necessità di un canale sicuro per la condivisione delle chiavi. Noto come “Diffie-Hellman key exchange” (scambio di chiavi Diffie-Hellman), tale algoritmo crittografico consente a due parti di stabilire una chiave di cifratura condivisa e segreta attraverso un canale di comunicazione insicuro (pubblico), senza la necessità che queste si siano scambiate informazioni in precedenza. La figura 2.1 illustra i passi dell’algoritmo che portano allo scambio della chiave di cifratura K condivisa fra le due parti.

Figura 2.1 - Scambio di chiavi Diffie-Hellman

Page 24: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

12  

Come visto nel capitolo 1, possiamo pensare alle due parti come a un client e a un server che si scambiano una chiave di cifratura. Il client, innanzitutto, genera un numero primo p molto elevato di almeno 1024 bit (cioè circa 300 cifre decimali) e un generatore g di Zp

* (che deve esistere essendo p primo). In aritmetica modulare un generatore modulo p (detto semplicemente generatore) è un intero g le cui potenze modulo p sono congruenti con i numeri coprimi a p. Ovvero g è un intero che elevato a potenza genera tutti i numeri coprimi a p. In particolare, è possibile dimostrare che se p è primo esiste sicuramente un generatore g che produce tutti gli elementi di Zp

*, in altre parole i numeri compresi tra 1 e (p -1). Vedremo nel seguito del capitolo il metodo implementato per trovare un generatore di Zp

*. Il client genera quindi un numero casuale a < p e calcola A = ga mod p. Come evidenziato in figura 2.1, i numeri p, g, A sono comunicati pubblicamente al server mentre a non viene condiviso. In modo analogo il server genera un numero casuale b < p, calcola B = gb mod p e lo invia al client. Entrambe le parti possono quindi calcolare la chiave di cifratura K:

• Il client calcola K = Ba mod p. • Il server calcola K = Ab mod p.

Come indica l’ultimo passaggio in figura 2.1, client e server trovano lo stesso valore per K. Per le proprietà dell’aritmetica modulare, infatti, si ha che: K = Ab mod p = (ga mod p)b mod p = gab mod p = (gb mod p)a mod p = Ba mod p La chiave ottenuta può essere, quindi, utilizzata per crittografare le successive comunicazioni fra le due parti mediante un algoritmo di cifratura a chiave simmetrica. In questa tesi, a titolo di esempio applicativo, è stato implementato un algoritmo di cifratura simmetrica che, come vedremo nel seguito del capitolo, esegue l’XOR bit a bit fra la chiave crittografica generata e i dati in chiaro da inviare. 2.1.1 Sicurezza La sicurezza dell’algoritmo si basa sulla complessità computazionale del calcolo del logaritmo discreto. Una terza parte può intercettare i parametri p, g, A, B ma non è in grado di calcolare la chiave di cifratura K non conoscendo a o b. Non essendo stati condivisi, l’unico modo per determinare questi numeri è risolvere il problema del logaritmo discreto, infatti:

• a = logg A mod p • b = logg B mod p

La sicurezza dell’algoritmo, quindi, è garantita fino a quando il calcolo del logaritmo discreto è computazionalmente proibitivo.

Page 25: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

13  

A tale scopo, il generatore g gioca un ruolo fondamentale. Come documentato nei siti [5] e [6], affinché l’algoritmo Diffie-Hellman sia sicuro non è necessario che il generatore produca tutti gli interi modulo p non nulli, ma è sufficiente che il sottogruppo di Zp

* generato da g sia tale da rendere elevata la complessità computazionale del logaritmo discreto. Per ottenere ciò devono essere soddisfatte le seguenti condizioni:

• p sia un numero primo generato in modo casuale e sufficientemente grande, almeno 1024 bit.

• il generatore g ha ordine r che è il più piccolo intero per cui gr = 1 mod p. Il

più grande divisore primo di r deve essere elevato, di almeno 2k bit, dove k bit è il livello di sicurezza desiderato.

La prima condizione può essere facilmente soddisfatta grazie alle numerose librerie disponibili per la generazione di numeri primi casuali, come vedremo nell’implementazione realizzata dell’algoritmo. Fare in modo che l’ordine r del generatore scelto abbia un divisore primo sufficientemente grande, invece, può essere più complesso. È conveniente, quindi, procedere nel modo descritto di seguito (come indicato nel sito [6]). Si deve, innanzitutto, generare un numero primo casuale p “sicuro”, cioè tale che (p-1)/2 sia anch’esso primo. Indichiamo con q il numero (p-1)/2 e quindi possiamo esprimere p come p = 2q +1. Poiché p deve essere un numero primo sufficientemente grande, anche q lo sarà. Si può dimostrare che un qualunque intero casuale g modulo p non nullo ha ordine r pari a 1, 2, q o 2q. Gli ordini pari a 1 e 2 si ottengono rispettivamente per g uguale a 1 e (p-1). Qualunque altro intero casuale g compreso nell’intervallo [2, (p-2)] avrà, quindi, ordine r pari a q o 2q e può quindi essere usato come generatore per l’algoritmo Diffie-Hellman. Infatti, essendo q un numero primo sufficientemente grande, l’ordine r del generatore sarà elevato, come richiesto per la sicurezza dell’algoritmo. Soddisfatte queste condizioni, per una terza parte che intercetta la comunicazione è pressoché impossibile ricostruire la chiave scambiata dalle informazioni ottenute. Purtroppo l'algoritmo Diffie-Hellman è vulnerabile all'attacco "Man in the middle" (del terzo uomo interposto). Supponiamo che una terza parte intercetti il parametro A che il client invia al server con cui vuole comunicare. Questa può generare, fingendosi il server, un suo numero B e inviarlo al client scambiando così una chiave di cifratura condivisa. In modo del tutto analogo, questa terza parte può generare una chiave condivisa col server e, da qui in avanti, intercettare e leggere tutta la corrispondenza tra i due. Per prevenire simili attacchi, la soluzione è di usare un ente certificatore che garantisca l'identità dei corrispondenti.

Page 26: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

14  

2.2 Scambio della chiave di cifratura: classe Dh Analizziamo, quindi, l’implementazione dell’algoritmo Diffie-Hellman realizzata in questa tesi. Nella versione in linguaggio C++ è stata creata la classe Dh, la quale consente lo scambio di una chiave crittografica secondo le modalità previste dall’algoritmo e, inoltre, gestisce la cifratura e la decifratura dei dati attraverso tale chiave. L’interfaccia della classe Dh e l’implementazione dei suoi metodi sono interamente riportate in appendice, rispettivamente in ClassDh.hpp e ClassDh.cpp. Tuttavia, per semplicità di consultazione, ne richiamiamo di seguito la dichiarazione. 14    class  Dh  15    {  16            public:  17                    mpz_class  ReturnKey()  const  {  return  K;  }  18                    int  SizeOfK()  const  {  return  mpz_sizeinbase(K.get_mpz_t(),  

10);}  19                    bool  GenerateEncryptionKey_Client(int  socket,  string  

ipAddress,  int  udpPort);  20                    bool  GenerateEncryptionKey_Server(int  socket);  21                    string  DhEncrypt(const  string&  toEncryptStr);  22                    string  DhDecrypt(const  char*  toDecrypt);  23  24            private:  25                    mpz_class  p,  g,  a,  b,  A,  B;  26                    mpz_class  K;  //key  27                    mpz_class  GetVariable(string  varName);  28                    mpz_class  GeneratePrimeNumber(string  name,  unsigned  numBits);  29                    mpz_class  FindGenerator();  30                    void  GetPgaAndSetA(int  choice);  31                    bool  SendPGA(int  socket,  string  ipAddress,  int  udpPort);  32                    bool  ReceiveBandComputeK(int  socket);  33                    bool  ReceivePGA(int  socket);  34                    bool  SendB(int  socket);  35                    void  ComputeBandKey();  36                    int  rdtsc();  37    };   Da notare, innanzitutto, come le variabili dell’algoritmo p, g, a, b, A, B nonché la chiave di cifratura K siano inserite nella parte privata, secondo il principio dell’information hiding (linee 25 e 26). Chi utilizza la classe, quindi, non può accedere direttamente a questi dati ma può solamente ricorrere ai metodi presenti nella sua parte pubblica. Tutto ciò si traduce in una maggior sicurezza poiché la chiave di cifratura e tutte le variabili che permettono di generarla non possono essere modificate in modo indiscriminato ma solamente secondo le modalità previste dalle funzioni pubbliche della classe. Osserviamo, inoltre, come questi parametri siano di tipo mpz_class. Questa, infatti, è la classe messa a disposizione dalla libreria GMP per la gestione di numeri interi molto elevati.

Page 27: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

15  

Lo scambio della chiave crittografica fra due parti, qui pensate come un client e un server, è realizzato dai metodi pubblici GenerateEncryptionKey_Client() e GenerateEncryptionKey_Server(). Essi utilizzano le funzioni della parte privata della classe Dh per accedere alle variabili dell’algoritmo e impostarne i valori, come evidenziato in figura 2.2. La figura 2.2, riportata di seguito, rappresenta in dettaglio la successione delle chiamate alle funzioni di classe.

Lo scambio della chiave ha inizio col client che chiama il metodo pubblico GenerateEncryptionKey_Client() (linee 182÷209 in appendice). Come evidenziato in figura 2.2, questo metodo prevede l’esecuzione di tre funzioni private della classe Dh, la prima delle quali è GetPgaAndSetA() che imposta i parametri p, g, a, A. L’utente del client può lasciare che sia il calcolatore a generare i due parametri principali p, g oppure inserirli manualmente (linee 184÷194). La seconda possibilità è certamente utile dal punto di vista didattico poiché permette all’utente di osservare il funzionamento dell’algoritmo con diverse combinazioni dei suoi parametri. Tuttavia, la generazione manuale di numeri interi molto elevati che soddisfino i criteri di sicurezza richiesti risulta estremamente complessa. A questo scopo è, quindi, possibile selezionare la prima opzione che garantisce l’affidabilità dell’algoritmo. La funzione GetPgaAndSetA() riceve come parametro d’ingresso un intero choice che rappresenta la scelta fatta dall’utente: 1 se viene scelta la prima opzione, 2 per la seconda (linea 196).

Figura 2.2 - Funzioni per lo scambio della chiave

GenerateEncryptionKey_Client()

GetPgaAndSetA()

SendPGA()

ReceiveBandComputeK()

GenerateEncryptionKey_Server()

ReceivePGA()

ComputeBandKey()

SendB()

client server

Page 28: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

16  

Nel primo caso, la generazione dei parametri avviene in questo modo:

• p viene creato dalla funzione GeneratePrimeNumber() (linea 24 in appendice) a cui viene passato in ingresso un intero numBits, oltre ad una stringa name che indica il nome della variabile (p in questo caso). La funzione utilizza il metodo BN_generate_prime_ex() fornito dalla libreria OpenSSL per generare un numero primo pseudo-casuale di almeno numBits bit di lunghezza; qui è stato utilizzato un valore di 1024 bit (linea 78 in appendice). Il terzo parametro passato a BN_generate_prime_ex() è un intero di valore uno; questo indica alla funzione di generare un numero primo “sicuro”. Da notare come la libreria OpenSSL utilizzi il tipo di dato BIGNUM e sia, quindi, necessaria una conversione intermedia in una stringa per tradurlo in un intero mpz_class (linea 80 in appendice). In C++ questo passaggio risulta, di fatto, trasparente: grazie all’overload dell’operatore “=”, è, infatti, possibile assegnare all’intero mpz_class la stringa restituita dalla funzione BN_bn2dec() corrispondente al numero primo generato. Il parametro p così creato è, quindi, un numero primo pseudo-casuale di almeno 1024 bit “sicuro”, cioè tale che anche (p-1)/2 è primo.

• g viene generato dalla funzione FindGenerator(). Come visto in precedenza, poiché p è un numero primo “sicuro”, è possibile utilizzare come generatore un numero intero casuale di valore compreso fra 2 e p-2. Questo è esattamente il compito svolto dalla funzione sopraccitata. Innanzitutto viene prodotto un intero casuale size minore o uguale al numero di cifre di p-2. Questa sarà la dimensione del generatore. Infatti, viene generato un numero size di interi casuali che vanno a costituire le cifre di g nel seguente modo: se size è uguale alla dimensione di p-2, allora ogni cifra di g è generata come intero casuale minore di quella corrispondente in p-2 altrimenti come intero casuale compreso tra 0 e 9. Questo garantisce che il generatore sia un numero casuale minore di p-2 (linee 48÷65 in appendice). Se si dovesse ottenere un valore di g pari a 2, la procedura verrebbe ripetuta. Da notare l’utilizzo del numero di cicli di clock della CPU come seme per srand(). Questa informazione è fornita dall’istruzione assembly rdtsc (eseguita dall’omonima funzione della classe Dh) e garantisce una migliore randomizzazione essendo un numero che varia in modo estremamente rapido e difficilmente prevedibile.

Nel secondo caso, invece, viene chiamata la funzione GetVariable() per permettere all’utente del client di inserire i valori di p e g desiderati. Dopodiché, indipendentemente da come sono stati generati i due parametri, all’utente spetta il compito di scegliere e inserire un valore casuale a minore di p (sempre attraverso la funzione GetVariable()); a questo punto A viene calcolato come A = ga mod p (linee 32 e 34 in appendice). Da notare come la funzione mpz_powm() fornita dalla libreria GMP per l’elevamento a potenza esegua interamente il calcolo precedente, compresa l’operazione di modulo. Come si vede nel codice in appendice, infatti, la funzione accetta quattro parametri: rispettivamente A (in cui è salvato il risultato dell’operazione), la base g, l’esponente a e il divisore p.

Page 29: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

17  

Al client non resta che comunicare p, g e A al server tramite il metodo privato SendPGA(). Come evidenziato in figura 2.2, infatti, contemporaneamente al client, il server esegue la funzione GenerateEncryptionKey_Server() e si mette in attesa di questi tre parametri chiamando ReceivePGA(). Se entrambe le operazioni hanno successo, il server procede generando b, calcolando B e la chiave di cifratura K tramite la funzione privata ComputeBandKey(). All’utente del server viene chiesto, quindi, di inserire un numero intero casuale b diverso da uno ma minore di p; dopodichè si procede al calcolo di B = gb mod p e quindi di K = Ab mod p (linee 174÷178 in appendice). Il server mantiene segreto il numero b scelto e la chiave K ma condivide B chiamando la funzione SendB(). Il client tramite il metodo ReceiveBandComputeK() può infine ricevere B e calcolare K = Ba mod p (linee 109÷118 in appendice). Le chiavi così calcolate dalle due parti risultano identiche come dimostrato in precedenza. Da notare come lo scambio dei dati tra le due parti avvenga, attraverso la rete, secondo le modalità descritte in precedenza al punto 1.3. A questo proposito si evidenziano le chiamate alle funzioni udp_send(), udp_reply() e udp_receive() (linee 95, 109, 163 e 133 in appendice) rispettivamente per inviare e ricevere i dati. Ricordiamo come sia necessario per il client e il server creare il socket prima di utilizzare tali funzioni. Questo passaggio non è gestito direttamente dalla classe Dh e deve, quindi, essere svolto dall’applicazione che la utilizza, come vedremo nell’esempio che sarà illustrato nel seguito del capitolo. 2.2.1 Funzioni crittografiche della classe Dh Come si nota nella sua dichiarazione (linee 21 e 22), la classe Dh comprende le due funzioni DhEncrypt() e DhDecrypt() che utilizzano la chiave crittografica condivisa rispettivamente per la cifratura e la decifratura dei dati. Come detto in precedenza, nell’esempio applicativo realizzato la cifratura avviene eseguendo l’XOR tra la chiave e i dati da trasmettere. La funzione DhEncrypt() riceve in ingresso il parametro toEncryptStr, cioè la stringa di dati da crittografare. Partendo dal primo, viene eseguito l’XOR tra il valore decimale di ciascun carattere di toDecrypt e quello del carattere corrispondente della chiave di cifratura; il risultato è poi memorizzato nella stringa encrypted (linee 230÷235 in appendice). Da notare il cast verso il tipo unsigned char (linea 233), utilizzato per ottenere solamente valori positivi dall’operazione di XOR, contrariamente a quanto accadrebbe se toEncryptStr contenesse caratteri non appartenenti alla tabella ASCII standard. Terminata l’elaborazione, la stringa encrypted che contiene i dati crittografati viene restituita come output dalla funzione. È fondamentale osservare come la lunghezza di toEncryptStr debba essere minore o uguale a quella della chiave, altrimenti una parte delle informazioni non sarebbe cifrata. La classe Dh fornisce, quindi, il selettore SizeOfK() che restituisce esattamente il numero di caratteri della chiave crittografica. Questa informazione permette di suddividere correttamente i dati da trasmettere prima di utilizzare DhEncrypt().

Page 30: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

18  

La funzione DhDecrypt() esegue, invece, l’operazione di decifratura (linee 239÷258 in appendice). Essa riceve in ingresso la stringa toDecrypt che contiene i dati iniziali crittografati, ovvero una successione di cifre decimali. Ogni terna di caratteri della stringa costituisce, quindi, un numero intero, risultato dell’operazione di XOR eseguita dalla funzione DhEncrypt() appena illustrata. Eseguendo nuovamente l’XOR tra questi interi e i caratteri della chiave di cifratura si ottengono i dati di partenza che vengono memorizzati in decrypted (linea 253). La funzione DhDecrypt() restituisce, quindi, la stringa decrypted contenente i dati decriptati.

Page 31: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

19  

2.3 Comunicazione criptata: libreria DhDataLib La libreria DhDataLib è stata creata per la trasmissione e la ricezione di dati cifrati utilizzando la classe Dh. Il codice relativo è riportato interamente in appendice (si faccia riferimento alle voci DhDataLib.hpp e DhDataLib.cpp). Di seguito ne richiamiamo l’header: 1      #ifndef  DHDATALIB_HPP  2      #define  DHDATALIB_HPP  3  4      #include  "ClassDh.hpp"  5      #include  <fstream>  6  7      bool  ReadAndSendData(Dh&  srv,  int  socket,  string  ipAddress,  int  

udpPort);  8      bool  ReceiveAndDecryptData(Dh&  srv,  int  socket);  9      void  SendData(const  string&  data,  Dh&  srv,  int  socket);  10    string  ReadFromFile();  11    string  ReadMessage();  12    void  printStrInDec(const  string&  toPrint);  13    void  printStrInHex(const  string&  toPrint,  bool  crypted);  14  15    #endif   Le due funzioni principali della libreria DhDataLib sono ReadAndSendData() e ReceiveAndDecryptData(). La prima è utilizzata per inviare dati criptati mentre la seconda è impiegata per riceverli e decifrarli. La funzione ReadAndSendData() (linee 71÷105 in appendice) permette, innanzitutto, di scegliere fra tre opzioni:

1) Inviare i dati inseriti da tastiera. 2) Inviare i dati contenuti in un file di testo. 3) Terminare la trasmissione.

Nel primo caso viene chiamata il metodo ReadMessage() che legge i caratteri inseriti da testiera, accoda ad essi la stringa di controllo "EOF~EOF~EOF" che ne indica la fine e memorizza il tutto nella stringa restituita come output. All’interno di ReadAndSendData() i caratteri letti dal metodo appena citato sono assegnati alla stringa message che viene poi inviata grazie alla funzione SendData(), che verrà descritta nel seguito (linee 87 e 88 in appendice). La seconda opzione prevede la trasmissione del contenuto di un file di testo. L’unica differenza rispetto al caso precedente, quindi, sta nel fatto che i dati del file sono letti dalla funzione ReadFromFile() e non da ReadMessage() (linea 93). Nel terzo caso, invece, la stringa di controllo "EOTS~EOTS~EOTS" viene inviata tramite SendData() per indicare al ricevitore la fine della trasmissione. ReadAndSendData() restituisce, infine, un valore booleano che indica se è stata scelta o meno la terza opzione, ovvero se la trasmissione deve essere interrotta (linea 104).

Page 32: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

20  

Come detto, quindi, è SendData() la funzione che invia effettivamente i dati da trasmettere, dopo averli crittografati grazie alla classe Dh (linee 140÷163 in appendice). Nel punto 2.2.1 del capitolo 2 abbiamo visto come i dati da cifrare debbano essere suddivisi in blocchi di caratteri di lunghezza minore o uguale a quella della chiave crittografica per utilizzare la funzione DhEncrypt(). SendData() deve gestire, quindi, anche questa operazione. Come si evince dal codice, la funzione riceve in ingresso la stringa data da trasmettere e, partendo dal primo, ne copia i caratteri in encryptedStr fino a quando la lunghezza di quest’ultima è pari a quella della chiave crittografica. A questo punto encryptedStr viene cifrata tramite DhEncrypt() ed inoltrata grazie alla funzione udp_reply() della libreria udpsocketlib (linee 152 e 156). Tutti i caratteri dalla stringa encryptedStr vengono, quindi, eliminati e la procedura viene iterata fino a quando data non è stata completamente inviata. La funzione ReceiveAndDecryptData() (linee 35÷69 in appendice) deve svolgere quindi l’operazione inversa e riscostruire interamente i dati iniziali a partire dai frammenti cifrati ricevuti, che vengono prodotti come visto sopra. Ognuna di queste stringhe criptate è ricevuta attraverso la funzione udp_receive() e assegnata al vettore di caratteri buffer (linea 45). Quest’ultimo viene decifrato dalla funzione DhDecrypt() e il risultato è salvato nella stringa bufferDecrypted (linea 49) che viene poi aggiunta a messageDecripted (linea 52). Quando in bufferDecrypted è presente la successione di caratteri "EOF~EOF~EOF" (che viene rimossa), la stringa messageDecripted contiene i dati iniziali trasmessi completamente ricostruiti (linee 59÷66). La funzione ReceiveAndDecryptData() restituisce un valore booleano che sarà vero solamente quando viene ricevuta la stringa "EOTS~EOTS~EOTS" che indica il termine della comunicazione. La libreria DhDataLib presenta, infine, i due metodi printStrInDec() printStrInHex() che permettono di stampare a video rispettivamente i valori decimali ed esadecimali dei caratteri delle stringhe fornite in input (linee 3÷33).

Page 33: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

21  

2.4 Esempio di utilizzo Vediamo ora un esempio di utilizzo della libreria DhDataLib e della classe Dh. Come illustrato nei capitoli precedenti, due parti, che indichiamo come client e server, grazie alla classe Dh generano una chiave di cifratura condivisa che viene usata dalle funzioni della libreria DhDataLib per crittografare la comunicazione tra di esse. Riportiamo di seguito il codice in linguaggio C++ relativo alle applicazioni del client e del server che utilizzano gli strumenti appena citati, insieme alla libreria udpsocketlib.

Server 1      #include  "ClassDh.hpp"  2      #include  "udpsocketlib.hpp"  3      #include  "DhDataLib.hpp"  4  5      int  main(int  argc,  char  *argv[])  6      {  7              Dh  srv;  8              int  sk,  udpPort;  9              string  serverIpAdrress,  message;  10            bool  done  =  false;  11  12            if  (argc  ==  1)  13            {  14                    cout<<"Server  ip  address:";  15                    cin>>serverIpAdrress;  16                    cout<<"Udp  port:";  17                    cin>>udpPort;  18            }  19            else  if  (argc  ==  3)  20            {  21                    serverIpAdrress  =  argv[1];  22                    udpPort  =  atoi(argv[2]);  23            }  24            else  25            {  26                    cout<<"Required  arguments:  server  ip  address,  udp  port"<<endl;  27                    exit(1);  28            }  29  30            if  ((sk  =  create_udp_server((char*)serverIpAdrress.c_str(),  

udpPort))  <  0)  31            {  32                    cout<<"Cannot  open  server  socket"<<endl;  33                    exit(1);  34            }  35  36            if  (!srv.GenerateEncryptionKey_Server(sk))  37                    exit(1);  38  39            do  

Page 34: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

22  

40            {  41                    done  =  ReceiveAndDecryptData(srv,  sk);  42                    if  (!done)  43                            done  =  ReadAndSendData(srv,  sk);  44            }while  (!done);  45  46            close_udp_socket(sk);  47            cout<<"\n\nExit..\n\n";  48            return  0;  49    }  

Client 1      #include  "ClassDh.hpp"  2      #include  "udpsocketlib.hpp"  3      #include  "DhDataLib.hpp"  4  5      int  main(int  argc,  char  *argv[])  6      {  7              Dh  clnt;  8              int  sk,  udpPort;  9              string  serverIpAdrress;  10            bool  done  =  false;  11  12            if  (argc  ==  1)  13            {  14                    cout<<"Server  ip  address:";  15                    cin>>serverIpAdrress;  16                    cout<<"Udp  port:";  17                    cin>>udpPort;  18            }  19            else  if  (argc  ==  3)  20            {  21                    serverIpAdrress  =  argv[1];  22                    udpPort  =  atoi(argv[2]);  23            }  24            else  25            {  26                    cout<<"Required  arguments:  server  ip  address,  udp  port"<<endl;  27                    exit(1);  28            }  29  30            if  ((sk  =  create_udp_client())  <  0)  31            {  32                    cout<<"Cannot  open  client  socket"<<endl;  33                    exit(1);  34            }  35  36            if  (!clnt.GenerateEncryptionKey_Client(sk,  serverIpAdrress  

,udpPort))  37                    exit(1);  38  39            do  40            {  41                    done  =  ReadAndSendData(clnt,  sk);  42                    if  (!done)  

Page 35: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

23  

43                            done  =  ReceiveAndDecryptData(clnt,  sk);  44            }while  (!done);  45  46            close_udp_socket(sk);  47            cout<<"\n\nExit.."<<endl<<endl;  48            return  0;  49    }   Innanzitutto, entrambe le parti creano il socket UDP grazie alle due funzioni create_udp_server() e create_udp_client() messe a disposizione dalla libreria udpsocketlib. Come visto nel punto 1.3 del capitolo 1, create_udp_server() riceve in ingresso l’indirizzo IPv4 del server e la porta locale su cui attenderà i dati per associarle al socket (linea 30, Server). Queste informazioni devono essere fornite come argomento della funzione main del server direttamente dalla linea di comando, altrimenti il loro inserimento viene richiesto esplicitamente dal programma (linee 12÷28, Server). Le stesse informazioni devono essere fornite all’applicazione del client; in questo caso però non saranno associate al socket ma saranno utilizzate, quando necessario, solamente per inviare dati al server. Da notare, infatti, come create_udp_client() non riceva parametri in ingresso (linea 30, Client). Una volta creato il socket, client e server possono procedere alla generazione di una chiave crittografica condivisa, come illustrato in precedenza in questo capitolo. Vengono chiamate, infatti, da entrambe le parti le funzioni della classe Dh GenerateEncryptionKey_Server() e GenerateEncryptionKey_Client() per lo scambio della chiave (linea 36, Client e Server). Se l’operazione ha successo, le due parti possono, infine, utilizzare la libreria DhDataLib per comunicare in modo protetto attraverso la rete. Come si vede nel codice, entrambe le parti entrano in un ciclo do..while in cui vengono eseguite alternativamente le due funzioni ReadAndSendData() ReceiveAndDecryptData() (linee 39÷44). La comunicazione ha inizio con il client che chiama ReadAndSendData() per inviare i dati al server, il quale a sua volta esegue ReceiveAndDecryptData() per riceverli. Dopodiché le parti si scambiano i ruoli e il ciclo continua fino a quando una delle due non termina la comunicazione. Ricordiamo, infatti, che entrambe le funzioni restituiscono un valore booleano che indica il raggiungimento di tale condizione, come visto nel punto 2.3 del capitolo 2. A questo punto da entrambe le parti il socket viene chiuso e le applicazioni terminano (linee 46 e 48).

Page 36: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

24  

2.5 Confronto con la versione in C Nella versione in linguaggio C è stata mantenuta la stessa struttura di quella in C++ in modo tale che lo scambio di una chiave crittografica così come la cifratura, la decifratura e la trasmissione dei dati avvengano sempre secondo le modalità descritte in precedenza. Tuttavia esistono alcune differenze fra le due versioni, dovute principalmente alle diverse caratteristiche dei linguaggi di programmazione, che si ritiene utile analizzare. Innanzitutto, non essendo presente il concetto di classe, nella versione in linguaggio C è stato necessario creare la libreria DhLib per lo scambio della chiave crittografica secondo l’algoritmo Diffie-Hellman. Il codice è riportato interamente in appendice (si faccia riferimento alle voci DhLib.h e DhLib.c). Di seguito ne richiamiamo solamente l’header. 13    //  Create  type  bool  (not  present  in  c).  14    typedef  enum  {  false,  true  }  bool;  15  16    struct  dhStruct  17    {  18            mpz_t  p,  g,  a,  b,  A,  B,  K;  19    };  20  21    void  GeneratePrimeNumber(char*  name,  mpz_t  num,  unsigned  numBits);  22    void  FindGenerator(mpz_t  q,  mpz_t  g);  23    bool  GenerateEncryptionKey_Client(int  socket,  char*  ipAddress,  int  

udpPort,  struct  dhStruct*  dh);  24    void  GetPgaAndSetA(struct  dhStruct*  dh,  int  choice);  25    bool  SendPGA(int  socket,  char*  ipAddress,  int  udpPort,  struct  

dhStruct*  dh);  26    bool  ReceiveBandComputeK(int  socket,  struct  dhStruct*  dh);  27    bool  GenerateEncryptionKey_Server(int  socket,  struct  dhStruct*  dh);  28    bool  ReceivePGA(int  socket,  struct  dhStruct*  dh);  29    void  ComputeBandKey(struct  dhStruct*  dh);  30    bool  SendB(int  socket,  struct  dhStruct*  dh);  31    char*  DhEncrypt(char*  toEncryptStr,  char*  key);  32    char*  DhDecrypt(char*  toDecrypt,  char*  key);  33    void  GetVariable(char*  varName,  mpz_t  var);  34    int  rdtsc();   Dal confronto con la versione in C++ si nota come le funzioni della libreria DhLib siano le stesse presenti nella classe Dh (ma opportunamente tradotte in linguaggio C) e svolgano le stesse operazioni. Lo scambio della chiave di cifratura, quindi, avviene sempre attraverso i due metodi GenerateEncryptionKey_Server() e GenerateEncryptionKey_Client() e la successione delle funzioni chiamate è la stessa della versione in C++. All’inizio del capitolo 2, al punto 2.2 si è vista l’importanza delle classi dal punto di vista della sicurezza e robustezza del software: essendo contenute nella parte privata, le variabili dell’algoritmo e la chiave di cifratura sono invisibili a chi utilizza la classe ed è possibile accedervi solo attraverso i suoi metodi pubblici.

Page 37: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

25  

Data l’assenza delle classi in C, viene meno anche la possibilità di sfruttare il principio dell’information hiding. Nella libreria DhLib le variabili dell’algoritmo non sono più campi privati di una classe ma vengono solamente inserite all’interno di una struct dhStruct (linee 16÷19). Chi utilizza la libreria può, quindi, accedervi direttamente in modo analogo a quanto avviene per le funzioni di libreria a cui la struct contenente i dati viene passata per riferimento. Tutto ciò si traduce in un livello di sicurezza minore rispetto al caso precedente. Questo aspetto è evidente nei programmi scritti come esempio di utilizzo delle librerie DhLib e DhDataLib. Il codice è riportato in appendice alle voci Dh_s.c Dh_c.c. In entrambi i programmi, dopo aver scambiato la chiave crittografica, questa viene convertita in una stringa (linea 39 in appendice). Per fare questo si accede direttamente al dato contenuto nella struct tramite l’operatore “.”. In questo caso il valore della chiave K viene solamente letto, ma nello stesso modo è possibile modificare il dato. Questo vale ovviamente per tutte le altre variabili. Da notare, quindi, la differenza con l’utilizzo della classe Dh in cui la chiave crittografica possa essere solamente letta attraverso il selettore ReturnKey() e non sia possibile modificare direttamente nessuna delle variabili. Da notare, inoltre, come le variabili dell’algoritmo siano rappresentate da oggetti di tipo mpz_t (linea 18) a differenza della classe Dh in cui sono di tipo mpz_class. La classe mpz_class presente nella libreria GMP è stata creata, infatti, in C++ per la gestione degli oggetti mpz_t: in altre parole la loro inizializzazione, il rilascio della memoria loro riservata e l’overloading degli operatori. Per fare ciò tale classe utilizza le funzioni specifiche della libreria GMP che operano su oggetti di tipo mpz_t. Questo semplifica notevolmente l’utilizzo di tale tipo di dato in C++; nel codice scritto, infatti, mpz_powm() è l’unica funzione specifica che è stato necessario utilizzare esplicitamente. L’overloading degli operatori d’input/output, di quelli relazionali e di quelli matematici ha permesso di trattare gli oggetti mpz_t come i tipi di dato nativi del C++. Tutto ciò non è più vero per il linguaggio C. Da notare, a questo proposito, nel codice dei programmi Dh_c.c e Dh_s.c come le variabili mpz_t della struct dhStruct debbano essere inizializzate tramite la funzione mpz_inits() prima di utilizzarle e la memoria debba, infine, essere liberata chiamando mpz_clears() (linee 11 e 48 in appendice). Nel codice della libreria DhLib si nota, inoltre, l’utilizzo delle seguenti funzioni:

• mpz_set() che svolge il compito dell’operatore di assegnazione “=” • mpz_sub_ui() per sottrarre un intero unsigned long ad uno mpz_t • mpz_cmp_ui() e mpz_cmp() per comparare un intero mpz_t rispettivamente a

un intero unsigned long e a un altro mpz_t. queste funzioni svolgono, quindi, il compito degli opertatori relazionali “>”, “>=”, “<”, “<=” e “==”

• gmp_printf() per visualizzare gli interi mpz_t sullo standard output • gmp_scanf() per acquisire interi mpz_t dallo standard input

L’uso di queste funzioni non incrementa notevolmente la complessità nella scrittura del codice in linguaggio C; in alcuni casi, tuttavia, la sua leggibilità può risentirne, specialmente se confrontata al C++.

Page 38: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

26  

È stato, infine, necessario tradurre in C anche la libreria DhDataLib, il cui codice è riportato in appendice alle voci DhDataLib.h DhDataLib.c. Come fatto in precedenza, richiamiamo di seguito la dichiarazione delle funzioni: 6      bool  ReadAndSendData(char*  key,  int  socket);  7      bool  ReceiveAndDecryptData(char  *key,  int  socket);  8      void  SendData(char*  data,  char*  key,  int  socket);  9      char*  ResizeDinamicString(char*  toResize,  int  newDim);  10    char*  ReadMessage();  11    char*  ReadFromFile();  12    void  printStrInDec(char*  toPrint);  13    void  printStrInHex(char*  toPrint,  bool  crypted);   Anche in questo caso sono state mantenute tutte le funzioni presenti nella versione in C++ e quindi la comunicazione criptata fra due parti avviene esattamente nello stesso modo descritto in precedenza. È importante, tuttavia, sottolineare come il C++ consenta un utilizzo migliore e più semplice delle stringhe di caratteri rispetto al C, in particolare quelle di dimensione variabile. In C++ abbiamo utilizzato la classe string che gestisce autonomamente il ridimensionamento delle stringhe per l’aggiunta di singoli caratteri o di altre stringhe tramite la funzione push_back() e l’operatore “+” sovraccaricato. Queste caratteristiche sono state utili nelle funzioni ReadMessage() e ReadFromFile() in quanto hanno reso particolarmente semplice l’inserimento dei caratteri letti rispettivamente dallo standard input e da un file in una stringa e l’aggiunta in coda della sequenza di controllo "EOF~EOF~EOF". In C, invece, le stringhe sono trattate come vettori di caratteri ed è necessario gestire esplicitamente il loro ridimensionamento. A questo scopo si è scelto di ricorrere all’allocazione dinamica della memoria tramite la funzione malloc(). È stato così possibile creare la funzione ResizeDinamicString() (linee 113÷126 in appendice) per ridimensionare una stringa di caratteri in modo che possa contenere tutti i dati, senza perdita di informazioni. Come si vede nel codice delle funzioni ReadMessage() e ReadFromFile() (linee 138, 143, 165 e 170 in appendice), ResizeDinamicString() viene chiamata tutte le volte che i caratteri letti in input devono essere aggiunti a una stringa, prima di poter utilizzare la funzione strcat(). L’allocazione dinamica richiede, infine, di prestare particolare attenzione al corretto rilascio della memoria occupata. Da notare a questo proposito le chiamate alla funzione free() (linee 75, 79 e 122) che svolge quest’ultima operazione.

Page 39: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

27  

3 Algoritmo RSA 3.1 Descrizione Nel 1978 Ronald Rivest, Adi Shamir e Leonard Adleman (tre ricercatori del MIT) proposero, nell’articolo “A Method for Obtaining Digital Signatures and Public-Key Cryptosystems” [7], l’algoritmo di crittografia a chiave asimmetrica noto come “algoritmo RSA” (il cui nome è costituito dalle iniziali dei suoi inventori). La crittografia asimmetrica è basata sull’utilizzo di due chiavi distinte per la cifratura e per la decifratura delle informazioni, dette rispettivamente chiave pubblica e chiave privata. Quando due parti devono comunicare tra loro, ciascuna di esse non deve fare altro che cifrare i dati con la chiave pubblica del destinatario, che, una volta ricevuti, sarà in grado di decifrarli con la propria chiave privata. In questo sistema, quindi, ogni parte possiede una coppia di chiavi: quella pubblica che deve essere, appunto, distribuita e resa di pubblico dominio perché consente di codificare le informazioni e quella privata (che deve essere mantenuta segreta) che consente di decifrarle. Da notare come la chiave pubblica possa essere condivisa attraverso un canale insicuro: chi la ottiene, infatti, può soltanto inviare informazioni cifrate al suo proprietario, ma non è in grado di ottenere e decodificare i dati diretti a quest’ultimo dal momento che non è a conoscenza della sua chiave privata. Poiché le due chiavi non sono indipendenti tra loro, la sicurezza del meccanismo di cifratura è garantita dalla difficoltà di ricostruire una delle due chiavi a partire dall’altra. Nell’algoritmo RSA la generazione delle chiavi avviene nel seguente modo:

1. si scelgono due numeri primi casuali p e q sufficientemente grandi in modo da garantire la sicurezza dell’algoritmo

2. si calcola n = p×q e φ = (p – 1)×(q – 1) 3. si sceglie un numero 1 < e < φ coprimo con φ. Come indicato dagli autori

dell’algoritmo nell’articolo [7], si può utilizzare, ad esempio, un numero primo casuale maggiore del max(p, q); l’importante è che questo sia scelto da un insieme sufficientemente grande.

4. si calcola il numero d tale che e×d = 1 mod φ La chiave pubblica è costituita dalla coppia (n, e), mentre quella privata da (n, d). Vediamo, quindi, come utilizzare le chiavi generate per la cifratura e decifratura delle informazioni. Innanzitutto, i dati da codificare devono essere suddivisi in blocchi di dimensione compatibile con l’operazione di cifratura e opportunamente convertiti in decimale (come vedremo nel seguito del capitolo). Indicando con m il valore decimale di ciascun blocco, la sua dimensione deve essere tale per cui 0 < m < n. La cifratura delle informazioni avviene, grazie alla chiave pubblica, attraverso l’operazione c = me mod n; c rappresenta, così, ciascun blocco di dati crittografato. Per decifrare c utilizzando la chiave privata, è necessario calcolare t = cd mod n, dove indichiamo con t il risultato dell’ultima operazione. Affinché la decifrazione abbia successo, t deve necessariamente coincidere con c. La dimostrazione della correttezza dell’algoritmo RSA verrà fornita nel seguito del capitolo.

Page 40: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

28  

La sua sicurezza, invece, è basata sulla difficoltà di scomporre in fattori primi i numeri interi molto elevati. Come evidenziato in [8], se si riuscisse a fattorizzare il numero n (noto pubblicamente), allora sarebbe possibile trovare p e q e da questi φ. Di conseguenza, conoscendo e, si potrebbe facilmente determinare d tramite l’algoritmo di Euclide e violare, quindi, il meccanismo di cifratura. Tuttavia non è stato ancora trovato un metodo per la fattorizzazione di numeri molto grandi che non sia computazionalmente proibitivo. Per questo motivo l’algoritmo RSA è considerato sicuro se si utilizzano p e q sufficientemente elevati, cioè di dimensioni tali per cui n sia un numero intero di almeno 200 cifre decimali (come suggerito dagli ideatori dell’algoritmo nell’articolo [7]). 3.1.1 Correttezza dell’algoritmo La correttezza dell’algoritmo viene dimostrata dagli autori nell’articolo [7] sfruttando il piccolo teorema di Fermat di cui riportiamo solamente l’enunciato. Sia p un numero primo e a un intero non divisibile da p, il teorema afferma che:

a(p – 1) = 1 mod p Viene utilizzato, inoltre, un importante risultato del teorema cinese del resto, il quale afferma che la relazione a = b mod pq risulta equivalente al sistema costituito da:

• a = b mod p • a = b mod q

Si vuole dimostrare, quindi, che i dati decifrati indicati con t coincidono con quelli originali m. Per le proprietà dell’aritmetica modulare possiamo scrivere:

t = cd mod n = (me mod n) d mod n = (me) d mod n = med mod n dove c indica i dati m cifrati, come visto in precedenza. Per come sono stati costruiti e e d, si ha che:

e×d = 1 mod φ = 1 mod ((p – 1)×(q – 1))

Di conseguenza:

e×d = 1 mod (p – 1) e analogamente

e×d = 1 mod (q – 1)

Page 41: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

29  

Per il piccolo teorema di Fermat si ha che:

med = m mod p e med = m mod q Siccome p e q sono numeri diversi e primi, possiamo applicare il teorema cinese del resto, ottenendo che:

med = m mod (p×q) = m mod n e quindi:

t = cd mod n = med mod n = m mod n

Abbiamo quindi dimostrato che, decrittando i dati cifrati con la chiave pubblica (n, e) tramite quella privata (n, d), si ottengono nuovamente i dati originali.

Page 42: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

30  

3.2 Generazione delle chiavi di cifratura: classe Rsa Analizziamo, quindi, l’implementazione dell’algoritmo RSA realizzata in questa tesi. Nella versione in linguaggio C++, la classe Rsa è stata creata per la generazione delle chiavi di cifratura pubblica e privata e per la gestione delle operazioni di criptazione e di decriptazione dei dati, secondo le modalità appena descritte. Come vedremo, sono presenti, inoltre, le due funzioni necessarie per la condivisione e per la ricezione della chiave pubblica. L’interfaccia della classe Rsa e l’implementazione dei suoi metodi sono interamente riportate in appendice, rispettivamente in ClassRsa.hpp e ClassRsa.cpp. Tuttavia, per semplicità di consultazione, ne richiamiamo di seguito la dichiarazione. 14    class  Rsa  15    {  16            public:  17                    mpz_class  N()  const  {  return  n;}  18                    int  SizeOfN()  const  {  return  mpz_sizeinbase(n.get_mpz_t(),  

10);}  19                    mpz_class  E()  const  {  return  e;}  20                    mpz_class  D()  const  {  return  d;}  21                    void  GenerateEncryptionKeys();  22                    bool  SendPublicKey(int  socket,  string  ipAddress,  int  udpPort);  23                    bool  ReceivePublicKey(int  socket);  24                    void  RsaEncrypt(string&  toEncryptStr);  25                    string  RsaDecrypt(const  char*  toDecrypt);  26  27        private:  28                    mpz_class  p,  q,  phi;  29                    mpz_class  n,  e,  d;  //keys  30                    mpz_class  ComputeGCD(const  mpz_class&  x,  const  mpz_class&  y);  31                    mpz_class  GetRandomE();  32                    void  GeneratePQandComputeNPhi();  33                    mpz_class  GeneratePrimeNumber(string  name,  unsigned  numBits);  34                    void  FindE();  35                    void  ComputeD();  36                    int  rdtsc();  37    };   Innanzitutto notiamo che, come già visto per la classe Dh, le variabili dell’algoritmo (ovvero p, q e phi) e le chiavi di cifratura (costituite da n, e e d) sono di tipo mpz_class e sono inserite nella parte privata della classe. Questo garantisce una maggior sicurezza poiché le chiavi non sono direttamente accessibili a chi usa la classe e, quindi, possono essere generate e modificate solo dalle funzioni della classe stessa. In particolare, la chiave pubblica e quella privata vengono create dalla funzione GenerateEncryptionKeys() (linea 21). Quest’ultima, come si evince dal codice (linee 131, 132 e 133 in appendice), sfrutta i metodi privati della classe Rsa per impostare i valori delle variabili dell’algoritmo e ottenere, infine, le chiavi crittografiche.

Page 43: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

31  

Il dettaglio delle funzioni di classe chiamate all’interno di GenerateEncryptionKeys() è riportato nella figura sottostante.

Come indicato in figura 3.1, la prima funzione che viene chiamata in GenerateEncryptionKeys() è GeneratePQandComputeNPhi(). L’algoritmo RSA, infatti, ha inizio con la generazione di due numeri primi elevati p e q e con il calcolo di n e φ (nel codice quest’ultima variabile è stata indicata con phi). Questo è esattamente il compito svolto da GeneratePQandComputeNPhi() che, come si può notare nel codice (linee 22, 23, 26 e 27 in appendice), utilizza la funzione GeneratePrimeNumber() per generare i due numeri primi casuali p e q e, infine, calcola n = p×q e phi = (p – 1) × (q – 1). La funzione GeneratePrimeNumber() è la stessa utilizzata nella classe Dh; si rimanda, quindi, al punto 2.2 del capitolo 2 per maggiori dettagli. Da notare, invece, come la dimensione scelta per p e q sia di 512 bit. In questo modo n sarà un numero intero di circa 308 cifre decimali tale, quindi, da garantire la sicurezza dell’algoritmo: la condizione di 200 cifre decimali indicata nell’articolo [7] risulta, infatti, ampiamente soddisfatta. A questo punto viene chiamata la funzione FindE() per calcolare il numero intero e che costituisce, in coppia con n, la chiave pubblica e che, come visto in precedenza, deve essere coprimo e minore di phi. La funzione FindE(), quindi, trova il numero e nel seguente modo. Innanzitutto viene chiamata la funzione GetRandomE() (linea 64

GenerateEncryptionKeys()

2) FindE()

3) ComputeD()

GeneratePrimeNumber()

GetRandomE()

ComputeGCD()

1) GeneratePQandComputeNPhi()

Figura 3.1 - Funzioni per la creazione delle chiavi

Page 44: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

32  

in appendice) che assegna ad e un numero intero casuale compreso tra il max(p, q) e (phi – 1). Dopodiché, come si può notare nel codice (linee 65÷72 in appendice), viene calcolato il massimo comun divisore fra e e phi tramite la funzione ComputeGCD() che implementa l’algoritmo di Euclide:

• se è pari ad 1, i due numeri sono coprimi e quindi e è corretto. • se è diverso da 1, allora i due numeri non sono coprimi. Si diminuisce e di 1 e

si ricalcola il massimo comun divisore fino ad ottenere un valore corretto per e. Se quest’ultimo dovesse diventare pari a p o a q, allora il ciclo si ripeterebbe ricominciando dalla chiamata a GetRandomE().

La funzione FindE() converge molto rapidamente ad un valore corretto per il numero e, cioè tale per cui 1 < e < phi ed è coprimo con phi. Inoltre, e viene individuato all’interno di un insieme molto ampio poiché il max(p, q) e (phi – 1) differiscono di molti ordini di grandezza. Ciò significa che la sicurezza dell’algoritmo RSA è garantita. A questo punto viene chiamata la funzione ComputeD() per calcolare il numero d e ottenere, quindi, la chiave privata costituita dalla coppia (d, n). Come detto in precedenza, d deve essere calcolato in modo tale che e×d = 1 mod φ ovvero d è l’inverso moltiplicativo di e. La funzione ComputeD() sfrutta, quindi, l’algoritmo di Euclide esteso per determinare d; senza entrare nei dettagli matematici, utilizziamo l’implementazione ripotata nel sito [9] ma opportunamente modificata per poter lavorare con numeri interi molto grandi, ovvero con dati di tipo mpz_class. Trovato d, la funzione GenerateEncryptionKeys() giunge al termine. Sono state generate, quindi, entrambe le chiavi di cifratura: la chiave pubblica (n, e) e quella privata (n, d). Tuttavia, per poterle utilizzare nella cifratura di una comunicazione che avviene tra due parti, è necessario condividere la chiave pubblica. Per questo motivo la classe Rsa comprende le due funzioni SendPublicKey() e ReceivePublicKey() che possono essere usate rispettivamente per inviare e ricevere la chiave pubblica. Come si vede dal codice (linee 142÷147 in appendice), la prima non fa altro che convertire n ed e in due stringhe che poi vengono inviate grazie alla funzione udp_send(); la seconda (linee 165÷173 in appendice) esegue l’operazione inversa ricevendo le due stringhe tramite udp_receive() e convertendole in numeri interi mpz_class. Un esempio di utilizzo delle funzioni della classe Rsa verrà proposto nel seguito del capitolo. La classe Rsa comprende, infine, i due metodi pubblici RsaEncrypt() e RsaDecrypt() (line 24 e 25) per la cifratura e la decifratura dei dati. La prima riceve in ingresso la stringa toEncryptStr da criptare, la converte nel numero intero encrypted di tipo mpz_class e calcola, grazie alla funzione mpz_powm() della libreria GMP, encrypted = encryptede mod n (linee 187 e 190 in appendice). È importante notare come la funzione RsaEncrypt() richieda che toEncryptStr contenga il valore numerico dei dati da cifrare e che questo sia minore di n (come visto in precedenza nel capitolo). Di conseguenza, per poter utilizzare correttamente tale funzione, è necessario che i dati siano già stati convertiti in decimale e opportunamente suddivisi. A questo punto encrypted, dopo essere stato tradotto in una stringa, viene memorizzato in toEncryptStr (linea 192 in appendice) che, in questo modo, conterrà i dati iniziali cifrati.

Page 45: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

33  

Per decifrare i dati, la funzione RsaDecrypt() deve necessariamente svolgere l’operazione inversa. Essa riceve in ingresso la stringa toDecrypt che viene convertita nel numero intero decrypted (linea 200 in appendice). Dopodiché la funzione calcola, per mezzo di mpz_powm(), decrypted = decryptedd mod n e restituisce il risultato di tale operazione sotto forma di stringa di caratteri. Poiché i dati vengono convertiti in decimale e suddivisi prima di essere cifrati, dopo la decifratura dovrà essere gestita la loro ricostruzione. Di seguito vedremo come tutte queste operazioni siano realizzate dalle funzioni della libreria RsaDataLib.

Page 46: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

34  

3.3 Comunicazione criptata: libreria RsaDataLib La libreria RsaDataLib utilizza la classe Rsa per permettere la trasmissione e la ricezione di dati cifrati grazie alle chiavi crittografiche generate. Il codice relativo è riportato interamente in appendice (si faccia riferimento alle voci RsaDataLib.hpp e RsaDataLib.cpp). Di seguito ne richiamiamo l’header: 1      #ifndef  RSADATALIB_HPP  2      #define  RSADATALIB_HPP  3  4      #include  "ClassRsa.hpp"  5      #include  <fstream>  6  7      void  ReceiveAndDecryptData(Rsa&  clt,  int  socket);  8      bool  ReadAndSendData(Rsa&  srv,    int  socket);  9      void  SendData(const  string&  data,  Rsa&  srv,  int  socket);  10    string  ReadFromFile();  11    string  ReadMessage();  12    string  RebuildData(string&  decryptedStr);  13  14    #endif   Le due funzioni principali della libreria sono ReadAndSendData() e ReceiveAndDecryptData() che permettono, rispettivamente, di inviare dati criptati e di riceverli e decifrarli. Come si evince dal codice (linee 3÷27 e 56÷90 in appendice), sia queste due funzioni che ReadFromFile() e ReadMessage() sono sostanzialmente le stesse presenti nella libreria DhDataLib, con la sola differenza che in questo caso vengono utilizzati oggetti di classe Rsa e non Dh. Si rimanda, quindi, al punto 2.3 del capitolo 2 per la loro descrizione. È opportuno, però, analizzare le differenze, dovute principalmente alla diversa modalità di cifratura dei dati, rispetto alla libreria DhDataLib che sono. Ciò che varia, infatti, è il modo in cui devono essere suddivisi i dati da trasmettere prima di poterli criptare (grazie alle funzioni della classe Rsa) e la loro ricostruzione una volta decifrati. La prima operazione è svolta dalla funzione SendData() mentre la seconda da RebuildData(). SendData() (linee 124÷150 in appendice) riceve in ingresso la stringa data da trasmettere, traduce (partendo dal primo) un carattere nel corrispondente valore decimale e lo accoda alla stringa encryptedStr (linee 132 e 133). Dopodiché encryptedStr viene convertita nel numero intero encrypted di tipo mpz_class (linea 134). Se encrypted è minore di n, l’inserimento dei caratteri in encryptedStr prosegue, altrimenti quest’ultima viene cifrata grazie alla funzione RsaEncrypt() della classe Rsa e, quindi, trasmessa tramite udp_reply() (linee 140, 141 e 142). encryptedStr viene, quindi, svuotata e il procedimento ripetuto fino a quando la stringa data non è stata interamente trasmessa. La funzione ReceiveAndDecryptData() riceve, quindi, i dati originali (ovvero quelli contenuti nella stringa data) criptati e suddivisi in blocchi nel modo appena descritto. L’operazione di decifrazione è svolta dal metodo RsaDecrypt() della classe Rsa che restituisce la stringa aux in cui è presente il valore numerico dei dati originali

Page 47: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

35  

(ovvero il contenuto di encryptedStr). Quest’ultima contiene, quindi, una sequenza di cifre decimali in cui ogni terna di numeri costituisce un carattere dei dati iniziali. Di conseguenza, è necessario utilizzare la funzione RebuildData() (linee 29÷54 in appendice) che converte il valore decimale di ciascuna terna di cifre della stringa aux in un carattere. In questo modo i dati originali vengono ricostruiti. Nel codice di ReceiveAndDecryptData() si notano le chiamate a RsaDecrypt() e RebuildData() (linee 11 e 12 in appendice). Il loro utilizzo rappresenta l’unica differenza rispetto all’omonima funzione della libreria DhDataLib in cui vengono usate le funzioni della classe Dh. Di seguito viene proposto un esempio di utilizzo dei metodi della libreria RsaDataLib.

Page 48: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

36  

3.4 Esempio di utilizzo Vediamo ora un esempio di utilizzo della libreria RsaDataLib e della classe Rsa in cui si realizza una comunicazione criptata tra due parti che indichiamo come client e server. Come illustrato nei capitoli precedenti, la classe Rsa permette di generare le chiavi di cifratura che vengono usate dalle funzioni della libreria RsaDataLib per crittografare la comunicazione tra le due parti. Riportiamo di seguito il codice in linguaggio C++ relativo alle applicazioni del client e del server che utilizzano gli strumenti appena citati (insieme alla libreria udpsocketlib).

Server 1      #include  "ClassRsa.hpp"  2      #include  "udpsocketlib.hpp"  3      #include  "RsaDataLib.hpp"  4  5      int  main(int  argc,  char  *argv[])  6      {  7              Rsa  srv;  8              int  sk,  udpPort;  9              bool  done;  10            string  serverIpAdrress;  11            if  (argc  ==  1)  12            {  13                    cout<<"Server  ip  address:";  14                    cin>>serverIpAdrress;  15                    cout<<"Udp  port:";  16                    cin>>udpPort;  17            }  18            else  if  (argc  ==  3)  19            {  20                    serverIpAdrress  =  argv[1];  21                    udpPort  =  atoi(argv[2]);  22            }  23            else  24            {  25                    cout<<"Required  arguments:  server  ip  address,  udp  port"<<endl;  26                    exit(1);  27            }  28            if  ((sk  =  create_udp_server((char*)serverIpAdrress.c_str(),  

udpPort))  <  0)  29            {  30                    cout<<"Cannot  open  server  socket"<<endl;  31                    exit(1);  32            }  33            if  (!srv.ReceivePublicKey(sk))  34                    exit(1);  35            do  36            {  37                    done  =  ReadAndSendData(srv,  sk);  38            }while  (!done);  39            cout<<"\n\nExit..\n\n";  

Page 49: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

37  

40            close_udp_socket(sk);  41            return  0;  42    }  

Client 1      #include  "ClassRsa.hpp"  2      #include  "udpsocketlib.hpp"  3      #include  "RsaDataLib.hpp"  4  5      int  main(int  argc,  char  *argv[])  6      {  7              Rsa  clnt;  8              int  sk,  udpPort;  9              string  serverIpAdrress;  10  11            if  (argc  ==  1)  12            {  13                    cout<<"Server  ip  address:";  14                    cin>>serverIpAdrress;  15                    cout<<"Udp  port:";  16                    cin>>udpPort;  17            }  18            else  if  (argc  ==  3)  19            {  20                    serverIpAdrress  =  argv[1];  21                    udpPort  =  atoi(argv[2]);  22            }  23            else  24            {  25                    cout<<  "Required  arguments:  server  ip  address,  udp  

port"<<endl;  26                    exit(1);  27            }  28            if  ((sk  =  create_udp_client())  <  0)  29            {  30                    cout<<"Cannot  open  client  socket"<<endl;  31                    exit(1);  32            }  33            clnt.GenerateEncryptionKeys();  34            if  (!clnt.SendPublicKey(sk,  serverIpAdrress,  udpPort))  35                    exit(1);  36            ReceiveAndDecryptData(clnt,  sk);  37            close_udp_socket(sk);  38            return  0;  39    }   Osservando il codice di entrambi i programmi, si vede che la creazione del socket per mezzo delle funzioni messe a disposizione dalla libreria udpsocketlib (linee 11÷32 server e client) avviene in modo analogo a quello visto nell’esempio di utilizzo della classe Dh. Si rimanda quindi ai capitoli 1.3 e 2.4 per una descrizione dettagliata. È opportuno analizzare, invece, l’uso delle funzioni della classe Rsa. Come si evince dal codice, dopo che entrambe le parti hanno creato il socket, il server si mette in attesa di ricevere la chiave pubblica del client grazie alla funzione ReceivePublicKey() (linee 33 e 34, server). Ovviamente, nel caso in cui venga

Page 50: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

38  

riscontrato qualche errore nella ricezione della chiave, il programma del server termina. Contemporaneamente, il client prima genera la chiave privata e quella pubblica chiamando la funzione GenerateEncryptionKeys() (linea 33, client) e poi condivide quest’ultima grazie a SendPublicKey() (linee 34 e 35, client). Anche in questo caso, se si riscontra qualche errore nella condivisione della chiave, il programma del client termina. Se lo scambio della chiave pubblica tra le due parti avviene correttamente, il server può utilizzare quest’ultima per trasmettere dati cifrati al client attraverso la libreria RsaDataLib. Nell’esempio realizzato vediamo, infatti, che il client si mette in attesa di ricevere informazioni dal server attraverso la funzione ReceiveAndDecryptData() (linea 36, client). Quest’ultimo, invece, entra in un ciclo do..while per trasmettere dati al client grazie a ReadAndSendData() (linee 35÷38, server). Quando la trasmissione di dati da parte del server finisce, da entrambi i lati viene chiuso il socket e i programmi terminano.

Page 51: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

39  

3.5 Confronto con la versione in C Anche in questo caso, come per il Diffie-Hellman, nella versione in linguaggio C è stata mantenuta la stessa struttura di quella in C++. Di conseguenza la creazione delle chiavi crittografiche così come la cifratura, la decifratura e la trasmissione dei dati avvengono nello stesso modo e attraverso le stesse funzioni descritte in precedenza nel capitolo. Tuttavia, come nel caso precedente, esistono alcune differenze fra le due versioni, dovute alle diverse caratteristiche dei due linguaggi di programmazione, che si ritiene utile analizzare. Poiché nel linguaggio C non esiste il concetto di classe è stato necessario creare la libreria RsaLib per la generazione delle chiavi di cifratura dell’algoritmo Rsa. Il codice è riportato interamente in appendice (si faccia riferimento alle voci RsaLib.h e RsaLib.c). Di seguito ne richiamiamo l’header. 13    typedef  enum  {  false,  true  }  bool;  14  15    struct  keysRsa  16    {  17            mpz_t  p,  q,  phi;  18            mpz_t  n,  e,  d;  //keys  19    };  20  21    struct  publicKeyRsa  22    {  23            mpz_t  e,  n;  24    };  25  26    bool  ReceivePublicKey(struct  publicKeyRsa*  pbk,  int  socket);  27    char*  RsaEncrypt(char*  toEncryptStr,  struct  publicKeyRsa*  pbk);  28    char*  RsaDecrypt(char*  toDecrypt,  struct  keysRsa*  key);  29    void  GenerateEncryptionKeys(struct  keysRsa*  keys);  30    void  GeneratePrimeNumber(char*  name,  mpz_t  num,  int  numBits);  31    void  GeneratePQandComputeNPhi(struct  keysRsa*  var);  32    void  GetRandomE(struct  keysRsa*  var);  33    void  FindE(struct  keysRsa*  var);  34    void  ComputeGCD(mpz_t  r,  mpz_t  e,  mpz_t  phi);  35    void  ComputeD(struct  keysRsa*  var);  36    bool  SendPublicKey(int  socket,  char*  ipAddress,  int  udpPort,  struct  

keysRsa*  pubK);  37    int  rdtsc();   L’analisi del codice conferma quanto appena detto e cioè che le funzioni della libreria RsaLib sono le stesse presenti nella classe Rsa (ma opportunamente tradotte in linguaggio C). La generazione della chiave di cifratura pubblica e di quella privata, quindi, avviene sempre attraverso il metodo GenerateEncryptionKeys()  e la successione delle funzioni chiamate è la stessa della versione in C++. L’importanza delle classi dal punto di vista della sicurezza e robustezza del software è già stata ampiamente discussa ai punti 2.2 e 2.5 del capitolo 2. Di conseguenza ricordiamo solamente che l’assenza delle classi in C comporta l’impossibilità di sfruttare il principio dell’information hiding. Come nella libreria DhLib, anche in RsaLib le variabili dell’algoritmo non sono più campi privati di una classe ma

Page 52: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

40  

vengono inserite all’interno di una struct keysRsa (linee 15÷19) e, quindi, chi utilizza la libreria può accedervi direttamente. Come detto, questo determina un livello di sicurezza minore rispetto alle classi del C++. Nella libreria è stata definita, inoltre, la struct publicKeyRsa (linee 21÷24) per contenere la chiave pubblica costituita dalla coppia (n, e). Abbiamo visto che questi due numeri sono le uniche informazioni condivise pubblicamente e, quindi, chi le riceve non ha bisogno di utilizzare tutti i campi della struct keysRsa (contrariamente a chi genera entrambe le chiavi). Di conseguenza la funzione ReceivePublicKey() riceve come parametro una struct publicKeyRsa (linea 26) in cui memorizzerà la chiave pubblica ricevuta. Poiché quest’ultima viene utilizzata anche nell’operazione di cifratura, anche la funzione RsaEncrypt() ha come parametro d’ingresso una struct publicKeyRsa (linea 27). Al punto 2.5 del capitolo 2 si è parlato, inoltre, dell’effetto che l’overloading degli operatori del C++ determina sulla leggibilità del codice. Abbiamo visto che in C++ le variabili dell’algoritmo sono oggetti della classe mpz_class, che quest’ultima realizza l’overloading degli operatori (relazionali, matematici e di input/output) e che ciò semplifica notevolmente l’utilizzo di tale tipo di dato e la leggibilità del codice. In C, invece, le variabili sono di tipo mpz_t ed è necessario utilizzare le funzioni specifiche della libreria GMP per lavorare su di esse. Questo può peggiorare di molto la leggibilità del codice se confrontato con il C++, come risulta evidente per i metodi ComputeGCD() e ComputeD(). In entrambe le funzioni le operazioni svolte sui dati possono risultare di difficile comprensione, a differenza di quanto accade per le stesse funzioni scritte in C++. Si ritiene, quindi, opportuno evidenziare le funzioni della libreria GMP utilizzate in RsaLib (oltre a quelle già citate in precedenza):

• mpz_sub() che esegue la sottrazione tra due interi mpz_t, ovvero svolge il compito dell’operatore “-” per questo tipo di dati

• mpz_ui_sub() per sottrarre un intero mpz_t ad uno unsigned long • mpz_mul() che esegue la sottrazione tra due interi mpz_t (operatore “ * ”) • mpz_add() che svolge il compito dell’operatore “+” per gli interi mpz_t • mpz_fdiv_r() che esegue l’operazione “%” tra due interi mpz_t • mpz_fdiv_q() che esegue l’operazione “ / ” tra due interi mpz_t

Anche la libreria RsaDataLib è stata opportunamente tradotta in linguaggio C (il codice è riportato in appendice alle voci RsaDataLib.h RsaDataLib.c). Come fatto in precedenza, ne richiamiamo di seguito la dichiarazione delle funzioni: 6      void  ReceiveAndDecryptData(struct  keysRsa*  privateKey,  int  socket);  7      char*  ReadFromFile();  8      char*  ReadMessage();  9      void  SendData(char*  data,  struct  publicKeyRsa*  pbk,  int  socket);  10    bool  ReadAndSendData(struct  publicKeyRsa*  rk,  int  socket);  11    char*  ResizeDinamicString(char*  toResize,  int  newDim);  12    void  RebuildData(char*  decryptedStr);   Anche in questo caso sono state mantenute tutte le funzioni presenti nella versione in C++ e quindi la comunicazione cifrata fra due parti avviene esattamente nello stesso modo descritto in precedenza.

Page 53: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

41  

Anche in questo caso valgono le considerazioni fatte al punto 2.5 del capitolo 2 per quanto riguarda la gestione delle stringhe di dimensione dinamica. Per maggiori dettagli si rimanda a tale capitolo. Qui ci limitiamo solamente a evidenziare il ricorso all’allocazione dinamica della memoria. Da notare, a questo proposito, la presenza della funzione ResizeDinamicString() nella libreria (linea11) utilizzata per il ridimensionamento delle stringhe (già descritta nel capitolo 2) e delle chiamate a malloc() e free() nel codice (rispettivamente linee 54, 201 e 32, 36, 90, 98, 189 e 208 in appendice). Il codice relativo ai programmi scritti come esempio di utilizzo delle librerie RsaLib e RsaDataLib è riportato in appendice alle voci Rsa_s.c e Rsa_c.c.

Page 54: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

42  

Page 55: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

43  

Conclusioni In questa tesi sono stati realizzati tutti gli strumenti e i programmi necessari ad effettuare comunicazioni cifrate attraverso la rete grazie agli algoritmi considerati. Il raggiungimento di tale risultato ha richiesto lo studio di nuovi argomenti o, comunque, l’approfondimento di argomenti trattati solo parzialmente durante i corsi. Questo ha permesso, quindi, l’apprendimento di importanti nozioni riguardanti la crittografia, la sicurezza informatica e l’utilizzo di strumenti per la programmazione in linguaggio C e C++ che estendono le conoscenze acquisite durante i corsi.

Page 56: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

44  

Page 57: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

45  

Bibliografia [1] «Corso di Reti di Calcolatori», 18/12/2014,

http://web.diegm.uniud.it/pierluca/public_html/teaching/reti_di_calcolatori/reti_di_calcolatori.html

[2] «Cygwin», 18/12/2014, https://cygwin.com/install.html [3] «GMP», 18/12/2014, https://gmplib.org/#DOWNLOAD [4] W. Diffie and M.E. Hellman, “New Directions in Cryptography”, IEEE

Transactions on Information Theory, Vol. IT-22, No. 6, November 1976, pp. 644-654.

[5] «Diffie-Hellman: choosing wrong generator “g” parameter and its implications of

practical attacks», 18/12/2014, http://crypto.stackexchange.com/questions/10025/diffie-hellman-choosing-wrong-generator-g-parameter-and-its-implications-of-p

[6] «How does one calculate a primitive root for Diffie-Hellman?», 18/12/2014,

http://crypto.stackexchange.com/questions/820/how-does-one-calculate-a-primitive-root-for-diffie-hellman

[7] R.L. Rivest, A. Shamir and L. Adelman “A Method for Obtaining Digital

Signatures and Public-Key Cryptosystems”, Communications of the ACM, Vol. 21, No 2, February 1978, pp. 120-126.

[8] A.S. Tanenbaum, D.J Wetherall, “Reti Di Calcolatori”, Editore Pearson,

settembre 2011, pp 758-759. [9] «Modular inverse», 18/12/2014, http://rosettacode.org/wiki/Modular_inverse

Page 58: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

46  

Page 59: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

47  

Appendici File in C++ ClassDh.hpp 1      #ifndef  DH_HPP  2      #define  DH_HPP  3  4      #include  <cassert>  5      #include  <iostream>  6      #include  <gmpxx.h>  7      #include  <string>  8      #include  <unistd.h>  9      #include  "udpsocketlib.hpp"  10    #include  "openssl/bn.h"  11  12    using  namespace  std;  13  14    class  Dh  15    {  16            public:  17                    mpz_class  ReturnKey()  const  {  return  K;  }  18                    int  SizeOfK()  const  {  return  mpz_sizeinbase(K.get_mpz_t(),  

10);  }  19                    bool  GenerateEncryptionKey_Client(int  socket,  string  

ipAddress,  int  udpPort);  20                    bool  GenerateEncryptionKey_Server(int  socket);  21                    string  DhEncrypt(const  string&  toEncryptStr);  22                    string  DhDecrypt(const  char*  toDecrypt);  23  24            private:  25                    mpz_class  p,  g,  a,  b,  A,  B;  26                    mpz_class  K;  //key  27                    mpz_class  GetVariable(string  varName);  28                    mpz_class  GeneratePrimeNumber(string  name,  unsigned  numBits);  29                    mpz_class  FindGenerator();  30                    void  GetPgaAndSetA(int  choice);  31                    bool  SendPGA(int  socket,  string  ipAddress,  int  udpPort);  32                    bool  ReceiveBandComputeK(int  socket);  33                    bool  ReceivePGA(int  socket);  34                    bool  SendB(int  socket);  35                    void  ComputeBandKey();  36                    int  rdtsc();  37    };  38    #endif  

Page 60: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

48  

ClassDh.cpp 1      #include  "ClassDh.hpp"  2  3      mpz_class  Dh::GetVariable(string  varName)  4      {  5              mpz_class  var;  6              string  varStr;  7  8              do  9              {  10                    cout<<"\nEnter  "<<varName<<":  ";  11                    cin>>varStr;  12                    var.set_str(varStr,  10);  13                    if  (var  <=  0)  14                            cout<<"\nError.  Please  insert  a  number  >  0"<<endl;  15            }while  (var  <=  0);  16            return  var;  17    }  18  19    void  Dh::GetPgaAndSetA(int  choice)  20    {  21            if  (choice  ==  1)  22            {  23                    cout<<"\n\nGenerating  'p'  and  'g'...\n\n";  24                    p  =  GeneratePrimeNumber("p",  1024);  25                    g  =  FindGenerator();  26            }  27            else  if  (choice  ==  2)  28            {  29                    p  =  GetVariable("'p'");  30                    g  =  GetVariable("'g'");  31            }  32            a  =  GetVariable("'a',  such  that  1<a<p");  33            assert(a  <  p  &&  a  >  1);  34            mpz_powm(A.get_mpz_t(),  g.get_mpz_t(),  a.get_mpz_t(),  

p.get_mpz_t());  35            cout<<"\n\tA=g^a  (mod  p)="<<A<<endl;  36    }  37  38    mpz_class  Dh::FindGenerator()  39    {  40            mpz_class  g;  41            string  pStr,  gStr;  42            int  size,  temp;  43            bool  sameSize;  44            g  =  p  –  2;  45            pStr  =  p.get_str(10);  46            do  47            {  48                    srand(rdtsc());  49                    size  =  (rand()  %  (pStr.size()  –  1  ))  +  1;  50                    sameSize  =  (size  ==  (int)pStr.size());  51                    for  (int  i  =  0;  i  <  size;  i++)  52                    {  53                            srand(rdtsc());  

Page 61: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

49  

54                            if  (sameSize)  55                            {  56                                    temp  =  pStr[i]  -­‐  '0';  57                                    if  (temp  !=  0)  58                                            temp  =  rand()  %  temp;  59                            }  60                            else  61                                    temp  =  rand()  %  9;  62                            gStr.push_back((char)  temp  +  '0');  63                    }  64                    g.set_str(gStr,  10);  65            }while  (g  ==  2);  66            cout<<"\n\tg="<<g<<endl;  67            return  g;  68    }  69  70    mpz_class  Dh::GeneratePrimeNumber(string  name,  unsigned  numBits)  71    {  72            bool  ctrl  =  false;  73            mpz_class  num;  74            BIGNUM  primeNum;  75            BN_init(&primeNum);  76            do  77            {  78                    ctrl  =  BN_generate_prime_ex(&primeNum,  numBits,  1,  NULL,  NULL,  

NULL);  79            }while  (!ctrl);  80            num  =  BN_bn2dec(&primeNum);  81            BN_free(&primeNum);  82            cout<<"\n\t"<<name<<"="<<num<<endl;  83            return  num;  84    }  85  86    bool  Dh::SendPGA(int  socket,  string  ipAddress,  int  udpPort)  87    {  88            string  toSend[3];  89            toSend[0]  =  p.get_str(10);  90            toSend[1]  =  g.get_str(10);  91            toSend[2]  =  A.get_str(10);  92            cout<<"\nSending  p,g  and  A..."<<endl<<endl;  93            for  (unsigned  count  =  0;  count  <  3;  count++)  94            {  95                    if  (!udp_send(socket,  (char*)toSend[count].c_str(),  

(char*)ipAddress.c_str(),  udpPort))  96                    {  97                            cout<<"Unable  to  send  p,  g  and  A..."<<endl<<endl;  98                            return  false;  99                    }  100                    sleep(1);  101          }  102          return  true;  103  }  104  105  bool  Dh::ReceiveBandComputeK(int  socket)  106  {  107          char  strB[BUFSIZ+1];  108  

Page 62: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

50  

109          if  (udp_receive(socket,  strB)  ==  -­‐1)  110          {  111                  cout<<"Unable  to  receive  B!"<<endl<<endl;  112                  return  false;  113          }  114          cout<<"B  received!\n\n\tB="<<strB<<endl<<endl;  115          B.set_str(strB,  10);  116          if  (B  >  0)  117          {  118                  mpz_powm(K.get_mpz_t(),  B.get_mpz_t(),  a.get_mpz_t(),  

p.get_mpz_t());  119                  return  true;  120          }  121          else  122                  return  false;  123  }  124  125  bool  Dh::ReceivePGA(int  socket)  126  {  127          char  strPGA[3][BUFSIZ+1];  128          unsigned  count  =  0;  129  130          cout<<"\n\nWaiting  for  p,  g  and  A...\n\n";  131          do  132          {  133                  if  (udp_receive(socket,  strPGA[count])  ==  -­‐1)  134                  {  135                          cout<<"Unable  to  receive  p,g  and  A!"<<endl<<endl;  136                          return  false;  137                  }  138                  count++;  139          }while  (count  <  3);  140  141          p.set_str(strPGA[0],  10);  142          g.set_str(strPGA[1],  10);  143          A.set_str(strPGA[2],  10);  144  145          if  (p  !=  0  &&  g  !=  0  &&  A  !=0)  146          {  147                  cout<<"Data  received:"<<endl<<endl;  148                  cout<<"\n\tp="<<p<<"\n\n\tg="<<g<<"\n\n\tA="<<A<<endl<<endl;  149                return  true;  150          }  151          else  152          {  153                  cout<<"Error.  Wrong  data."<<endl<<endl;  154                  return  false;  155          }  156  }  157  158  bool  Dh::SendB(int  socket)  159  {  160          string  toSend  =  B.get_str(10);  161  162          cout<<"Sending  B..."<<endl<<endl;  163          if  (!udp_reply(socket,  (char*)toSend.c_str()))  164          {  

Page 63: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

51  

165                  cout<<"Unable  to  send  B..."<<endl<<endl;  166                  return  false;  167          }  168          cout<<"Data  sent!"<<endl<<endl;  169          return  true;  170  }  171  172  void  Dh::ComputeBandKey()  173  {  174          b  =  GetVariable("'b',  such  that  1<b<p");  175          assert(b  >  1  &&  b  <  p);  176  177          mpz_powm(B.get_mpz_t(),  g.get_mpz_t(),  b.get_mpz_t(),  

p.get_mpz_t());  178          mpz_powm(K.get_mpz_t(),  A.get_mpz_t(),  b.get_mpz_t(),  

p.get_mpz_t());  179          cout<<"\n\tB=g^b  (mod  p)="<<B<<endl<<endl;  180  }  181  182  bool  Dh::GenerateEncryptionKey_Client(int  socket,  string  ipAddress,  

int  udpPort)  183  {  184          int  choice;  185          cout<<"\n\nAutomatically  generate  p,g?\n";  186          cout<<"1)Yes.\n";  187          cout<<"2)No,  I  insert  them.\n";  188          do  189          {  190                  cout<<"\nChoose  an  option:";  191                  cin>>choice;  192                  if  (choice  !=  1  &&  choice  !=  2)  193                          cout<<"\nInvalid  choice!\n\n";  194          }while  (choice  !=  1  &&  choice  !=  2);  195  196          GetPgaAndSetA(choice);  197  198          if  (SendPGA(socket,  (char*)ipAddress.c_str(),  udpPort))  199          {  200                  cout<<"Data  sent!\n\nWaiting  for  B..."<<endl<<endl;  201                  if  (ReceiveBandComputeK(socket))  202                  {  203                          cout<<"\n\nThe  encryption  key  is:\n\n\tK=B^a  (mod  

p)="<<K<<endl<<endl;  204                          return  true;  205                  }  206          }  207          cout<<"\nUnable  to  create  the  key."<<endl;  208          return  false;  209  }  210  211  bool  Dh::GenerateEncryptionKey_Server(int  socket)  212  {  213          if  (ReceivePGA(socket))  214          {  215                  ComputeBandKey();  216                  if  (SendB(socket))  217                  {  

Page 64: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

52  

218                          cout<<"\n\nThe  encryption  key  is:\n\n\tK=A^b  (mod  p)="<<K<<endl<<endl;  

219                          return  true;  220                  }  221          }  222          cout<<"\nUnable  to  create  the  key."<<endl;  223          return  false;  224  }  225  226  string  Dh::DhEncrypt(const  string&  toEncryptStr)  227  {  228          string  key,  encrypted;  229          char  ch[4];  230          key  =  K.get_str(10);  231          for  (unsigned  i  =  0;  i  <  toEncryptStr.size();  i++)  232          {  233                  sprintf(ch,  "%.3d",  (unsigned  char)toEncryptStr[i]^  (unsigned  

char)key[i]);  234                  encrypted  +=  ch;  235          }  236          return  encrypted;  237  }  238  239  string  Dh::DhDecrypt(const  char*  toDecrypt)  240  {  241          string  key,  decrypted;  242          char  ch[4];  243          unsigned  aux  =  0,  count  =  0;  244          key  =  K.get_str(10);  245          decrypted.append(toDecrypt);  246          for  (unsigned  i  =  0;  i  <  strlen(toDecrypt);  i++)  247          {  248                  ch[aux]  =  toDecrypt[i];  249                  aux++;  250                  if  (aux  ==  3)  251                  {  252                          ch[3]  =  '\0';  253                          decrypted.push_back((unsigned  char)  atoi(ch)^key[count]);  254                          aux  =  0,  count++;  255                  }  256          }  257          return  decrypted;  258  }  259  260  int  Dh::rdtsc()  261  {  262          __asm__  __volatile__("rdtsc");  263  }  264  265  void  error_handler(char  *message)  266  {  267          cout<<"fatal  error:  "<<message<<endl;  268          return;  269  }  

Page 65: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

53  

DhDataLib.hpp 1      #ifndef  DHDATALIB_HPP  2      #define  DHDATALIB_HPP  3  4      #include  "ClassDh.hpp"  5      #include  <fstream>  6  7      bool  ReadAndSendData(Dh&  srv,  int  socket);  8      bool  ReceiveAndDecryptData(Dh&  srv,  int  socket);  9      void  SendData(const  string&  data,  Dh&  srv,  int  socket);  10    string  ReadFromFile();  11    string  ReadMessage();  12    void  printStrInDec(const  string&  toPrint);  13    void  printStrInHex(const  string&  toPrint,  bool  crypted);  14  15    #endif   DhDataLib.cpp 1      #include  "DhDataLib.hpp"  2  3      void  printStrInDec(const  string&  toPrint)  4      {  5              for  (unsigned  i  =  0;  i  <  toPrint.size();  i++)  6              {  7                      cout<<toPrint[i];  8                      if  (((i  +  1)  %  3)  ==  0)  9                              cout<<”  “;  10            }  11            cout<<endl;  12    }  13  14    void  printStrInHex(const  string&  toPrint,  bool  crypted)  15    {  16            char  ch[4];  17            unsigned  k  =  0;  18            cout<<"\nIn  hex:  ";  19            for  (unsigned  i  =  0;  i  <  toPrint.size();  i++)  20                    if  (crypted)  21                    {  22                            ch[k]  =  toPrint[i],  k++;  23                            if  (k  ==  3)  24                            {  25                                    ch[3]  =  '\n',  k  =  0;  26                                    cout<<hex<<atoi(ch)<<”  “;  27                            }  28                    }  29                    else  30                    cout<<hex<<(int)((unsigned  char)toPrint[i])<<"  ";  31  32            cout<<endl;  33    }  34    

Page 66: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

54  

35    bool  ReceiveAndDecryptData(Dh&  srv,  int  socket)  36    {  37            bool  exitFunction  =  false;  38            bool  exitProgram  =  false;  39            char  buffer[BUFSIZ+1];  40            string  messageDecripted,  bufferDecrypted;  41  42            cout<<"\n\n\nWaiting  for  data.."<<endl<<endl;  43            while  (!exitFunction)  44            {  45                    udp_receive(socket,  buffer);  46                    cout<<"\n\n\nEncrypted  data  received  (in  decimal):  ";  47                    printStrInDec(buffer);  48                    printStrInHex(buffer,  true);  49                    bufferDecrypted  =  srv.DhDecrypt(buffer);  50                    cout<<"\n\nDecrypted  data  received:  "<<bufferDecrypted<<endl;  51                    printStrInHex(bufferDecrypted,  false);  52                    messageDecripted  +=  bufferDecrypted;  53  54                    if  (messageDecripted.find("EOTS~EOTS~EOTS",  

messageDecripted.size()  -­‐14)!=  string::npos)  55                    {  56                            exitProgram  =  true;  57                            exitFunction  =  true;  58                    }  59                    else  if  (messageDecripted.find("EOF~EOF~EOF",  

messageDecripted.size()  -­‐  11)!=  string::npos)  60                    {  61                            messageDecripted  =  

messageDecripted.erase(messageDecripted.size()  -­‐  11,  11);  62                            cout<<"\n\n\nDecripted  data:"<<endl<<endl;  63                            cout<<messageDecripted<<endl<<endl;  64                            messageDecripted.clear();  65                            exitFunction  =  true;  66                    }  67            }  68            return  exitProgram;  69    }  70  71    bool  ReadAndSendData(Dh&  srv,  int  socket)  72    {  73            string  message;  74            int  choice;  75            cout<<"\n\nWhat  do  you  want  to  do?"<<endl<<endl;  76            cout<<"1)Send  a  message"<<endl;  77            cout<<"2)Send  data  from  file"<<endl;  78            cout<<"3)Exit"<<endl;  79            do  80            {  81                    cout<<"Choose  an  option:";  82                    cin>>choice;  83                    switch  (choice)  84                    {  85                            case  1:  86                            {  87                                    message  =  ReadMessage();  88                                    SendData(message,  srv,  socket);  

Page 67: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

55  

89                                    break;  90                            }  91                            case  2:  92                            {  93                                    message  =  ReadFromFile();  94                                    SendData(message,  srv,  socket);  95                                    break;  96                            }  97                          case  3:  98                                  SendData("EOTS~EOTS~EOTS",  srv,  socket);  99                                  break;  100                          default:  101                                  cout<<"\nInvalid  choice!"<<endl<<endl;  102                  }  103          }while  (choice  !=  1  &&  choice  !=  2  &&  choice  !=  3);  104          return  choice  ==  3;  105  }  106  107  string  ReadMessage()  108  {  109          string  message;  110          char  ch;  111          cout<<"\nEnter  the  message  to  send:  ";  112          ch  =  cin.get();  //  clean  the  stream.  113          do  114          {  115                  ch  =  cin.get();  116                  message  +=  ch;  117          }  118          while  (ch  !=  '\n');  119                  message[message.size()  -­‐  1]=  '\0';  120          message  +=  "EOF~EOF~EOF";  121          return  message;  122  }  123  124  string  ReadFromFile()  125  {  126          ifstream  is;  127          string  nameFile,  fileData;  128          char  ch;  129          cout<<"\nEnter  file  name  with  extension:  ";  130          cin>>nameFile;  131          is.open(nameFile.c_str());  132          while  (is.get(ch))  133                  fileData  +=  ch;  134  135          is.close();  136          fileData  +=  "EOF~EOF~EOF";  137          return  fileData;  138  }  139  140  void  SendData(const  string&  data,  Dh&  srv,  int  socket)  141  {  142          string  encryptedStr;  143          int  keyLen  =  srv.SizeOfK();  144          int  counter  =  0;  145          for  (unsigned  i  =  0;  i  <  data.size();  i++)  

Page 68: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

56  

146          {  147                  encryptedStr.push_back(data[i]);  148                  if  (counter  ==  keyLen  -­‐  1  ||  i  ==  data.size()  -­‐  1)  149                  {  150                          cout<<"\n\n\nData  to  send:  "<<encryptedStr<<endl;  151                          printStrInHex(encryptedStr,  false);  152                          encryptedStr  =  srv.DhEncrypt(encryptedStr);  153                          cout<<"\n\nEncrypted  data  to  send  (in  decimal):  ";  154                          printStrInDec(encryptedStr);  155                          printStrInHex(encryptedStr,  true);  156                          udp_reply(socket,  (char*)encryptedStr.c_str());  157                          sleep(1);  158                          encryptedStr.clear();  159                          counter  =  0;  160                  }  161                  counter++;  162          }  163  }   ClassRsa.hpp 1      #ifndef  RSA_HPP  2      #define  RSA_HPP  3  4      #include  <cassert>  5      #include  <iostream>  6      #include  <gmpxx.h>  7      #include  <string>  8      #include  <unistd.h>  9      #include  "udpsocketlib.hpp"  10    #include  "openssl/bn.h"  11  12    using  namespace  std;  13  14    class  Rsa  15    {  16            public:  17                    mpz_class  N()  const  {  return  n;}  18                    int  SizeOfN()  const  {  return  mpz_sizeinbase(n.get_mpz_t(),  

10);}  19                    mpz_class  E()  const  {  return  e;}  20                    mpz_class  D()  const  {  return  d;}  21                    void  GenerateEncryptionKeys();  22                    bool  SendPublicKey(int  socket,  string  ipAddress,  int  udpPort);  23                    bool  ReceivePublicKey(int  socket);  24                    void  RsaEncrypt(string&  toEncryptStr);  25                    string  RsaDecrypt  (const  char*  toDecrypt);  26  27        private:  28                    mpz_class  p,  q,  phi;  29                    mpz_class  n,  e,  d;  //keys  30                    mpz_class  ComputeGCD(const  mpz_class&  x,  const  mpz_class&  y);  31                    mpz_class  GetRandomE();  32                    void  GeneratePQandComputeNPhi();  33                    mpz_class  GeneratePrimeNumber(string  name,  unsigned  numBits);  34                    void  FindE();  

Page 69: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

57  

35                    void  ComputeD();  36                    int  rdtsc();  37    };  38  39    #endif   ClassRsa.cpp 1      #include  "ClassRsa.hpp"  2  3      mpz_class  Rsa::GeneratePrimeNumber(string  name,  unsigned  numBits)  4      {  5              bool  ctrl  =  false;  6              mpz_class  num;  7              BIGNUM  primeNum;  8              BN_init(&primeNum);  9              do  10            {  11                    ctrl  =  BN_generate_prime_ex(&primeNum,  numBits,  1,  NULL,  NULL,  

NULL);  12            }while  (!ctrl);  13            num  =  BN_bn2dec(&primeNum);  14            BN_free(&primeNum);  15            cout<<"\t"<<name<<"="<<num<<endl<<endl;  16            return  num;  17    }  18  19    void  Rsa::GeneratePQandComputeNPhi()  20    {  21            cout<<"\n\nGenerating  prime  numbers  'p'  and  'q'.."<<endl<<endl;  22            p  =  GeneratePrimeNumber("p",  512);  23            q  =  GeneratePrimeNumber("q",  512);  24            cout<<"\n\nComputing  'n'  and  'phi'.."<<endl<<endl;  25            assert(p  !=  0  &&  q  !=  0);  26            n  =  p  *  q;  27            phi  =  (p  -­‐  1)  *  (q  –  1);  28            cout<<"\tn=p*q="<<n<<"\n\n\tphi=(p-­‐1)*(q-­‐1)="<<phi<<endl<<endl;  29    }  30  31    mpz_class  Rsa::GetRandomE()  32    {  33            mpz_class  aux;  34            string  str;  35            int  max,  min,  temp,  size;  36            aux  =  phi  -­‐  1;  37            max  =  mpz_sizeinbase(aux.get_mpz_t(),  10);  38            if  (p  >=  q)  39                    min  =  mpz_sizeinbase(p.get_mpz_t(),  10)  +  1;  40            else  41                    min  =  mpz_sizeinbase(q.get_mpz_t(),  10)  +  1;  42            do  43            {  44                    srand(rdtsc());  45                    size  =  (rand()  %  (max  -­‐  min))  +  min;  46                    for  (int  i  =  0;  i  <  size;  i++)  47                    {  

Page 70: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

58  

48                            srand(rdtsc());  49                            temp  =  rand()  %  9;  50                            str.push_back((char)temp  +  '0');  51                    }  52                    aux.set_str(str,  10);  53            }while  (aux  >=  phi  -­‐  1);  54            return  aux;  55    }  56  57    void  Rsa::FindE()  58    {  59            mpz_class  temp  =  0;  60            bool  eFound  =  false;  61            assert(phi  !=  0);  62            do  63            {  64                    e  =  GetRandomE();  65                    while  (temp!=  1  &&  e  >  p  &&  e  >  q)  66                    {  67                            temp  =  ComputeGCD(e,  phi);  68                            if  (temp  ==  1)  69                                    eFound  =  true;  70                            else  71                                    e  -­‐=  1;  72                    }  73            }while  (!eFound);  74            cout<<"\n\n\t'e'  such  that  GCD(e,phi)=1  is:"<<e<<endl<<endl;  75    }  76  77    mpz_class  Rsa::ComputeGCD(const  mpz_class&  x,  const  mpz_class&  y)  78    {  79            mpz_class  m  =  0,  n  =  0,  r  =  0;  80            m  =  x;  81            n  =  y;  82            if  (m  >  n)  83                    r  =  n;  84            else  85            {  86                    r  =  m;  87                    m  =  n;  88                    n  =  r;  89            }  90            while  (r  !=  0)  91            {  92                    r  =  m  %  n;  93                    m  =  n;  94                    n  =  r;  95            }  96            r  =  m;  97            return  r;  98    }  99  100  void  Rsa::ComputeD()  101  {  102          mpz_class  t,  nt,  r,  nr,  q,  tmp,  a,  b;  103          a  =  e;  b  =  phi;  104          if  (b  <  0)  

Page 71: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

59  

105                  b  =  -­‐b;  106          if  (a  <  0)  107                  a  =  b  -­‐  (-­‐a  %  b);  108          t  =  0;  109          nt  =  1;  110          r  =  b;  111          nr  =  a  %  b;  112          while  (nr  !=  0)  113          {      114                  q  =  r  /  nr;  115                  tmp  =  nt;  116                  nt  =  t  –  (q  *  nt);  117                  t  =  tmp;  118                  tmp  =  nr;  119                  nr  =  r  –  (q  *  nr);  120                  r  =  tmp;  121          }  122          assert(r  <=  1);  /*  No  inverse  */      123          if  (t  <  0)  124                  t  +=  b;  125          d  =  t;  126          cout<<"\t'd'  such  that  (e*d=  1  mod  phi)  is:"<<d<<endl<<endl;  127  }  128  129  void  Rsa::GenerateEncryptionKeys()  130  {  131          GeneratePQandComputeNPhi();  132          FindE();  133          ComputeD();  134          cout<<"\nThe  private  key  

is(d,n):\n\n\td="<<d<<"\n\n\tn="<<n<<endl<<endl;  135          cout<<"\nThe  public  key  

is(e,n):\n\n\te="<<e<<"\n\n\tn="<<n<<endl<<endl;  136  }  137  138  bool  Rsa::SendPublicKey(int  socket,  string  ipAddress,  int  udpPort)  139  {  140          string  public_key[2];  141          assert(e  !=  0  &&  n  !=  0);  142          public_key[0]  =  e.get_str(10);  143          public_key[1]  =  n.get_str(10);  144          cout<<"Sharing  the  public  key..Sending  'e'  and  

'n'..."<<endl<<endl;  145          for  (unsigned  count  =  0;  count  <  2;  count++)  146          {  147                  if  (!udp_send(socket,  (char*)public_key[count].c_str(),  

(char*)ipAddress.c_str(),  udpPort))  148                  {  149                          cout<<"Unable  to  send  the  public  key..."<<endl<<endl;  150                          return  false;  151                  }  152                  sleep(1);  153          }  154          cout<<"Data  sent!\n\nWaiting..."<<endl<<endl;  155          return  true;  156  }  157  

Page 72: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

60  

158  bool  Rsa::ReceivePublicKey(int  socket)  159  {  160          char  public_key[2][BUFSIZ+1];  161          unsigned  count  =  0;  162          cout<<"\n\nWaiting  for  public  key..."<<endl<<endl;  163          do  164          {  165                  if  (udp_receive(socket,  public_key[count])  ==  -­‐1)  166                  {  167                          cout<<"Unable  to  receive  the  public  key..."<<endl<<endl;  168                          return  false;  169                  }  170                  count++;  171          }while  (count  <  2);  172          e.set_str(public_key[0],  10);  173          n.set_str(public_key[1],  10);  174          if  (n  ==  0  ||  e  ==  0)  175          {  176                  cout<<"Error.  Wrong  public  key."<<endl<<endl;  177                  return  false;  178          }  179          cout<<"The  public  key(e,n)  is:"<<endl<<endl;  180          cout<<"\te="<<e<<"\n\n\tn="<<n<<endl<<endl;  181          return  true;  182 }  183  184  void  Rsa::RsaEncrypt(string&  toEncryptStr)  185  {  186          mpz_class  encrypted;  187          encrypted.set_str(toEncryptStr,  10);  188          cout<<"\n\nData  to  send(in  

decimal):"<<endl<<toEncryptStr<<endl<<endl;  189  190          mpz_powm(encrypted.get_mpz_t(),  encrypted.get_mpz_t()  ,  

e.get_mpz_t(),  n.get_mpz_t());  191  192          toEncryptStr  =  encrypted.get_str(10);  193          cout<<"Encrypted  data  to  send(in  

decimal):"<<endl<<toEncryptStr<<endl<<endl;  194  }  195  196  string  Rsa::RsaDecrypt(const  char*  toDecrypt)  197  {  198          mpz_class  decrypted;  199          cout<<"\nEncrypted  data  received(in  

decimal):"<<endl<<toDecrypt<<endl<<endl;  200          decrypted.set_str(toDecrypt,  10);  201          mpz_powm(decrypted.get_mpz_t(),  decrypted.get_mpz_t()  ,  

d.get_mpz_t(),  n.get_mpz_t());  202          return  decrypted.get_str(10);  203  }  204  205  void  error_handler(char  *message)  206  {  207          cout<<"fatal  error:  "<<message<<endl;  208          return;  209  }  

Page 73: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

61  

210  211  int  Rsa::rdtsc()  212  {  213          __asm__  __volatile__("rdtsc");  214  }   RsaDataLib.hpp 1      #ifndef  RSADATALIB_HPP  2      #define  RSADATALIB_HPP  3  4      #include  "ClassRsa.hpp"  5      #include  <fstream>  6  7      void  ReceiveAndDecryptData(Rsa&  clt,  int  socket);  8      bool  ReadAndSendData(Rsa&  srv,    int  socket);  9      void  SendData(const  string&  data,  Rsa&  srv,  int  socket);  10    string  ReadFromFile();  11    string  ReadMessage();  12    string  RebuildData(string&  decryptedStr);  13  14    #endif   RsaDataLib.cpp 1      #include  "RsaDataLib.hpp"  2  3      void  ReceiveAndDecryptData(Rsa&  clt,  int  socket)  4      {  5              bool  exit  =  false;  6              char  buffer[BUFSIZ  +  1];  7              string  messageDecripted,  aux;  8              while  (!exit)  9              {  10                    udp_receive(socket,  buffer);  11                    aux  =  clt.RsaDecrypt(buffer);  12                    messageDecripted  +=  RebuildData(aux);  13                    if  (messageDecripted.find("EOTS~EOTS~EOTS",  

messageDecripted.size()  -­‐  14)!=  string::npos)  14                    {  15                            cout<<"\n\nExit.."<<endl<<endl;  16                            exit  =  true;  17                    }      18                    else  if  (messageDecripted.find("EOF~EOF~EOF",  

messageDecripted.size()  -­‐  14)!=  string::npos)  19                    {  20                            messageDecripted  =  

messageDecripted.erase(messageDecripted.size()  -­‐  11,  11);  21                            cout<<"\n\nDecripted  data:"<<endl<<endl;  22                            cout<<messageDecripted<<endl<<endl;  23                            messageDecripted.clear();  24                            cout<<"\nWaiting  for  new  data.."<<endl<<endl;  25                    }  26              }  27    }  

Page 74: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

62  

28  29    string  RebuildData(string&  decryptedStr)  30    {  31            int  r,  strLen,  k  =  0;  32            char  ch[4];  33            string  finalStr;  34            strLen  =  decryptedStr.size();  35            r  =  strLen  %  3;  36            if  (r  !=0)  37                    for  (int  i  =  0;  i  <  (3  –  r);  i++)  38                            decryptedStr  =  "0"  +  decryptedStr;  39            cout<<"Received  data  decrypted(in  

decimal):"<<endl<<decryptedStr<<endl<<endl;  40            do  41            {  42                    int  length  =  0;  43                    if  (strLen  >=  3)  44                            length  =  decryptedStr.copy(ch,  3,  k);  45                    else  46                            length  =  decryptedStr.copy(ch,  strLen,  k);  47                    ch[length]=  '\0';  48                    char  c  =  (char)(atoi(ch));  49                    finalStr  +=  c;  50                    k  +=  3;  51            }while  (k  <  strLen);  52            cout<<"Received  data  decrypted:"<<endl<<finalStr<<endl<<endl;  53            return  finalStr;  54    }  55  56    bool  ReadAndSendData(Rsa&  srv,    int  socket)  57    {  58            string  message;  59            int  choice;  60            cout<<"\n\nWhat  do  you  want  to  do?"<<endl<<endl;  61            cout<<"1)Send  a  message"<<endl;  62            cout<<"2)Send  data  from  file"<<endl;  63            cout<<"3)Exit"<<endl;  64            do  65            {  66                    cout<<"Choose  an  option:";  67                    cin>>choice;  68                    switch  (choice)  69                    {  70                            case  1:  71                            {  72                                    message  =  ReadMessage();  73                                    SendData(message,  srv,  socket);  74                                    break;  75                            }  76                            case  2:  77                            {  78                                    message  =  ReadFromFile();  79                                    SendData(message,  srv,  socket);  80                                    break;  81                            }  82                            case  3:  83                                    SendData("EOTS~EOTS~EOTS",  srv,  socket);  

Page 75: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

63  

84                                    break;  85                            default:  86                                    cout<<"\nInvalid  choice!"<<endl<<endl;  87                    }  88            }while  (choice  !=  1  &&  choice  !=  2  &&  choice  !=  3);  89            return  choice  ==  3;  90    }  91  92    string  ReadMessage()  93    {  94            string  message;  95            char  ch;  96            cout<<"\nEnter  the  message  to  send:  ";  97            ch  =  cin.get();  //  Clean  the  stream  98            do  99            {  100                  ch  =  cin.get();  101                  message  +=  ch;  102          }  103          while  (ch  !=  '\n');  104          message[message.size()  -­‐  1]=  '\0';  105          message  +=  "EOF~EOF~EOF";  106          return  message;  107  }  108  109  string  ReadFromFile()  110  {  111          ifstream  is;  112          string  nameFile,  fileData;  113          char  ch;  114          cout<<"\nEnter  file  name  with  extension:  ";  115          cin>>nameFile;  116          is.open(nameFile.c_str());  117          while  (is.get(ch))  118                  fileData  +=  ch;  119          is.close();  120          fileData  +=  "EOF~EOF~EOF";  121          return  fileData;  122  }  123  124  void  SendData(const  string&  data,  Rsa&  srv,  int  socket)  125  {  126          string  encryptedStr,  toSend;  127          mpz_class  encrypted,  n;  128          char  ch[4];  129          n  =  srv.N();  130          for  (unsigned  i  =  0;  i  <=  data.size();  i++)  131          {  132                  sprintf(ch,  "%.3d",  (unsigned  char)data[i]);  133                  encryptedStr  +=  ch;  134                  encrypted.set_str(encryptedStr,  10);  135                  toSend  +=  data[i];  136                  if  (encrypted  >  n  ||  i  ==  data.size())  137                  {  138                          toSend.erase(toSend.size()  -­‐  1);  139                          cout<<"\n\nData  to  send:"<<endl<<toSend;  

Page 76: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

64  

140                          encryptedStr  =  encryptedStr.erase(encryptedStr.size()  -­‐  3,  3);  

141                          srv.RsaEncrypt(encryptedStr);  142                          udp_reply(socket,  (char*)encryptedStr.c_str());  143                          sleep  (1);  144                          encryptedStr.clear();  145                          toSend.clear();  146                          toSend  +=  data[i];  147                          encryptedStr  +=  ch;  148                  }  149          }  150  }   File in C DhLib.h 1      #ifndef  DHLIB_H  2      #define  DHLIB_H  3  4      #include  <stdio.h>  5      #include  <stdlib.h>  6      #include  <gmp.h>  7      #include  <string.h>  8      #include  <unistd.h>  9      #include  <openssl/bn.h>  10    #include  <assert.h>  11    #include  "udpsocketlib.h"  12  13    //  Create  type  bool  (not  present  in  c).  14    typedef  enum  {  false,  true  }  bool;  15  16    struct  dhStruct  17    {  18            mpz_t  p,  g,  a,  b,  A,  B,  K;  19    };  20  21    void  GeneratePrimeNumber(char*  name,  mpz_t  num,  unsigned  numBits);  22    void  FindGenerator(mpz_t  q,  mpz_t  g);  23    bool  GenerateEncryptionKey_Client(int  socket,  char*  ipAddress,  int  

udpPort,  struct  dhStruct*  dh);  24    void  GetPgaAndSetA(struct  dhStruct*  dh,  int  choice);  25    bool  SendPGA(int  socket,  char*  ipAddress,  int  udpPort,  struct  

dhStruct*  dh);  26    bool  ReceiveBandComputeK(int  socket,  struct  dhStruct*  dh);  27    bool  GenerateEncryptionKey_Server(int  socket,  struct  dhStruct*  dh);  28    bool  ReceivePGA(int  socket,  struct  dhStruct*  dh);  29    void  ComputeBandKey(struct  dhStruct*  dh);  30    bool  SendB(int  socket,  struct  dhStruct*  dh);  31    char*  DhEncrypt(char*  toEncryptStr,  char*  key);  32    char*  DhDecrypt(char*  toDecrypt,  char*  key);  33    void  GetVariable(char*  varName,  mpz_t  var);  34    int  rdtsc();  

Page 77: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

65  

35  36    #endif   DhLib.c 1      #include  "DhLib.h"  2  3      bool  GenerateEncryptionKey_Server(int  socket,  struct  dhStruct*  dh)  4      {  5              if  (ReceivePGA(socket,  dh))  6              {  7                      ComputeBandKey(dh);  8                      if  (SendB(socket,  dh))  9                      {  10                            gmp_printf("\n\nThe  encryption  key  is:\n\n\tK=A^b  (mod  

p)=%Zd\n\n",  dh-­‐>K);  11                            return  true;  12                    }  13            }  14            printf("\nUnable  to  create  the  key.\n");  15            return  false;  16    }  17  18    bool  ReceivePGA(int  socket,  struct  dhStruct*  dh)  19    {  20            char  strPGA  [3][BUFSIZ+1];  21            int  count  =  0;  22            printf("\n\nWaiting  for  p,  g  and  A...\n\n");  23            do  24            {  25                    if  (udp_receive(socket,  strPGA  [count])  ==  -­‐1)  26                    {  27                            printf("Unable  to  receive  p,g  and  A!\n\n");  28                            return  false;  29                    }  30                    count++;  31            }while  (count  <  3);  32            mpz_set_str(dh-­‐>p,  strPGA  [0],  10);  33            mpz_set_str(dh-­‐>g,  strPGA  [1],  10);  34            mpz_set_str(dh-­‐>A,  strPGA  [2],  10);  35            if  (mpz_cmp_ui(dh-­‐>p,  0)  !=0  &&  mpz_cmp_ui(dh-­‐>g,  0)  !=0  &&  

mpz_cmp_ui(dh-­‐>A,  0)  !=0)  36            {  37                    printf("Data  received:\n\n");  38                    gmp_printf("\n\tp=%Zd\n\n\tg=%Zd\n\n\tA=%Zd\n\n",  dh-­‐>p,  dh-­‐

>g,  dh-­‐>A);  39                    return  true;  40            }  41            else  42            {  43                    printf("Error.  Wrong  data.\n\n");  44                    return  false;  45            }  46    }  47    

Page 78: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

66  

48    void  ComputeBandKey(struct  dhStruct*  dh)  49    {  50            GetVariable("'b',  such  that  1<b<p",  dh-­‐>b);  51            assert(mpz_cmp_ui(dh-­‐>b,  1)  >  0  &&  mpz_cmp(dh-­‐>p,  dh-­‐>b)  >  0);  52            mpz_powm(dh-­‐>B,  dh-­‐>g,  dh-­‐>b,  dh-­‐>p);  53            mpz_powm(dh-­‐>K,  dh-­‐>A,  dh-­‐>b,  dh-­‐>p);    54            gmp_printf("\n\tB=g^b  (mod  p)=%Zd\n\n",  dh-­‐>B);  55    }  56  57    bool  SendB(int  socket,  struct  dhStruct*  dh)  58    {  59            char  *toSend  =  mpz_get_str(NULL,  10,  dh-­‐>B);  60            printf("Sending  B...\n\n");  61            if  (!udp_reply(socket,  toSend))  62            {  63                    printf("Unable  to  send  B...\n\n");  64                    return  false;  65            }  66            printf("Data  sent!\n\n");  67            return  true;  68    }  69  70    bool  GenerateEncryptionKey_Client(int  socket,  char*  ipAddress,  int  

udpPort,  struct  dhStruct*  dh)  71    {  72            int  choice;  73            printf("\n\nAutomatically  generate  p,g?\n");  74            printf("1)Yes.\n");  75            printf("2)No,  I  insert  them.\n");  76            do  77            {  78                    printf("\nChoose  an  option:");  79                    scanf("%d",  &choice);  80                    if  (choice  !=  1  &&  choice  !=  2)  81                            printf("\nInvalid  choice!\n\n");  82            }while  (choice  !=  1  &&  choice  !=  2);  83            GetPgaAndSetA(dh,  choice);  84            if  (SendPGA(socket,  ipAddress,  udpPort,  dh))  85            {  86                    printf("Data  sent!\n\nWaiting  for  B...\n\n");  87                    if  (ReceiveBandComputeK(socket,  dh))  88                    {  89                            gmp_printf("\n\nThe  encryption  key  is:\n\n\tK=B^a  (mod  

p)=%Zd\n\n",  dh-­‐>K);  90                            return  true;  91                    }  92            }  93            printf("\nUnable  to  create  the  key.\n");  94            return  false;  95    }  96  97    void  FindGenerator(mpz_t  p,  mpz_t  g)  98    {  99            char  *pStr;  100          int  size,  temp,  i;  101          bool  sameSize;  102          mpz_set(g,  p);  

Page 79: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

67  

103          mpz_sub_ui(g,  g,  2);  104          pStr  =  mpz_get_str(NULL,  10,  p);  105          do  106          {  107                  srand(rdtsc());  108                  size  =  (rand()  %  ((int)  strlen(pStr)  -­‐  1))  +  1;  109                  sameSize  =  (size  ==  (int)  strlen(pStr));  110                  for  (i  =  0;  i  <  size;  i++)  111                  {  112                          srand(rdtsc());  113                          if  (sameSize)  114                          {  115                                  temp  =  pStr[i]  -­‐  '0';  116                                  if  (temp  !=  0)  117                                          temp  =  rand()  %  temp;  118                          }  119                          else  120                                  temp  =  rand()  %  9;  121                          pStr[i]  =  ((char)  temp  +  '0');  122                  }  123                  pStr[size]  =  '\0';  124                  mpz_set_str(g,  pStr,  10);  125          }while  (mpz_cmp_ui(g,  2)  ==  0);  126          gmp_printf("\n\tg=%Zd\n",  g);  127  }  128  129  void  GeneratePrimeNumber(char*  name,  mpz_t  num,  unsigned  numBits)  130  {  131          bool  ctrl  =  false;  132          BIGNUM  primeNum;  133          BN_init(&primeNum);  134          do  135          {  136                  ctrl  =  BN_generate_prime_ex(&primeNum,  numBits,  1,  NULL,  NULL,  

NULL);  137          }while  (!ctrl);  138          mpz_set_str(num,  BN_bn2dec(&primeNum),  10);  139          BN_free(&primeNum);  140          gmp_printf("\n\t%s=%Zd\n",  name,  num);  141  }  142  143  void  GetPgaAndSetA(struct  dhStruct*  dh,  int  choice)  144  {  145          if  (choice  ==  1)  146          {  147                  printf("\n\nGenerating  'p'  and  'g'...\n\n");  148                  GeneratePrimeNumber("p",  dh-­‐>p,  1024);  149                  FindGenerator(dh-­‐>p,  dh-­‐>g);  150          }  151          else  if  (choice  ==  2)  152          {  153                  GetVariable("'p'",  dh-­‐>p);  154                  GetVariable("'g'",  dh-­‐>g);  155          }  156          GetVariable("'a',  such  that  1<a<p",  dh-­‐>a);  157          assert(mpz_cmp_ui(dh-­‐>a,  1)  >  0  &&  mpz_cmp(dh-­‐>p,  dh-­‐>a)  >  0);  158          mpz_powm(dh-­‐>A,  dh-­‐>g,  dh-­‐>a,  dh-­‐>p);  

Page 80: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

68  

159          gmp_printf("\n\tA=g^a  (mod  p)=%Zd\n",  dh-­‐>A);  160  }  161  162  bool  SendPGA(int  socket,  char*  ipAddress,  int  udpPort,  struct  

dhStruct*  dh)  163  {  164          char  *toSend[3];  165          int  count  =  0;  166          toSend[0]  =  mpz_get_str(NULL,  10,  dh-­‐>p);  167          toSend[1]  =  mpz_get_str(NULL,  10,  dh-­‐>g);  168          toSend[2]  =  mpz_get_str(NULL,  10,  dh-­‐>A);  169          printf("\nSending  p,g  and  A...\n\n");  170          do  171          {  172                  if  (!udp_send(socket,  toSend[count],  ipAddress,  udpPort))  173                  {  174                          printf("Unable  to  send  p,  g  and  A...\n\n");  175                          return  false;  176                  }  177                  count++;  178                  sleep(1);  179          }while  (count  <  3);  180          return  true;  181  }  182  183  bool  ReceiveBandComputeK(int  socket,  struct  dhStruct*  dh)  184  {  185          char  strB[BUFSIZ+1];  186          if  (udp_receive(socket,  strB)  ==  -­‐1)  187          {  188                  printf("Unable  to  receive  B!\n\n");  189                  return  false;  190          }  191          printf("B  received!\n\n\tB=%s\n\n",  strB);  192          mpz_set_str(dh-­‐>B,  strB,  10);  193          if  (mpz_cmp_ui(dh-­‐>B,  0)  >  0)  194          {  195                  mpz_powm(dh-­‐>K,  dh-­‐>B,  dh-­‐>a,  dh-­‐>p);  196                  return  true;  197          }  198          else  199                  return  false;  200  }  201  202  void  error_handler(char  *message)  203  {  204          printf("fatal  error:  %s\n",  message);  205          return;  206  }  207  208  char*  DhEncrypt(char*  toEncryptStr,  char*  key)  209  {  210          char  ch[4];  211          char  *aux  =  malloc((strlen(toEncryptStr)  *  3  +  2)*sizeof(char));  212          int  i;  213          aux[0]  =  '\0';  214          for  (i  =  0;  i  <  strlen  (toEncryptStr);  i++)  

Page 81: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

69  

215          {  216                  sprintf(ch,"%.3d",  (unsigned  char)toEncryptStr[i]^(unsigned  

char)key[i]);  217                  strcat(aux,  ch);  218          }  219          return  aux;  220  }  221  222  char*  DhDecrypt  (char*  toDecrypt,  char*  key)  223  {  224          int  i,  aux  =  0,  count=  0;  225          char  ch[4];  226          char  *decrypted  =  malloc  ((strlen(key)  +  2)*sizeof(char));  227          for  (i  =  0;  i  <  strlen(toDecrypt);  i++)  228          {  229                  ch[aux]  =  toDecrypt[i];  230                  aux++;  231                  if  (aux  ==  3)  232                  {  233                          ch[aux]='\0';  234                          decrypted[count]  =  (unsigned  char)  atoi(ch)^key[count];  235                          aux  =  0,  count++;  236                  }  237          }  238          decrypted[count]  =  '\0';  239          return  decrypted;  240  }  241  242  void  GetVariable(char*  varName,  mpz_t  var)  243  {  244          do  245          {  246                  printf("\nEnter  %s:  ",  varName);  247                  gmp_scanf("%Zd",  var);  248                  if  (mpz_cmp_ui(var,  0)  <=  0)  249                          printf("\nError.  Please  insert  a  number  >  0\n");  250          }while  (var  <=  0);  251  }  252  253  int  rdtsc()  254  {  255          __asm__  __volatile__("rdtsc");  256  }   DhDataLib.h 1      #ifndef  DHDATALIB_HPP  2      #define  DHDATALIB_HPP  3  4      #include  "DhLib.h"  5  6      bool  ReadAndSendData(char*  key,  int  socket);  7      bool  ReceiveAndDecryptData(char  *key,  int  socket);  8      void  SendData(char*  data,  char*  key,  int  socket);  9      char*  ResizeDinamicString(char*  toResize,  int  newDim);  10    char*  ReadMessage();  

Page 82: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

70  

11    char*  ReadFromFile();  12    void  printStrInDec(char*  toPrint);  13    void  printStrInHex(char*  toPrint,  bool  crypted);  14    #endif   DhDataLib.c 1      #include  "DhDataLib.h"  2  3      bool  ReadAndSendData(char*  key,  int  socket)  4      {  5              char*  message;  6              int  choice;  7              printf("\n\nWhat  do  you  want  to  do?\n\n");  8              printf("1)Send  a  message\n");  9              printf("2)Send  data  from  file\n");  10            printf("3)Exit\n");  11            do  12            {  13                    printf("Choose  an  option:");  14                    scanf("%d",  &choice);  15                    switch  (choice)  16                    {  17                            case  1:  18                            {  19                                    message  =  ReadMessage();  20                                    SendData(message,  key,  socket);  21                                    free(message);  22                                    message  =  NULL;  23                                    break;  24                            }  25                            case  2:  26                            {  27                                    message  =  ReadFromFile();  28                                    SendData(message,  key,  socket);  29                                    free(message);  30                                    message  =  NULL;  31                                    break;  32                            }  33                            case  3:  34                                    SendData("EOTS~EOTS~EOTS",  key,  socket);  35                                    break;  36                            default:  37                                    printf("\nInvalid  choice!\n\n");  38                    }  39            }while  (choice  !=  1  &&  choice  !=  2  &&  choice  !=  3);  40            return  choice  ==  3;  41    }  42  43    bool  ReceiveAndDecryptData(char  *key,  int  socket)  44    {  45            bool  exitFunction  =  false,  exitProgram  =  false;  46            char  buffer[BUFSIZ  +  1],  *decrypted,  *messageDecript  =  NULL;  47            int  messLen  =  0;  48  49            printf("\n\n\nWaiting  for  data...\n\n");  

Page 83: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

71  

50            while  (!exitFunction)  51            {  52                    udp_receive(socket,  buffer);  53                    printf("\n\n\nEncrypted  data  received  (in  decimal):  ");  54                    printStrInDec(buffer);  55                    printStrInHex(buffer,  true);  56                    decrypted  =  DhDecrypt(buffer,  key);  57                    messageDecript  =  ResizeDinamicString(messageDecript,  messLen  +  

strlen(decrypted));  58                    printf("\n\nDecrypted  data  received:  %s\n",  decrypted);  59                    printStrInHex(decrypted,  false);  60                    strcat(messageDecript,  decrypted);  61                    messLen  =  strlen(messageDecript);  62  63                    if  (strstr(messageDecript,  "EOTS~EOTS~EOTS")  !=  NULL)  64                    {  65                            exitProgram  =  true;  66                            exitFunction  =  true;  67                    }  68                    else  if  (strstr(messageDecript,  "EOF~EOF~EOF")  !=  NULL)  69                    {  70                            messageDecript[strlen(messageDecript)  -­‐  11]  =  '\0';  71                            printf("\n\nDecripted  data:\n\n%s\n\n",  messageDecript);  72                            exitFunction  =  true;  73                    }  74                    if  (decrypted  !=  NULL)  75                            free(decrypted);  76                    decrypted  =  NULL;  77            }  78            if  (messageDecript  !=  NULL)  79                    free(messageDecript);  80            messageDecript  =  NULL;  81  82            return  exitProgram;  83    }  84  85    void  SendData(char*  data,  char*  key,  int  socket)  86    {  87            int  dataLen  =  strlen(data),  keyLen  =  strlen(key),  i,  counter  =  0;  88            char  encryptedStr[keyLen  +  1],  *encrypted;  89            for  (i  =  0;  i  <  dataLen;  i++)  90            {  91                    encryptedStr[counter]  =  data[i];  92                    counter++;  93                    if  (counter  ==  keyLen  ||  i  ==  dataLen  -­‐  1)  94                    {  95                            encryptedStr[counter]  =  '\0';  96                            printf("\n\n\nData  to  send:  %s\n",  encryptedStr);  97                            printStrInHex(encryptedStr,  false);  98                            encrypted  =  DhEncrypt(encryptedStr,  key);  99                            printf("\n\nEncrypted  data  to  send  (in  decimal):  ");  100                            printStrInDec(encrypted);  101                          printStrInHex(encrypted,  true);  102                          udp_reply(socket,  encrypted);  103                          encryptedStr[0]  =  '\0';  104                          counter  =  0;  105                          if  (encrypted  !=  NULL)  

Page 84: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

72  

106                                  free(encrypted);  107                          encrypted  =  NULL;  108                          sleep(1);  109                  }  110          }  111  }  112  113  char*  ResizeDinamicString(char*  toResize,  int  newDim)  114  {  115          char*resized  =  malloc((newDim  +  1)*sizeof(char));  116          if  (resized  ==  NULL)  117                  printf("\n\nFailed  to  realloc.\n\n");  118          resized[0]  =  '\0';  119          if  (toResize  !=  NULL)  120          {  121                  strcpy(resized,  toResize);  122                  free(toResize);  123                  toResize  =  NULL;  124          }  125          return  resized;  126  }  127  128  char*  ReadMessage()  129  {  130          char  *message  =  NULL;  131          char  buffer[(BUFSIZ  +  1)];  132          int  messLen  =  0;  133          printf("\nEnter  the  message  to  send:  ");  134          getchar();  135          do  136          {  137                  fgets(buffer,  BUFSIZ,  stdin);  138                  message  =  ResizeDinamicString(message,  messLen  +  

strlen(buffer));  139                  strcat(message,  buffer);  140                  messLen  =  strlen(message);  141          }while  (buffer[strlen(buffer)  -­‐  1]  !=  '\n');  142          message[messLen-­‐1]=  '\0';  143          message  =  ResizeDinamicString(message,  strlen(message)  +  11);  144          strcat(message,  "EOF~EOF~EOF");  145          return  message;  146  }  147  148  char*  ReadFromFile()  149  {  150          FILE*  source;  151          char  fileName[1024],  buffer[(BUFSIZ  +  1)];  152          char  *fileData  =  NULL;  153          int  dataLen  =  0;  154          do  155          {  156                  printf("\nInsert  file  name  with  extension:  ");  157                  scanf("%s",fileName);  158                  if  ((source  =  fopen(fileName,  "r"))  ==  NULL)  159                          printf("\nCannot  read  the  file...Try  again\n");  160          }while  (  source  ==  NULL  );    161  

Page 85: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

73  

162          while  (!feof(source))  163          {  164                  fgets(buffer,BUFSIZ,  source);  165                  fileData  =  ResizeDinamicString(fileData,  dataLen  +  

strlen(buffer));  166                  strcat(  fileData,  buffer  );  167                  dataLen  =  strlen(fileData);  168          }  169          fileData[strlen(fileData)]=  '\0';  170          fileData  =  ResizeDinamicString(fileData,  strlen(fileData)  +  11);  171          strcat(fileData,  "EOF~EOF~EOF");  172          fclose(source);  173          return  fileData;  174  }  175  176  void  printStrInDec(  char*  toPrint  )  177  {  178          int  i;  179          for  (i  =  0;  i  <  strlen(toPrint);  i++)  180          {  181                  printf("%c",  toPrint[i]);  182                  if  (((i  +  1)  %  3)  ==  0)  183                          printf("  ");  184          }  185          printf("\n");  186  }  187    188  void  printStrInHex(char*  toPrint,  bool  crypted)  189  {  190          int  i;  191          char  ch[4];  192          unsigned  k  =  0;  193          printf("\nIn  hex:  ");  194          for  (i  =  0;  i  <  strlen(toPrint);  i++)  195                  if  (crypted)  196                  {  197                          ch[k]  =  toPrint[i],  k++;  198                          if  (k  ==  3)  199                          {  200                                  ch[3]  =  '\0',  k  =0;  201                                  printf("%x  ",  atoi(ch));  202                          }  203                  }  204                  else  205                          printf("%x  ",  (unsigned  char)  toPrint[i]);  206          printf  (  "\n"  );  207  }   Dh_c.c 1      #include  "DhLib.h"  2      #include  "DhDataLib.h"  3  4      int  main(int  argc,  char  *argv[])  5      {  

Page 86: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

74  

6              struct  dhStruct  clnt;  7              int  sk,  udpPort;  8              char  serverIpAdrress[1024];  9              char  *key;  10            bool  done  =  false;  11            mpz_inits(clnt.p,  clnt.g,  clnt.a,  clnt.b,  clnt.A,  clnt.B,  clnt.K,  

NULL);  12  13            if  (argc  ==  1)  14            {  15                    printf("Server  ip  address:  ");  16                    scanf("%s",  serverIpAdrress);  17                    printf("Udp  port:");  18                    scanf("%d",  &udpPort);  19            }  20            else  if  (argc  ==  3)  21            {  22                    strcpy(serverIpAdrress,  argv[1]);  23                    udpPort  =  atoi(argv[2]);  24            }  25            else  26            {  27                    printf("Required  arguments:  server  ip  address,  udp  port\n");  28                    exit(1);  29            }  30  31            if  ((sk  =  create_udp_client())  <  0)  32            {  33                    printf("Cannot  open  client  socket\n");  34                    exit(1);  35            }  36  37            if  (!GenerateEncryptionKey_Client(sk,  serverIpAdrress  ,udpPort,  

&clnt))  38                    exit(1);  39            key  =  mpz_get_str(NULL,  10,  clnt.K);  40            do  41            {  42                    done  =  ReadAndSendData(key,  sk);  43                    if  (!done)  44                            done  =  ReceiveAndDecryptData(key,  sk);  45            }while  (!done);  46  47            printf("\n\nExit...\n\n");  48            close_udp_socket(sk);  49            mpz_clears(clnt.p,  clnt.g,  clnt.a,  clnt.b,  clnt.A,  clnt.B,  clnt.K,  

NULL);  50            return  EXIT_SUCCESS;  51  }   Dh_s.c 1      #include  "DhLib.h"  2      #include  "DhDataLib.h"  3  4      int  main(int  argc,  char  *argv[])  

Page 87: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

75  

5      {  6              struct  dhStruct  srv;  7              int  sk,  udpPort;  8              char  serverIpAdrress[1024];  9              char  *key;  10            bool  done  =  false;  11            mpz_inits(srv.p,  srv.g,  srv.b,  srv.B,  srv.K,  srv.A,  NULL);  12  13            if  (argc  ==  1)  14            {  15                    printf("Server  ip  address:  ");  16                    scanf("%s",  serverIpAdrress);  17                    printf("Udp  port:");  18                    scanf("%d",  &udpPort);  19            }  20            else  if  (argc  ==  3)  21            {  22                    strcpy(serverIpAdrress,  argv[1]);  23                    udpPort  =  atoi(argv[2]);  24            }  25            else  26            {  27                    printf("Required  arguments:  server  ip  address,  udp  port\n");  28                    exit(1);  29            }  30  31            if  ((sk  =  create_udp_server(serverIpAdrress,  udpPort))  <  0)  32            {  33                    printf("Cannot  open  server  socket\n");  34                    exit(1);  35            }  36  37            if  (!GenerateEncryptionKey_Server(sk,  &srv))  38                    exit(1);  39            key  =  mpz_get_str(NULL,  10,  srv.K);  40            do  41            {  42                    done  =  ReceiveAndDecryptData(key,  sk);  43                    if  (!done)  44                            done  =  ReadAndSendData(key,  sk);  45            }while  (!done);  46  47            printf("\n\nExit...\n\n");  48            close_udp_socket(sk);  49            mpz_clears(srv.p,  srv.g,  srv.b,  srv.B,  srv.K,  srv.A,  NULL);  50            return  EXIT_SUCCESS;  51  }   RsaLib.h 1      #ifndef  RSALIB_H  2      #define  RSALIB_H  3  4      #include  <stdio.h>  5      #include  <stdlib.h>  6      #include  <gmp.h>  

Page 88: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

76  

7      #include  <string.h>  8      #include  <openssl/bn.h>  9      #include  <unistd.h>  10    #include  "udpsocketlib.h"  11    #include  <assert.h>  12    //  Create  type  bool  (not  present  in  c).  13    typedef  enum  {  false,  true  }  bool;  14  15    struct  keysRsa  16    {  17            mpz_t  p,  q,  phi;  18            mpz_t  n,  e,  d;  //keys  19    };  20  21    struct  publicKeyRsa  22    {  23            mpz_t  e,  n;  24    };  25  26    bool  ReceivePublicKey(struct  publicKeyRsa*  pbk,  int  socket);  27    char*  RsaEncrypt(char*  toEncryptStr,  struct  publicKeyRsa*  pbk);  28    char*  RsaDecrypt(char*  toDecrypt,  struct  keysRsa*  key);  29    void  GenerateEncryptionKeys(struct  keysRsa*  keys);  30    void  GeneratePrimeNumber(char*  name,  mpz_t  num,  int  numBits);  31    void  GeneratePQandComputeNPhi(struct  keysRsa*  var);  32    void  GetRandomE(struct  keysRsa*  var);  33    void  FindE(struct  keysRsa*  var);  34    void  ComputeGCD(mpz_t  r,  mpz_t  e,  mpz_t  phi);  35    void  ComputeD(struct  keysRsa*  var);  36    bool  SendPublicKey(int  socket,  char*  ipAddress,  int  udpPort,  struct  

keysRsa*  pubK);  37    int  rdtsc();  38  39    #endif   RsaLib.c 1      #include  "RsaLib.h"  2  3      bool  ReceivePublicKey(struct  publicKeyRsa*  pbk,  int  socket)  4      {  5              char  public_key[2][BUFSIZ  +  1];  6              unsigned  count  =  0;  7              printf("\n\nWaiting  for  public  key...\n\n");  8              do  9              {  10                    if  (udp_receive(socket,  public_key[count])  ==  -­‐1)  11                    {  12                            printf("Unable  to  receive  the  public  key...\n\n");  13                            return  false;  14                    }  15                    count++;  16            }while  (count  <  2);  17            mpz_set_str(pbk-­‐>e,  public_key[0],  10);  18            mpz_set_str(pbk-­‐>n,  public_key[1],  10);  19            if  (mpz_cmp_ui(pbk-­‐>n,  0)  <=  0  ||  mpz_cmp_ui(pbk-­‐>e,  0)  <=  0)  

Page 89: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

77  

20            {  21                    printf("Error.  Wrong  public  key.\n\n");  22                    return  false;  23            }  24            printf("The  public  key(e,n)  is:\n\n");  25            gmp_printf("\te=%Zd\n\n\tn=%Zd\n\n",  pbk-­‐>e,  pbk-­‐>n);  26            return  true;  27    }  28      29  30    void  GenerateEncryptionKeys(struct  keysRsa*  keys)  31    {  32            GeneratePQandComputeNPhi(keys);  33            FindE(keys);  34            ComputeD(keys);  35            gmp_printf("\nThe  private  key  is(d,n):\n\n\td=%Zd\n\n\tn=%Zd\n",  

keys-­‐>d,  keys-­‐>n);  36            gmp_printf("\n\nThe  public  key  is(e,n):\n\n\te=%Zd\n\n\tn=%Zd\n",  

keys-­‐>e,  keys-­‐>n);  37    }  38  39    void  GeneratePrimeNumber(char*  name,  mpz_t  num,  int  numBits)  40    {  41            bool  ctrl  =  false;  42            BIGNUM  primeNum;  43            BN_init(&primeNum);  44            do  45            {  46                    ctrl  =  BN_generate_prime_ex(&primeNum,  numBits,  1,  NULL,  NULL,  

NULL);  47            }while  (!ctrl);  48            mpz_set_str(num,  BN_bn2dec(&primeNum),  10);  49            BN_free(&primeNum);  50            gmp_printf("\t%s=%Zd\n\n",  name,  num);  51    }  52  53    void  GeneratePQandComputeNPhi(struct  keysRsa*  var)  54    {  55            mpz_t  aux,  temp;  56            mpz_inits(aux,  temp,  NULL);  57            printf("\n\nGenerating  prime  numbers  'p'  and  'q'...\n\n");  58            GeneratePrimeNumber("p",  var-­‐>p,  512);  59            GeneratePrimeNumber("q",  var-­‐>q,  512);  60            printf("\n\nComputing  'n'  and  'phi'...\n\n");  61            mpz_mul(var-­‐>n,  var-­‐>p,  var-­‐>q);  62            mpz_sub_ui(aux,  var-­‐>p,  1);  63            mpz_sub_ui(temp,  var-­‐>q,  1);  64            mpz_mul(var-­‐>phi,  aux,  temp);  65            gmp_printf("\tn=p*q=%Zd\n\n\tphi=(p-­‐1)*(q-­‐1)=%Zd\n\n",  var-­‐>n,  

var-­‐>phi);  66            mpz_clears(aux,  temp,  NULL);  67    }  68  69    void  GetRandomE(struct  keysRsa*  var)  70    {  71            mpz_t  aux;  72            char  str[mpz_sizeinbase(var-­‐>phi,  10)];  

Page 90: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

78  

73            int  max,  min,  temp,  size,  i;  74            mpz_init(aux);  75            mpz_set(aux,  var-­‐>phi);  76            mpz_sub_ui(aux,  aux,  1);  77            max  =  mpz_sizeinbase(aux,  10);  78            if  (  mpz_cmp(var-­‐>p,  var-­‐>q)  >=  0)  79                    min  =  mpz_sizeinbase(var-­‐>p,  10)  +  1;  80            else  81                    min  =  mpz_sizeinbase(var-­‐>q,  10)  +  1;  82            do  83            {  84                    srand(rdtsc());  85                    size  =  (rand()  %  (max  -­‐    min))  +  min;  86                    for  (i  =  0;  i  <  size;  i++)  87                    {  88                            srand(rdtsc());  89                            temp  =  rand()  %  9;  90                            str[i]  =  (char)temp  +  '0';  91                    }  92                    str[i]  =  '\0';  93                    mpz_set_str(var-­‐>e,  str,  10);  94            }while  (mpz_cmp(var-­‐>e,  aux)  >=  0);  95            mpz_clears(aux,  NULL);  96    }  97  98    void  FindE(struct  keysRsa*  var)  99    {  100            bool  eFound  =  false;  101            mpz_t  t,  random;  102            mpz_inits(t,  random,  NULL);  103          do  104          {  105                  GetRandomE(var);  106                  while  (mpz_cmp_ui(t,  1)  !=  0  &&  mpz_cmp(var-­‐>e,  var-­‐>p)  >  0  &&  

mpz_cmp(var-­‐>e,  var-­‐>q)  >  0)  107                  {  108                          ComputeGCD(t,  var-­‐>e,  var-­‐>phi);  109                          if  (mpz_cmp_ui(t,  1)  ==  0)  110                                  eFound  =  true;  111                          else  112                                  mpz_sub_ui(var-­‐>e,  var-­‐>e,  1);  113                  }  114          }while  (!eFound);  115          gmp_printf("\n\n\t'e'  such  that  GCD(e,phi)=1  is:%Zd\n\n",  var-­‐>e);  116          mpz_clears(t,  random,  NULL);  117  }  118  119  void  ComputeGCD(mpz_t  r,  mpz_t  e,  mpz_t  phi)  120  {  121          mpz_t  m,  n;  122          mpz_inits(m,  n,  NULL);  123          mpz_set(m,  e);  124          mpz_set(n,  phi);  125          if  (mpz_cmp(m,  n)  >  0)  126                  mpz_set(r,  n);  127          else  128          {  

Page 91: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

79  

129                  mpz_set(r,  m);  130                  mpz_set(m,  n);  131                  mpz_set(n,  r);  132          }  133          while  (mpz_cmp_ui(r,  0)  !=  0)  134          {  135                  mpz_fdiv_r(r,  m,  n);  136                  mpz_set(m,  n);  137                  mpz_set(n,  r);  138          }  139          mpz_set(r,  m);  140          mpz_clears(m,  n,  NULL);  141  }  142  143  void  ComputeD(struct  keysRsa*  var)  144  {  145          mpz_t  t,  nt,  r,  nr,  q,  tmp,  a,  b;  146          mpz_inits(t,  nt,  r,  nr,  q,  tmp,  a,  b,  NULL);  147          mpz_set(a,  var-­‐>e);  148          mpz_set(b,  var-­‐>phi);  149          if  (mpz_cmp_ui(b,  0)  <  0)  150                  mpz_ui_sub(b,  0,  b);  151          if  (mpz_cmp_ui(a,  0)  <  0)  152          {  153                  mpz_ui_sub(a,  0,  a);  154                  mpz_fdiv_r(a,  a,  b);  155                  mpz_sub(a,  b,  a);  156          }  157          mpz_set_ui(t,  0);  158          mpz_set_ui(nt,  1);  159          mpz_set(r,  b);  160          mpz_fdiv_r(nr,  a,  b);  161          while  (mpz_cmp_ui(nr  ,  0)  !=  0)  162          {  163                  mpz_fdiv_q(q,  r,  nr);  164                  mpz_set(tmp,  nt);  165                  mpz_mul(nt,  q,  nt);  166                  mpz_sub(nt,  t,  nt);  167                  mpz_set(t,  tmp);  168                  mpz_set(tmp,  nr);  169                  mpz_mul(nr,  q,  nr);  170                  mpz_sub(nr,  r,  nr);  171                  mpz_set(r,  tmp);  172          }  173          assert(mpz_cmp_ui(r  ,  1)  <=  0);  /*  No  inverse  */  174          if  (mpz_cmp_ui(t  ,  0)  <  0)  175                  mpz_add(t,  t,  b);  176          mpz_set(var-­‐>d,  t);  177          mpz_clears(t,  nt,  r,  nr,  q,  tmp,  a,  b,  NULL);  178          gmp_printf("  \t'd'  such  that  (e*d=  1  mod  phi)  is:%Zd\n\n  ",  var-­‐

>d);  179  }  180  181  bool  SendPublicKey(int  socket,  char*  ipAddress,  int  udpPort  ,  struct  

keysRsa*  pubK)  182  {  183          int  count  =  0;  

Page 92: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

80  

184          char  *public_key[2];  185          public_key[0]  =  mpz_get_str(NULL,  10,  pubK-­‐>e);  186          public_key[1]  =  mpz_get_str(NULL,  10,  pubK-­‐>n);  187          printf("\nSharing  the  public  key...Sending  'e'  and  'n'...\n\n");  188          do  189          {  190                  if  (!udp_send(socket,  public_key[count],  ipAddress,  udpPort))  191                  {  192                          printf("Unable  to  send  the  public  key...\n\n");  193                          return  false;  194                  }  195                  sleep(1);  196                  count++;  197          }while  (count  <  2);  198          printf("Data  sent!\n\nWaiting...\n\n");  199          return  true;  200  }  201  202  char*  RsaEncrypt(char*  toEncryptStr,  struct  publicKeyRsa*  pbk)  203  {  204          mpz_t  encrypted;  205          char  *encryptedStr;  206          mpz_init(encrypted);  207          mpz_set_str(encrypted,  toEncryptStr,  10);  208          mpz_powm(encrypted,  encrypted,  pbk-­‐>e,  pbk-­‐>n);  209          encryptedStr  =  malloc((mpz_sizeinbase(encrypted,  10)  +  

1)*sizeof(char));  210          encryptedStr  =  mpz_get_str(NULL,  10,  encrypted);  211          mpz_clear(encrypted);  212          return  encryptedStr;  213  }  214  215  char*  RsaDecrypt(char*  toDecrypt,  struct  keysRsa*  key)  216  {  217          mpz_t  decrypted;  218          char  *decryptedStr;  219          mpz_init(decrypted);  220          mpz_set_str(decrypted,  toDecrypt,  10);  221          mpz_powm(decrypted,  decrypted,  key-­‐>d,  key-­‐>n);  222          decryptedStr  =  mpz_get_str(NULL,  10,  decrypted);  223          mpz_clear(decrypted);  224          return  decryptedStr;  225  }  226  227  int  rdtsc()  228  {  229          __asm__  __volatile__("rdtsc");  230  }  231  232  void  error_handler(char  *message)  233  {  234          printf("fatal  error:  %s\n",  message);  235          return;  236  }  

Page 93: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

81  

RsaDataLib.h 1      #ifndef  RSADATALIB_HPP  2      #define  RSADATALIB_HPP  3  4      #include  "RsaLib.h"  5  6      void  ReceiveAndDecryptData(struct  keysRsa*  privateKey,  int  socket);  7      char*  ReadFromFile();  8      char*  ReadMessage();  9      void  SendData(char*  data,  struct  publicKeyRsa*  pbk,  int  socket);  10    bool  ReadAndSendData(struct  publicKeyRsa*  rk,  int  socket);  11    char*  ResizeDinamicString(char*  toResize,  int  newDim);  12    void  RebuildData(char*  decryptedStr);  13    #endif   RsaDataLib.c 1      #include  "RsaDataLib.h"  2  3      void  ReceiveAndDecryptData(struct  keysRsa*  privateKey,  int  socket)  4      {  5              bool  exit  =  false;  6              int  messLen  =  0;  7              char  buffer[BUFSIZ  +  1];  8              char  *messageDecript  =  NULL,  *decrypted;  9              while  (!exit)  10            {  11                    udp_receive(socket,  buffer);  12                    printf("\nEncrypted  data  received(in  decimal):\n%s\n\n",  

buffer);  13                    decrypted  =  RsaDecrypt(buffer,  privateKey);  14                    RebuildData(decrypted);  15                    printf("Received  data  decrypted:\n%s\n\n",  decrypted);  16                    messageDecript  =  ResizeDinamicString(messageDecript,  messLen  +  

strlen(decrypted));  17                    strcat(messageDecript,  decrypted);  18                    messLen  =  strlen(messageDecript);  19                    if  (strstr(messageDecript,  "EOTS~EOTS~EOTS")  !=  NULL)  20                    {  21                            printf("\n\nExit...\n\n");  22                            exit  =  true;  23                    }  24                    else  if  (strstr(messageDecript,  "EOF~EOF~EOF")  !=  NULL)  25                    {  26                            messageDecript[strlen(messageDecript)  -­‐  11]  =  '\0';  27                            printf("\n\nDecripted  data:\n\n%s\n\n",  messageDecript);  28                            messageDecript[0]  =  '\0';  29                            printf("\nWaiting  for  new  data...\n\n");  30                    }  31                    if  (decrypted  !=  NULL)  32                            free(decrypted);  33                    decrypted  =  NULL;  34            }  35            if  (messageDecript  !=  NULL)  

Page 94: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

82  

36                    free(messageDecript);  37            messageDecript  =  NULL;  38    }  39  40    void  RebuildData(char*  decryptedStr)  41    {  42            char  ch[4],  *toReturn;  43            int  r,  len,  i  =  0,  j  =  0,  k;  44            len  =  strlen(decryptedStr);  45            r  =  len  %  3;  46            if  (r  !=0)  47            {  48                    i  =  3  -­‐  r;  49                    for  (k  =  0;  k    <  i;  k  ++)  50                            ch[k]  =  '0';  51            }  52            printf("Received  data  decrypted(in  decimal):\n%s\n\n",  

decryptedStr);  53            len  =  strlen(decryptedStr);  54            toReturn  =  malloc(len*sizeof(char));  55            k  =  0;  56            while  (k  <  len)  57            {  58                    ch[i]  =  decryptedStr[k];  59                    k++,  i++;  60                    if  (i  ==  3  ||  k  ==  len)  61                    {  62                            ch[3]  =  '\0';  63                            char  c  =  (char)(atoi(ch));  64                            toReturn[j]  =  c;  65                            j++,  i  =  0;  66                    }  67            }  68            toReturn[j]  =  '\0';  69            strcpy(decryptedStr,  toReturn);  70    }  71  72    bool  ReadAndSendData(struct  publicKeyRsa*  rk,  int  socket)  73    {  74            char*  message;  75            int  choice;  76            printf("\n\nWhat  do  you  want  to  do?\n\n");  77            printf("1)Send  a  message\n");  78            printf("2)Send  data  from  file\n");  79            printf("3)Exit\n");  80            do  81            {  82                    printf("Choose  an  option:");  83                    scanf("%d",  &choice);  84                    switch  (choice)  85                    {  86                            case  1:  87                            {  88                                    message  =  ReadMessage();  89                                    SendData(message,  rk,  socket);  90                                    free(message);  91                                    message  =  NULL;  

Page 95: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

83  

92                                    break;  93                            }  94                            case  2:  95                            {  96                                    message  =  ReadFromFile();  97                                    SendData(message,  rk,  socket);  98                                    free(message);  99                                    message  =  NULL;  100                                  break;  101                          }  102                          case  3:  103                                  SendData("EOTS~EOTS~EOTS",  rk,  socket);  104                                  break;  105                          default:  106                                  printf("\nInvalid  choice!\n\n");  107                  }  108          }while  (choice  !=  1  &&  choice  !=  2  &&  choice  !=  3);  109          return  choice  ==  3;  110  }  111  112  char*  ReadMessage()  113  {  114          char  *message  =  NULL;  115          char  buffer[BUFSIZ  +  1];  116          int  messLen  =  0;  117          printf("\nEnter  the  message  to  send:  ");  118          getchar();  119          do  120          {  121                  fgets(buffer,  BUFSIZ,  stdin);  122                  message  =  ResizeDinamicString(message,  messLen  +  

strlen(buffer));  123                  strcat(message,  buffer);  124                  messLen  =  strlen(message);  125          }while  (buffer[strlen(buffer)  -­‐  1]  !=  '\n');  126          message[messLen  -­‐  1]=  '\0';  127          message  =  ResizeDinamicString(message,  strlen(message)  +  11);  128          strcat(message,  "EOF~EOF~EOF");  129          return  message;  130  }  131  132  char*  ReadFromFile()  133  {  134          FILE*  source;  135          char  fileName[1024],  buffer[BUFSIZ  +  1];  136          char  *fileData  =  NULL;  137          int  dataLen  =  0;  138          do  139          {  140                  printf("\nInsert  file  name  with  extension:  ");  141                  scanf("%s",  fileName);  142                  if  ((source  =  fopen(fileName,  "r"))  ==  NULL)  143                          printf("\nCannot  read  the  file...Try  again\n");  144          }while  (source  ==  NULL);  145  146          while  (!feof(source))  147          {  

Page 96: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

84  

148                  fgets(buffer,  BUFSIZ,  source);  149                  fileData  =  ResizeDinamicString(fileData,  dataLen  +  

strlen(buffer));  150                  strcat(fileData,  buffer);  151                  dataLen  =  strlen(fileData);  152          }  153          fileData[strlen(fileData)]=  '\0';  154          fileData  =  ResizeDinamicString(fileData,  strlen(fileData)  +  11);  155          strcat(fileData,  "EOF~EOF~EOF");  156          fclose(source);  157          return  fileData;  158  }  159  160  void  SendData(char*  data,  struct  publicKeyRsa*  pbk,  int  socket)  161  {  162          int  i  =  0,  ii  =  0;  163          int  nSize  =  mpz_sizeinbase(pbk-­‐>n,  10);  164          char  toEncrypt[(nSize  *  4)  +  1  ],  *encryptedStr;  165          char  toSend[nSize  +  1];  166          mpz_t  encrypted;  167          char  ch[4];  168          mpz_init(encrypted);  169          toEncrypt[0]  =  '\0';  170          while  (i  <=  strlen(data))  171          {  172                  sprintf(ch,  "%.3d",  (unsigned  char)data[i]);  173                  strcat(toEncrypt,  ch);  174                  mpz_set_str(encrypted,  toEncrypt,  10);  175                  toSend[ii]  =  data[i];  176                  if  (mpz_cmp(encrypted,  pbk-­‐>n)  >=  0  ||  i  ==  strlen(data))  177                  {  178                          toSend[ii]  =  '\0';  179                          printf("\n\nData  to  send:\n%s",  toSend);  180                          toEncrypt[strlen(toEncrypt)  -­‐  3]  =  '\0';  181                          printf("\n\nData  to  send(in  decimal):\n%s\n\n",  

toEncrypt);  182                          encryptedStr  =  RsaEncrypt(toEncrypt,  pbk);  183                          printf("Encrypted  data  to  send(in  decimal):\n%s\n\n",  

encryptedStr);  184                          udp_reply(socket,  encryptedStr);  185                          ii=0;  186                          toSend[ii]  =  data[i];  187                          strcpy(toEncrypt,  ch);  188                          if  (encryptedStr  !=  NULL)  189                                  free(encryptedStr);  190                          encryptedStr  =  NULL;  191                          sleep(1);  192                  }  193                  ii++;  194                  i++;  195          }  196          mpz_clear(encrypted);  197  }  198  199  char*  ResizeDinamicString(char*  toResize,  int  newDim)  200  {  201          char*resized  =  malloc((newDim  +  1)*sizeof(char));  

Page 97: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

85  

202          if  (resized  ==  NULL)  203                  printf("\n\nFailed  to  realloc.\n\n");  204          resized[0]  =  '\0';  205          if  (toResize  !=  NULL)  206          {  207                  strcpy(resized,  toResize);  208                  free(toResize);  209                  toResize  =  NULL;  210          }  211          return  resized;  212  }   Rsa_s.c 1      #include  "RsaLib.h"  2      #include  "RsaDataLib.h"  3  4      int  main(int  argc,  char  *argv[])  5      {  6              struct  publicKeyRsa  srv;  7              int  sk,  udpPort;  8              bool  done;  9              char  serverIpAdrress[1024];  10            mpz_inits(srv.e,  srv.n,  NULL);  11            if  (argc  ==  1)  12            {  13                    printf("Server  ip  address:  ");  14                    scanf("%s",  serverIpAdrress);  15                    printf("Udp  port:");  16                    scanf("%d",  &udpPort);  17            }  18            else  if  (argc  ==  3)  19            {  20                    strcpy(serverIpAdrress,  argv[1]);  21                    udpPort  =  atoi(argv[2]);  22            }  23            else  24            {  25                    printf("Required  arguments:  server  ip  address,  udp  port\n");  26                    exit(1);  27            }  28            if  ((sk  =  create_udp_server(serverIpAdrress,  udpPort))  <  0)  29            {  30                    printf("Cannot  open  server  socket\n");  31                    exit(1);  32            }  33            if  (!ReceivePublicKey(&srv,sk))  34                    exit(1);  35            do  36            {  37                    done  =  ReadAndSendData(&srv,  sk);  38            }while  (!done);  39            printf("\n\nExit...\n\n");  40            close_udp_socket(sk);  41            mpz_clears(srv.e,  srv.n,  NULL);  42            return  EXIT_SUCCESS;  

Page 98: UNIVERSITÀ DEGLI STUDI DI UDINE - web.diegm.uniud.itweb.diegm.uniud.it/pierluca/public_html/teaching/reti_di... · informatica. Oggi, infatti, milioni di persone usano la rete per

86  

43    }   Rsa_c.c 1      #include  "RsaLib.h"  2      #include  "RsaDataLib.h"  3  4      int  main(int  argc,  char  *argv[])  5      {  6              struct  keysRsa  clnt;  7              int  sk;  8              int  udpPort;  9              char  serverIpAdrress[1024];  10            mpz_inits(clnt.p,  clnt.q,  clnt.n,  clnt.phi,  clnt.e,  clnt.d,  NULL);  11            if  (argc  ==  1)  12            {  13                    printf("Server  ip  address:  ");  14                    scanf("%s",  serverIpAdrress);  15                    printf("Udp  port:");  16                    scanf("%d",  &udpPort);  17            }  18            else  if  (argc  ==  3)  19            {  20                    strcpy(serverIpAdrress,argv[1]);  21                    udpPort  =  atoi(argv[2]);  22            }  23            else  24            {  25                    printf("Required  arguments:  server  ip  address,  udp  port\n");  26                    exit(1);  27            }  28            if  ((sk  =  create_udp_client())  <  0)  29            {  30                    printf("Cannot  open  client  socket\n");  31                    exit(1);  32            }  33            GenerateEncryptionKeys(&clnt);  34            if  (!SendPublicKey(sk,  serverIpAdrress,  udpPort,  &clnt))  35                    exit(1);  36            ReceiveAndDecryptData(&clnt,  sk);  37            close_udp_socket(sk);  38            mpz_clears(clnt.p,  clnt.q,  clnt.n,  clnt.phi,  clnt.e,  clnt.d,  

NULL);  39            return  EXIT_SUCCESS;  40    }