¿Cómo implementar iteraciones al hashear contraseñas?

1

Para las contraseñas de hash de forma segura, los algoritmos como PBKDF2 realizan muchas iteraciones de un hash común como SHA1. ¿Hay ciertas formas en que estas iteraciones deben realizarse para estar seguros?

En particular, de password-hash.js :

function generateHash(algorithm, salt, password, iterations) {
  iterations = iterations || 1;
  try {
    var hash = password;
    for(var i=0; i<iterations; ++i) {
      hash = crypto.createHmac(algorithm, salt).update(hash).digest('hex');
    }

    return algorithm + '$' + salt + '$' + iterations + '$' + hash;
  } catch (e) {
    throw new Error('Invalid message digest algorithm');
  }
}

¿Es esta una forma segura de hash la contraseña? Puedo imaginar que si tienes un algoritmo como este que tiene:

HMAC(HMAC(HMAC(password)))

entonces existe una función más rápida

HMAC3(password)

que da la misma salida. ¿Es este el caso?

    
pregunta Sjoerd 19.05.2016 - 12:16
fuente

1 respuesta

2

Sí, hay varios requisitos para una función hash iterativa:

  • No debería ser posible realizar ninguna precomputación, como el uso de tablas de arco iris.
  • La implementación debe evitar ejecutarse en ciclos o puntos fijos en la función hash.
  • La implementación debe ser lo más rápida posible, porque eso es lo que usaría el atacante.

Especialmente en el punto final, falta el código de ejemplo. El crypto.createHmac(algorithm, salt) debería estar realmente fuera del bucle. Debido a que el atacante hasheado muchas contraseñas con la misma sal, incluso puede colocar la llamada createHmac fuera del bucle de contraseña, por ejemplo:

hmac = crypto.createHmac(algorithm, salt)
for (password in allpasswords) {
    var hash = password;
    for(var i=0; i<iterations; ++i) {
        hash = hmac.update(hash).digest('hex');
    }
    ...
}

Esto le da al atacante una ventaja al descifrar contraseñas, lo que se evitaría si el HMAC usara la contraseña en lugar de la sal como la clave, como hace PBKDF2.

Al implementando el código dado en C y haciendo algunas optimizaciones, logré que sea 10 veces Más rápido que la implementación original de NodeJS. Esto significa que un atacante puede descifrar contraseñas 10 veces más rápido de lo que pretendía, sin siquiera utilizar una GPU o FPGA.

Entonces existe una función que hace una versión rápida de HMAC(HMAC(HMAC(password))) , simplemente porque HMAC hace el mismo trabajo en cada iteración.

Escribí una publicación de blog sobre esto.

    
respondido por el Sjoerd 25.05.2016 - 13:39
fuente

Lea otras preguntas en las etiquetas