Privacy Policy Cookie Policy
You are here
Home > Programmazione > C/C++ > Cifratura Xor in C – Parte 1

Cifratura Xor in C – Parte 1

Introduzione

Salve ragazzi! e benvenuti in questo articolo nel quale dopo una breve introduzione sullo Xor, introdurrò acune applicazioni per le quali è utilizzato e in più utilizzeremo questo strumento per implementare un metodo di cifratura abbastanza primitivo in C, buon divertimento!.

Per cifratura si intede il processo di trasformare il testo in qualcosa che non abbia significato per chi non è autorizzato a ricevere quella informazione. In genere le trasformazioni sono delle ‘rotazioni’ (ad esempio sostituire una ‘lettera’ di un alfabeto con un’altra dello stesso alfabeto) in base a un singolo valore, detto chiave, che verrà utilizzato anche per rendere di nuovo chiaro il testo.
Quello che implementeremo noi è proprio questo meccanismo!, come?, lo vedremo in questo articolo. Ma partiamo dall’inizio!…

Operatore XOR

Conoscevate lo Xor?, una funzione logica molto importante in quanto utilizzata in moltissime applicazioni: dall’networking, all’informatica, all’elettronica.
Lo Xor non è altro che un or esclusivo, ovvero una operazione matematica che dati in ingresso due bit resituisce 1 se e solo se i due bit in ingresso sono diversi tra loro.

Potete immaginare lo Xor come una ‘scatola nera’ che, se riceve in ingresso 0 e 1, mi restituisce in uscita 1; se riceve 1 e 1 o 0 e 0, mi restituisce 0.

Per fare un confronto con la logica tradizionale, lo xor tra due affermazioni, è quella relazione vera se e solo se una sola delle due frasi è vera.
Vediamo, dati in ingresso due bit, di cercare di capire come funziona lo Xor (o anche detto Or esclusivo)

Quella che ho disegnato sopra è la tabella di verità dello Xor, ovvero una tabella che mi dice, in funzione dei bit di ingresso X1 e Y1, quale sarà il risultato dell Xor. Come potete vedere, se i due bit sono uguali allora lo Xor restituisce 0 altrimenti 1.

Funzionamento

Il principio di cifratura da noi implementato, sfrutta una proprietà dello Xor ed è semplice.
Si applica sui bit dei caratteri che ricordandoai che ogni carattere viene rappresentato, all’interno della macchina, in codice ASCII cioè una serie di 8 bit, ognuno dei quali può essere 0 o 1.
Si fa uno Xor bit a bit di due caratteri (Si fa lo Xor tra i bit dei due caratteri presi uno a uno, ovvero prima si confronta il primo bit dei due caratteri in ingresso, poi il secondo e così via…) ottenendo in uscita alla nostra funzione, un’altro carattere. L’operazione di ripete per tutti i caratteri della stringa.
La propriètà che sfrutteremo è:  se si fa lo Xor tra due caratteri si ottiene un carattere univoco per ogni coppia!.

La cosa più interessante è un’altra proprietà: ottenuto il carattere tramite lo Xor tra altri due caratteri, se rieffettui lo Xor tra il carattere ottenuto e uno dei due utilizzati per cifrarlo ottieni l’altro!.

Facciamo un esempio che chiarirà il tutto tutto:

01011010, 00010101 questi sono i due caratteri in ingresso.
Quello che farà il nostro algoritmo e prendere il primo bit dei due caratteri: sono due zeri percui lo Xor restituirà 0 poi prendo il secondo bit dei due caratteri (1 e 0), lo Xor restituirà 1.
Ripetendo queste operazioni per tutti gli otto bit dei due caratteri la stringa che ottengo in uscita sarà: 01001111.

Perché proprio lo Xor?

semplice!.
Perché, come ho gia accennato, la proprietà dello Xor rende il processo di cifratura facilmente invertibile, infatti facendo nuovamente lo Xor tra il carattere ottenuto e uno dei caratteri in ingresso, riottengo l’altro carattere.

Realizziamo il nostro software

Anche in C i caratteri sono visti come insiemi di 8 bit (1 byte) per cui facendo lo Xor tra i e / , non faccio altro che dire al computer di eseguire lo Xor bit a bit, come mostrato precedentemente, ottenendo un’altro carattere.
Se rifaccio lo Xor tra il carattere ottenuto precedentemente e / riottengo la i.

In C lo Xor bit a bit lo si fa tramite l’operatore ‘^’.
Se quindi volessi fare lo Xor tra due caratteri dovrei semplicemente scrivere:

#include 

int main(){

	char password;
	char testo[8];
	char testo_cifrato[8];
	int i;
	
	// Chiedo di inserire un carattere in ingresso
	printf("Inserisci 8 un testo di otto caratteri\n");
	scanf("%8s",testo);
	printf("Inserisci una password di 1 carattere\n");
	scanf("%1s",password);
	
	// Stampo il testo da cifrare
	printf("Il testo da cifrare è: %s, la password è:%s \n", testo,password);

	// Esegui lo Xor tra tutti i caratteri del testo e della password
	for(i=0;testo[i]='\0';i++){
		testo_cifrato[i]=testo[i]^password;
	}

	printf("Il testo da cifrare, la password e il testo cifrato in esadecimale sono: \n");

	// Stampo il testo inserito in ingresso
	for(i=0;testo[i]!='\0';i++){
		printf("%c",testo[i]);
	}
	
	printf("\n");
	// Stampo la password
	printf("%c",password);

	printf("\n");
	// Stampo il testo cifrato in esadecimale (In esadecimale in quanto potrebbe 
        // contenere caratteri non stampabili!)
	for(i=0;testo_cifrato[i]!='\0';i++){
		printf("%x",testo_cifrato[i]);
	}
	printf("\n");
}

Naturalmente si capisce subito che questo programma ha ancora dei difetti e può servire solo come esempio.
Come fare se si vuole ottenere un algoritmo di crittografia Xor più complesso??.
Potremmo intanto volere utilizzare una password più lunga, cosiché possa essere più difficile trovare il testo originale, ma potremmo addirittura cercare di rendere la chiave indipendente dalla password inserita e dal testo cifrato in modo da rendere un poco più sicuro il processo.

Un esempio di come si potrebbe aggiungere più entropia al processo di cifratura è mostrato in seguito.

Un fattore di sicurezza potrebbe essere dato dal permettere all’utente di inserire una password e un testo più lunghi.
Possiamo permettergli di inserire testi di lunghezza variabile, ma impostando comunque un limite massimo per evitare buffer overflow!.
Per fare ciò dobbiamo usare la malloc(),  funzione dichiarata nella libreria standard che quindi va inclusa all’inizio del progetto.

#include <stdio.h>;
#include <stdlib.h>;

Il funzionamento è semplice. Chiediamo all’utente di quante cifre vuole che sia la password e dichiariamo un puntatore per dare il nome alla zona di memoria che ci serve (come attacare una etichetta grazie alla quale potere accedere e/o leggere il contenuto di una determinata zona di memoria).
Questo puntatore conterrà l’indirizzo del primo byte della zona di memoria allocata:

char *password; //Dichiaro un puntatore utilizzando l'operatore asterisco. 
int n;
printf("Di quanti caratteri deve essere la password?\n");
scanf("%d",&n); //Salvo la cifra inserita dall'utente in n
password=malloc(sizeof(char)*n); 
/* Alloco una zona di memoria delle dimensione di un char (sizeof() 
che restituisce la dimensione in byte di un tipo di dato ad esempio il char) 
per n che è il numero di caratteri che devo 
salvare e a questa zona di memoria do il nome di password (in verità non è proprio il nome della zona di memoria 
ma questo ci permetterà di capire 
il concetto base quindi per ora diciamo cosi! XD) */ 

Possibili miglioramenti

