¿Cómo compara node.bcrypt.js las contraseñas hash y de texto sin formato sin la sal?

95

Desde github :

Para hash una contraseña:

var bcrypt = require('bcrypt');
bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash("B4c0/\/", salt, function(err, hash) {
        // Store hash in your password DB.
    });
});

Para comprobar una contraseña:

// Load hash from your password DB.
bcrypt.compare("B4c0/\/", hash, function(err, res) {
    // res == true
});
bcrypt.compare("not_bacon", hash, function(err, res) {
    // res = false
});

Desde arriba, ¿cómo puede no haber valores de sal involucrados en las comparaciones? ¿Que me estoy perdiendo aqui?

SChang
fuente

Respuestas:

95

La sal se incorpora al hachís (como texto sin formato). La función de comparación simplemente extrae la sal del hash y luego la usa para hash la contraseña y realizar la comparación.

Cuenta
fuente
1
Todavía no entiendo Durante la comparación, ¿cómo sabe qué parte del hachís es la sal si no le proporcionas la sal?
Lunes,
6
bcrypt es un estándar y siempre concatena la sal con el hash en el mismo formato. Usted proporciona la sal cuando encripta y esta se incorpora al hash. bcrypt solo podrá descifrar los datos que se cifraron originalmente con bcrypt; de lo contrario, tiene razón: no habría forma de que sepa qué parte es el hash y qué parte es la sal.
Proyecto de ley
4
Ok, lo entendemos: la sal se almacena con el hash. bcrypt es de código abierto, por lo que todo el mundo sabe exactamente cómo lo almacena. Entonces, sabe cómo extraerlo o cómo generar hash a partir de una contraseña de texto sin formato. ¿Cómo ayuda esto a proteger las contraseñas contra la exploración de tablas de arco iris en busca de hashes, que es básicamente la idea principal detrás de la sal?
Vitaliy Lebedev
13
No importa si el atacante conoce la sal de un hash en particular, no es un secreto. El uso de un sal diferente para cada contraseña significa que el atacante no puede calcular previamente los hashes con valores comunes. Con una sal diferente en cada uno, tendrían que volver a calcular las tablas para cada contraseña, lo que las hace inútiles.
Proyecto de ley
3
vistazo a este camino, qué importa si atacante conoce con certeza la sal de usuario en la base de datos de la siguiente manera: column_password = hash, column_salt = saltvs column_password = hash_salt. El atacante todavía tiene la misma información. El punto de la sal es hacer que cada contraseña sea tan aleatoria y más grande que sea poco probable que alguien la haya calculado previamente.
Muhammad Umer
27

También tuve la misma pregunta que en el póster original y tuve que mirar un poco a mi alrededor y probar diferentes cosas para entender el mecanismo. Como ya han señalado otros, la sal se concatena al picadillo final. Entonces esto significa un par de cosas:

  1. El algoritmo debe conocer la longitud de la sal.
  2. También debe conocer la posición de la sal en la cadena final. por ejemplo, si está compensado por un número específico de izquierda o derecha.

Estas dos cosas generalmente están codificadas en la implementación, por ejemplo, la fuente de implementación bcrypt para bcryptjs define la longitud de la sal como 16

/**
* @type {number}
* @const
* @private
*/

var BCRYPT_SALT_LEN = 16;

Entonces, para ilustrar el concepto básico detrás de la idea, si uno quisiera hacerlo manualmente, se vería similar al siguiente. No recomiendo implementar cosas como esta usted mismo cuando hay bibliotecas que puede hacer.

var salt_length = 16;
var salt_offset = 0;

var genSalt = function(callback)
{
    var alphaNum = '0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ';
    var salt = '';
    for (var i = 0; i < salt_length; i++) {
        var j = Math.floor(Math.random() * alphaNum.length);
        salt += alphaNum[j];
    }
    callback(salt);
}

// cryptographic hash function of your choice e.g. shar2
// preferably included from an External Library (dont reinvent the wheel)
var shar2 = function(str) {
    // shar2 logic here 
    // return hashed string;
}

var hash = function(passwordText, callback)
{
    var passwordHash = null;
    genSalt(function(salt){
        passwordHash = salt + shar2(passwordText + salt);
    });

    callback(null, passwordHash);
}

var compare = function(passwordText, passwordHash, callback)
{
    var salt = passwordHash.substr(salt_offset, salt_length);
    validatedHash = salt + shar2(passwordText + salt);

    callback(passwordHash === validatedHash);   
}

// sample usage
var encryptPassword = function(user)
{
    // user is an object with fields like username, pass, email
    hash(user.pass, function(err, passwordHash){
        // use the hashed password here
        user.pass = passwordHash;
    });

    return user;
}

var checkPassword = function(passwordText, user)
{
    // user has been returned from database with a hashed password
    compare(passwordText, user.pass, function(result){
        // result will be true if the two are equal
        if (result){
            // succeeded
            console.log('Correct Password');
        }
        else {
            // failed
            console.log('Incorrect Password');
        }
    });
}
Alappin
fuente
0

Como yo mismo tenía la misma pregunta, sé exactamente en qué estás pensando.

Tiene una idea errónea entre "Clave secreta" que se usa en algoritmos criptográficos y "Salt" que se usa para ralentizar el proceso de cifrado y dificultar el uso de la fuerza bruta por parte de los piratas informáticos.

Cuando usa la contraseña simple y la sal para generar el hash, ¡este hash usa como clave secreta la contraseña misma ! Entonces, la próxima vez que intente compararla con una contraseña simple, ¡esta contraseña simple debe ser exactamente la misma que utilizó para generar el hash! Así que esta es la razón por la que no tiene que almacenarlo en otro lugar porque el usuario siempre lo proporciona tanto en los pasos de registro como de inicio de sesión.

babaliaris
fuente