2010-02-08 9 views
22

Me encontré con BCrypt.net después de leer Jeff Atwood's post about storing passwords que me llevó a la recomendación de Thomas Ptacek a use BCrypt para almacenar contraseñas. Lo cual finalmente me llevó a this C# implementation of BCrypt¿Por qué BCrypt.net GenerateSalt (31) vuelve inmediatamente?

En los comentarios en el último enlace anterior, alguien preguntó "¿Por qué GenerateSalt (30) se toma para siempre, pero GenerateSalt (31) parece que no tarda en absoluto?"

Ejecuté BCrypt.HashPassword (contraseña, BCrypt.GenerateSalt (31)) y obtuve mi resultado en 0 milisegundos.

He estado ejecutando BCrypt.HashPassword ("contraseña", BCrypt.GenerateSalt (30)) durante más de 5 minutos y todavía no he obtenido ningún resultado.

Me doy cuenta de que probablemente no necesitemos una sal de 30 caracteres generada al azar para crear nuestros hash de contraseñas (o irreversible encryption in BCrypt's case) durante años. EDITAR Debería haber leído el código un poco, logRounds no tiene nada que ver con la longitud de sal. Gracias Aaronaught.

Así que, ¿por qué GenerateSalt (31) devuelve un valor casi al instante (cuando se debe tomar alrededor de dos veces más que GenerateSalt (30)

ACTUALIZACIÓN

aquí está la solución:?

private byte[] CryptRaw(byte[] password, byte[] salt, int logRounds) { 
    // ... snip ... 
    uint rounds = 1U << logRounds; 
    // ... snip 
} 

Respuesta

25

sospecho que el error es aquí:

private byte[] CryptRaw(byte[] password, byte[] salt, int logRounds) { 
    // ... snip ... 
    int rounds = 1 << logRounds; 
    // ... snip 
} 

Cuando especifica 31 para el logRounds, se calcula que a medida que 2^32, que no puede caber en un int y desbordamientos, por lo el hash que realmente se hace en ... er, pasa cero, el autor debería haber utilizado uint lugar fácil de solucionar


también ha querido hacer comentarios sobre esto:..!

Me di cuenta que probablemente no necesitaremos una generados aleatoriamente 30 caracteres sal para crear nuestros hashes de contraseñas ...

Tenga en cuenta que el parámetro logRounds no se refiere al número de caracteres/bytes en la sal, que siempre es 16. Se refiere a la base logarítmica del número de pases que el hash tomará para calcular; en otras palabras, es una forma de hacer escala en escala con la Ley de Moore, haciendo que la función sea de varios órdenes de magnitud más costosa de computar si las computadoras alguna vez se vuelven lo suficientemente rápidas para descifrar los valores hash existentes.

+0

Mira, si probaran 'rondas' (en este punto -2^31) usando' rondas! = 0' en lugar de 'rondas> 0', ¡entonces todavía habría funcionado correctamente! :-P –

+1

@Chris: Lección aprendida, siempre escribe tus bucles 'for' con'! = 'En caso de desbordamiento. : P Esta es exactamente la razón por la que es tan peligroso para las personas rodar sus propias funciones de cifrado; ¡incluso los expertos lo malinterpretan! Supongo que este error nunca se informó porque nadie ha intentado 31 rondas de registro antes ... – Aaronaught

+0

es la solución correcta: uint rounds = 1U << logRounds; –

10

Si hash con GenerateSalt(31) vuelve casi al instante, eso es un error. debe informar que aguas arriba (no tengo, por jBCrypt). :-)

De forma predeterminada, las rondas de registro son 10. Esto significa que (si no recuerdo mal), se usan 1024 rondas. Cada vez que incrementa las rondas de registro, se duplica el número de rondas.

En 30 rondas de conexión, realizas 1073741824 rondas. Eso con razón toma mucho tiempo. En 31 rondas de registro, deberían realizarse 2147483648 rondas, pero sospecho que la implementación particular que está utilizando se desborda en su lugar. :-(

+0

esto parece una explicación muy probable para mí ... Voy a +1 aunque no estoy seguro :) – rmeador

+1

tiene sentido: si se duplica cada vez y falla a 31, probablemente haya un 32bit entero involucrado (menos un bit para el signo) en algún lugar que debería estar usando un largo o decimal en su lugar. –

Cuestiones relacionadas