Questa soluzione non è molto elegante, specialmente se non si ha fiducia dell’utente, poiché esso potrebbe inserire un valore di caratteri molto grande e questo mandare tutto il crash poiché la memoria del PC non è infinita.

Per ragioni di sicurezza è quindi importante dare un valore massimo di dimensione alla password inseribile, il che si può fare, ad esempio, chiedendo di inserire una password di massimo n cifre, con n stabilita da noi oppure chiedendo di inserire di quante cifre deve essere la password e poi controllare che il valore inserito sia contenuto nell’intervallo di possibili scelte con un semplice if, comunque nelle prossime lezioni vedremo come migliorare anche questi aspetti.

Questi sono i due metodi più semplici e veloci quindi quelli che utilizzeremo nel nostro articolo.

Un’altra soluzione, che unisce i vantaggi delle due, potrebbe essere quella di utilizzare una variabile temporanea da disallocare successivamente e che può contenente al massimo n cifre, fargli inserire una password che deve contenere al massimo n cifre e una volta che l’utente inserisce la password contare le cifre inserire e allocare solo lo spazio richiesto (Ma come fai a capire la dimensione della stringa inserita o a limitare il numero di caratteri inseriti per non dovere generare un vettore infinito e causare buffer overflow? vedremo anche questo!).

Intanto vediamo inserita la password come funziona lo Xor!
La soluzione è molto semplice, si scorre uno a uno i caratteri del testo e della password e si fa lo Xor come prima ma vediamo come rendere tutto un po’ più sicuro.

Creazione della chiave

In C una stringa è un vettore percuì alla posizione di ogni carattere viene anche associato un valore intero positivo detto “indice”.
Possiamo utilizzare questo valore per fare lo Xor, non tra il testo e la password ma tra il testo e un carattere casuale preso in un’altra stringa, mi spiego meglio.

La chiave di crittografia non sarà il carattere della nostra password ma, tramite una funzione, associeremo ad ogni carattere della nostra password un altro carattere preso da una stringa da noi generata in questo modo.

char key(char carattere){
return "01NS23H5Q9acOd%ghijl;opq:sWtev8w=xzAB<CDE9FJKL#MPrRm6bTkU@^VXZn!£$&/(>uyé*ç°Y§_[f·}~`4IòàÈè^?{}"[(int)chiave-33];
}

Come funziona?? prendo il carattere, lo passo alla funzione, questa trasforma il valore del carattere in un intero e seleziona il carattere della stringa la cui posizione corrisponde a quell’intero.

Il problema è che la stringa contiene 96 caratteri percui per selezionare un carattere della stringa devo inserire un indice che va da 0 a 95 mentre i caratteri dati ad input alla funzione hanno valore numerico che va da 33 a 126, devo quindi sottrarre 33 così che l’indice nell’intervallo 0 – 93 (ne saltano 2 ma poco importa in questa prima versione).
Il return non fa altro che restituirmi il carattere della stringa corrispondente alla posizione inserita in ingresso.

Cosi, richiamando questa funzione, ogni volta, abbiamo un carattere collegato alla nostra password ma allo stesso tempo diverso da quello della password stessa.

Anticipazioni

Nella funzione Xor, che vedremo la prossima volta, ho aggiunto, per facilità di gestione del progetto, un controllo che verifica il carattere restituito prima di salvarlo nella stringa, se tale carattere non è un carattere scrivibile, ma un carattere di gestione del formato come spazio o carrage return, rieffettua lo Xor con un altro carattere della password.
Vedremo questo al prossimo appuntamento.

Saluti.

Simone Sante Ruffo
Diplomato al liceo scientifico, si è laureato in ingegneria informatica e delle telecomunicazioni e sta proseguendo ora gli studi in Ingegneria Elettronica per prendersi la laurea magistrale. Appassionato di informatica, telecomunicazioni ed elettronica gli piace studiare, conoscere, progettare e risolvere problemi
http://simonesanteruffo.it

Lascia un commento

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.

Top