Con hashing si intende il processo che genera un output di dimensione fissa partendo da un input di dimensione variabile. Questo viene fatto attraverso l’uso di formule matematiche conosciute come funzioni di hash.
Non tutte le funzioni hash implicano l’uso di crittografia; se lo fanno, tali funzioni, prendono il nome di funzioni crittografiche di hash.
Si può vedere l’hashing come un modo di fare il “riassunto informatico” di un documento digitale.
Le funzioni di hash sono deterministiche. Questa proprietà significa che fino a quando l’input non cambia, l’algoritmo di hashing continuerà a produrre lo stesso output (conosciuto anche come digest o hash).
In genere, gli algoritmi di hashing sono progettati come funzioni unidirezionali, ovvero che non possono essere facilmente invertite senza enormi quantità di risorse e tempo di computazione.
In altre parole, è piuttosto semplice creare l’output dall’input, ma relativamente difficile andare nella direzione opposta (generare l’input partendo dal solo output).
In linea di massima, più è difficile trovare l’input, più l’algoritmo di hashing è considerato sicuro.
Le funzioni di hash fanno complesse operazioni matematiche sulla stringa di input fino a renderla “irriconoscibile” e portarla ad avere una dimensione di output predefinita. Il miglior modo per concepire una funzione di hash è quello di vederla come una “macchinetta” che prende in ingresso una stringa di qualsiasi dimensione ene tira fuori un’altra di dimensione fissata.
Le funzioni di hash convenzionali hanno una vasta gamma di casi d’uso, tra cui ricerca in database, analisi di grandi file e gestione dei dati.
Invece, le funzioni crittografiche di hash vengono usate estensivamente nelle applicazioni per la sicurezza informatica, come l’autenticazione di messaggi, l’impronta digitale, la firma digitale e molte altre.
Il vero potere dell’hashing si vede quando si ha a che fare con enormi quantità di informazioni. Per esempio, possiamo elaborare un grande file o un dataset attraverso una funzione di hash e usare
il suo output per verificare velocemente l’accuratezza e l’integrità dei dati. Questo è possibile grazie alla natura deterministica delle funzioni di hash: l’input risulterà sempre in un output
semplificato e condensato (hash). Questa tecnica rimuove quindi la necessità di dover archiviare e “ricordare” grandi quantità di dati.
Diverse funzioni di hash produrranno output di dimensione differente, ma la dimensione dell’output per ciascun algoritmo di hashing sarà sempre costante.
Per esempio, l’algoritmo SHA-256 produce output di 256 bit (64 caratteri nel formato esadecimale), mentre l’algoritmo SHA-1 genera digest di 160 bit (40 caratteri in esadecimale).
Per illustrare il concetto, si può notare che elaborando le parole “C3T” e “c3t” attraverso l’algoritmo di hashing SHA-256 otteniamo 2 digest di lunghezza fissa ma completamente diversi.
Similmente con l’algoritmo SHA-1 otteniamo due digest di 40 caratteri.
Un piccolo cambiamento nel testo di input risulta in un valore di hash totalmente differente. Inoltre, fissato l’algoritmo, gli output avranno sempre una dimensione fissa, a prescindere dalle dimensioni dell’input.
Una funzione di hash che utilizza tecniche crittografiche può essere definita come una funzione crittografica di hash. In generale, rompere una funzione crittografica di hash
richiede una miriade di tentativi a forza bruta. Per riuscire a “invertire” una funzione crittografica di hash, è necessario indovinare l’input a suon di tentativi fino a quando viene
prodotto l’output corrispondente. Tuttavia, c’è anche la possibilità che diversi input possano produrre lo stesso esatto output, caso in cui avviene una “collisione”.
Tecnicamente, una funzione crittografica di hash deve seguire tre proprietà per essere considerata effettivamente sicura: