Contrariamente a quanto sottolineano le risposte più votate qui, la non iniettività (cioè che ci sono più stringhe che hanno lo stesso valore) di una funzione hash crittografica causata dalla differenza tra la dimensione di input grande (potenzialmente infinita) e la dimensione di output fissa non lo è il punto importante - in realtà, preferiamo le funzioni hash in cui tali collisioni avvengono il più raramente possibile.
Considera questa funzione (nella notazione PHP, come domanda):
function simple_hash($input) {
return bin2hex(substr(str_pad($input, 16), 0, 16));
}
Questo aggiunge alcuni spazi, se la stringa è troppo corta, quindi prende i primi 16 byte della stringa, quindi la codifica come esadecimale. Ha la stessa dimensione di output di un hash MD5 (32 caratteri esadecimali o 16 byte se omettiamo la parte bin2hex).
print simple_hash("stackoverflow.com");
Questo produrrà:
737461636b6f766572666c6f772e636f6d
Questa funzione ha anche la stessa proprietà di non iniettività evidenziata dalla risposta di Cody per MD5: possiamo passare stringhe di qualsiasi dimensione (purché si adattino al nostro computer) e produrrà solo 32 cifre esadecimali. Ovviamente non può essere iniettivo.
Ma in questo caso, è banale trovare una stringa che mappa lo stesso hash (basta applicarlo hex2bin
sul tuo hash e il gioco è fatto). Se la tua stringa originale aveva la lunghezza 16 (come il nostro esempio), otterrai anche questa stringa originale. Niente di questo tipo dovrebbe essere possibile per MD5, anche se sai che la lunghezza dell'input è piuttosto breve (a parte provare tutti gli input possibili finché non ne troviamo uno che corrisponda, ad esempio un attacco di forza bruta).
I presupposti importanti per una funzione hash crittografica sono:
- è difficile trovare una stringa che produca un dato hash (resistenza preimage)
- è difficile trovare una stringa diversa che produca lo stesso hash di una determinata stringa (seconda resistenza preimage)
- è difficile trovare qualsiasi coppia di stringhe con lo stesso hash (resistenza alle collisioni)
Ovviamente la mia simple_hash
funzione non soddisfa nessuna di queste condizioni. (In realtà, se restringiamo lo spazio di input a "stringhe di 16 byte", la mia funzione diventa iniettiva, e quindi è anche dimostrabile che resiste alla seconda immagine e alle collisioni.)
Ora esistono attacchi di collisione contro MD5 (ad esempio è possibile produrre una coppia di stringhe, anche con un dato stesso prefisso, che hanno lo stesso hash, con un bel po 'di lavoro, ma non impossibile molto lavoro), quindi non dovresti usare MD5 per qualsiasi cosa critica. Non è ancora disponibile un attacco preimmagine, ma gli attacchi miglioreranno.
Per rispondere alla domanda effettiva:
Di cosa si tratta in queste funzioni che rende impossibile rintracciare le stringhe risultanti?
Ciò che MD5 (e altre funzioni hash si basano sulla costruzione Merkle-Damgard) effettivamente fanno è applicare un algoritmo di crittografia con il messaggio come chiave e un valore fisso come "testo normale", utilizzando il testo cifrato risultante come hash. (Prima di ciò, l'input viene riempito e suddiviso in blocchi, ciascuno di questi blocchi viene utilizzato per crittografare l'output del blocco precedente, XORed con il suo input per evitare calcoli inversi.)
I moderni algoritmi di crittografia (inclusi quelli utilizzati nelle funzioni hash) sono realizzati in modo da rendere difficile il recupero della chiave, anche con testo in chiaro e cifrato (o anche quando l'avversario ne sceglie uno). Lo fanno generalmente eseguendo molte operazioni di mescolamento dei bit in modo che ogni bit di uscita sia determinato da ogni bit chiave (più volte) e anche da ogni bit di ingresso. In questo modo puoi rintracciare facilmente cosa succede all'interno se conosci la chiave completa e l'input o l'output.
Per le funzioni hash tipo MD5 e un attacco preimage (con una stringa hash a blocco singolo, per semplificare le cose), hai solo input e output della tua funzione di crittografia, ma non la chiave (questo è quello che stai cercando).