¿Cómo puede bcrypt tener sales integradas?
El artículo de Coda Hale "Cómo almacenar una contraseña de forma segura" afirma que:
bcrypt tiene sales incorporadas para evitar ataques a la mesa Rainbow.
Cita este artículo , que dice que en la implementación de OpenBSD de bcrypt
:
OpenBSD genera el bcrypt salt de 128 bits a partir de un flujo de claves arcfour (arc4random(3)), sembrado con datos aleatorios que el kernel recopila de las sincronizaciones de los dispositivos.
No entiendo cómo puede funcionar esto. En mi concepción de una sal:
- Debe ser diferente para cada contraseña almacenada, de modo que se deberá generar una tabla de arcoíris separada para cada una.
- Debe almacenarse en algún lugar para que sea repetible: cuando un usuario intenta iniciar sesión, tomamos su intento de contraseña, repetimos el mismo procedimiento salt-and-hash que hicimos cuando almacenamos originalmente su contraseña y comparamos
Cuando uso Devise (un administrador de inicio de sesión de Rails) con bcrypt, no hay una columna salt en la base de datos, así que estoy confundido. Si la sal es aleatoria y no se almacena en ningún lugar, ¿cómo podemos repetir de manera confiable el proceso de hash?
En resumen, ¿cómo puede bcrypt tener sales integradas?
Esto es bcrypt:
Genera una sal aleatoria. Se ha preconfigurado un factor de "coste". Recoge una contraseña.
Derive una clave de cifrado a partir de la contraseña utilizando el factor de sal y costo. Úselo para cifrar una cadena conocida. Almacene el costo, la sal y el texto cifrado. Debido a que estos tres elementos tienen una longitud conocida, es fácil concatenarlos y almacenarlos en un solo campo, pero poder dividirlos más adelante.
Cuando alguien intenta autenticarse, recupera el costo y la sal almacenados. Derive una clave a partir de la contraseña ingresada, el costo y la sal. Cifre la misma cadena conocida. Si el texto cifrado generado coincide con el texto cifrado almacenado, la contraseña coincide.
Bcrypt opera de manera muy similar a esquemas más tradicionales basados en algoritmos como PBKDF2. La principal diferencia es el uso de una clave derivada para cifrar texto sin formato conocido; otros esquemas (razonablemente) asumen que la función de derivación de clave es irreversible y almacenan la clave derivada directamente.
Almacenado en la base de datos, un bcrypt
"hash" podría verse así:
$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
En realidad, se trata de tres campos, delimitados por "$":
2a
Identifica labcrypt
versión del algoritmo que se utilizó.10
es el factor costo; 2 Se utilizan 10 iteraciones de la función de derivación de claves (lo cual, por cierto, no es suficiente. Recomendaría un costo de 12 o más).vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa
es la sal y el texto cifrado, concatenados y codificados en una Base-64 modificada. Los primeros 22 caracteres se decodifican en un valor de 16 bytes para la sal. Los caracteres restantes son texto cifrado que se comparará para la autenticación.
Este ejemplo está tomado de la documentación de la implementación Ruby de Coda Hale.
Creo que esa frase debería haberse redactado de la siguiente manera:
bcrypt tiene sales integradas en los hashes generados para evitar ataques a la tabla Rainbow.
La bcrypt
utilidad en sí no parece mantener una lista de sales. Más bien, las sales se generan aleatoriamente y se agregan a la salida de la función para que se recuerden más adelante (según la implementación Java debcrypt
). Dicho de otra manera, el "hash" generado por bcrypt
no es sólo el hash. Más bien, es el hachís y la sal concatenados.
Estos son términos simples...
Bcrypt no tiene una base de datos, almacena la sal...
La sal se añade al hachís en formato base64....
La pregunta es ¿cómo verifica bcrypt la contraseña cuando no tiene base de datos...?
Lo que hace bcrypt es extraer la sal del hash de la contraseña... Utilice la sal extraída para cifrar la contraseña simple y compare el nuevo hash con el antiguo hash para ver si son iguales...
Para dejar las cosas aún más claras,
Registro/Dirección de inicio de sesión ->
La contraseña + salt se cifra con una clave generada a partir de: cost, salt y la contraseña. A ese valor cifrado lo llamamos cipher text
. luego adjuntamos la sal a este valor y lo codificamos usando base64. adjuntandole el costo y esta es la cadena producida por bcrypt
:
$2a$COST$BASE64
Este valor se almacena eventualmente.
¿Qué tendría que hacer el atacante para encontrar la contraseña? (otra dirección <-)
En caso de que el atacante tenga control sobre la base de datos, el atacante decodificará fácilmente el valor base64 y luego podrá ver la sal. la sal no es secreta. aunque es aleatorio. Luego necesitará descifrar el archivo cipher text
.
Lo que es más importante: no hay hash en este proceso, sino cifrado y descifrado costosos para la CPU. por tanto, las tablas de arcoíris son menos relevantes aquí.