Primero que nada, sí, SHA1 (así como cualquier otro algoritmo de hash) es determinista ; en otras palabras, dada la misma entrada, siempre producirá la misma salida. (Esa salida puede tener formato de manera diferente, como representación binaria pura, hexadecimal o Base64, pero el formato de la salida es irrelevante para el valor de la salida).
Lo que describe es lo que se conoce como ataque de preimagen .
Hay dos variantes de ataques de preimagen:
- En un ataque de preimagen , un atacante tiene un hash H (x) y desea deducir la entrada de hash x. En otras palabras, dados y y H (x) = y, encuentre x.
- En un segundo ataque de preimagen , un atacante tiene una entrada x y desea encontrar una diferente entrada x ', de modo que H (x) = H (x' ).
Tenga en cuenta que x (y x ') puede ser de tamaño arbitrario, pero la salida de la función hash es de tamaño fijo. Algunas funciones de hash se definen para diferentes tamaños de salida, pero dentro del espacio de un solo hash, el tamaño de salida sigue siendo fijo (y, por lo tanto, la función de hash puede tratarse como una salida de tamaño fijo).
Una función hash (como SHA1) funciona, en principio, mediante la iteración de la entrada y el uso de esa entrada para modificar el estado interno, y luego expone la totalidad o parte del estado interno (posiblemente después de un procesamiento final posterior) como el valor hash. Esto es lo que se conoce como construcción Merkle-Damgård .
Hay dos consecuencias de esto:
- Sí, dados los suficientes recursos informáticos, es posible encontrar una entrada que hace hashes a una salida dada
- No, dados los recursos informáticos infinitos, no es posible determinar exactamente qué entrada se usó para obtener una salida determinada (aunque, como consecuencia del punto anterior, puede obtener candidatos )
El último punto puede no ser obvio, pero se sigue del hecho de que si H (x) = y, yx es más largo que y, puede existir un número arbitrario de valores para x que dan el mismo valor para y . Para una función hash ideal, el número esperado de tales colisiones para un tamaño de entrada arbitrario X y un tamaño de salida arbitrario Y (ambos en bits) será 2 ^ (X-Y); por lo tanto, al agregar 192 bits en un hash de 160 bits, si tuviera la capacidad de enumerar todo el espacio de entrada de 192 bits, esperaría encontrar aproximadamente 2 ^ 32 (que es 2 ^ (192-160)) otros valores dando el mismo valor hash.
El caso extremo es un algoritmo hash definido como H (x) = 0. Es trivial en este caso determinar que el hash de un valor dado es 0, pero dada la definición de la función hash y su valor de salida 0, no es posible determinar el valor de cuál produjo 0 como salida.
Como ya se comentó por Anders , los algoritmos hash modernos tienen espacios de salida lo suficientemente grandes como para generar un diccionario de todos los posibles salidas de hash no es factible. Además, incluso si fuera posible generar y almacenar dicho diccionario, solo obtendría una entrada de candidato . Dependiendo del propósito del ataque, esto puede o no ser suficiente.
Supongamos que la función hash se define como H (x) = (x mod 2) para un espacio de entrada de enteros, lo que arroja 0 si x es par y 1 si x es impar. En este caso, puedo decirle que H (65535) = 1, pero dado el valor hash H (x) = 1, todo lo que puede decir sobre la entrada x es que es impar, y que uno de esos candidatos sería (por ejemplo) H (3) = 1.