Así que he estado jugando con la idea de tener valores de sal no deterministas para hashes.
Déjame explicarte lo que quiero decir:
Básicamente, apliqué algunas propiedades de Bitcoin, incluida una "dificultad" (es decir, el valor de hash debe comenzar con un cierto número de 0 bits) y se me ocurrió algo que podría usarse para los hashes de contraseña.
Mi algoritmo:
string hashstring=password;
for(int i = 0; i < int.MaxValue; i++)
{
var hash = Hash(hashstring);
hashstring = Convert.ToBase64String(hash);
if(MeetsDifficulty(hash, difficulty))
{
Console.WriteLine("i: "+i);
return hashstring;
}
}
la contraseña en este caso, es algo así como password+salt
donde sal es una sal aleatoria cyrptográfica estándar almacenada con el hash. Sin embargo, como puede ver, también hay un valor i
para el número de veces que se debe hacer hash, que no se almacena junto con el hash.
De esta manera, debe codificar la contraseña varias veces hasta que encuentre algo que cumpla con el nivel de dificultad requerido. Esto es fácil de verificar, pero requiere tiempo porque no se sabe exactamente cuántas veces se debe modificar el valor.
Hay algunas propiedades interesantes de este mecanismo:
- Una contraseña incorrecta es ligeramente indetectable. La única manera de saber que es incorrecto es si conoces el nivel de dificultad y encuentras un hash que lo satisface, pero no coincide con el hash
- Probablemente sea bastante difícil calcular algo de esto en paralelo.
- En teoría, se desconoce por completo cuánto tiempo llevará verificar o calcular un hash (que no sean las probabilidades)
- Bruteforce probablemente sería difícil porque cada intento de contraseña puede resultar en cantidades de hashes extremadamente grandes para verificar la dificultad
Sin embargo, no puedo encontrar un buen uso para estas propiedades. ¿Hay algo bueno para aplicar un esquema de este tipo o hay algo que lo use?
Además, ¿existen posibles puntos débiles en este esquema de hash?
Para mis pruebas, utilicé SHA256 como algoritmo de hash, y se hizo bastante lento después de una dificultad de unos 20 bits de ceros. Sin embargo, esto podría reemplazarse fácilmente con scrypt, bcrypt o SHA512
También, una idea más es que posiblemente puedas construir "rápido" para verificar hashes, pero solo cuando se te proporcione la contraseña correcta. (cambiando la sal si, por ejemplo, ya has activado el valor X veces y quieres apuntar solo al valor Y hash para verificarlo cuando se te da una contraseña correcta)