• Non ci sono risultati.

Confronto con la versione in C

Nel documento UNIVERSITÀ DEGLI STUDI DI UDINE (pagine 36-39)

2 Algoritmo Diffie-Hellman 2.1 Descrizione

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.

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++.

È 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.

3 Algoritmo RSA

Nel documento UNIVERSITÀ DEGLI STUDI DI UDINE (pagine 36-39)

Documenti correlati