El diseño representado socavaría por completo la seguridad de bcrypt.
Su diseño podría simplificarse simplemente eliminando la parte bcrypt del flujo y confiando solo en el hash SHA. Esa simplificación no cambiaría significativamente la seguridad del diseño, aún sería tan inseguro como la simple aplicación de un hash SHA.
Sin embargo, usar un hash SHA con un salt sería suficiente para proteger las buenas contraseñas. Solo las contraseñas débiles se benefician del uso de hashing de contraseña más fuerte.
No ha descrito completamente el problema que está tratando de resolver, por lo que no podemos proporcionarle ningún consejo sólido sobre cómo proceder. Sin embargo, me vienen a la mente dos interpretaciones de su pregunta, y cada una de ellas puede ser respondida.
¿Está intentando acelerar la creación masiva de usuarios?
Si está intentando acelerar la creación masiva de nuevos usuarios y el algoritmo de hash de contraseña lo ralentiza, entonces puedo proponer dos formas de mejorar ese caso de uso bastante específico.
- Use contraseñas seguras y un hash de contraseña mediocre. Si las contraseñas que genera para los usuarios inicialmente son seguras, entonces no necesita la seguridad completa de bcrypt. Una contraseña inicial con 128 bits de entropía pasado a través de un hash de contraseña que realiza una única iteración con sal de SHA-2 es lo suficientemente segura. Una vez que el usuario cambia la contraseña inicial a otra cosa, puede cambiar a un algoritmo de hashing de contraseña diferente. Esto incluso puede lograrse utilizando formatos estándar para hashes de contraseña, como el que una vez usó la función
crypt
, en el que el formato comienza con una especificación del hash utilizado.
- Use un hash de contraseña que admita el hash inicial rápido, pero es más lento para verificar las contraseñas. Esto se puede lograr aplicando un hash SHA-2 a la concatenación de sal, contraseña y una cadena de bits aleatoria corta. La cadena de bits aleatoria no se almacena de todos modos, por lo que tiene que ser forzada brutalmente para verificar una contraseña. Esta fuerza bruta reemplaza la iteración habitual utilizada en los hashes de contraseña.
¿Está intentando reducir la carga de CPU en su servidor?
Hay algoritmos de hashing de contraseñas que pueden descargar de forma segura la parte de cómputo que requiere la CPU al cliente sin comprometer la seguridad. Esto puede incluso mejorar la seguridad al no permitir que el servidor vea la contraseña real. El inconveniente de este enfoque es que requiere soporte del lado del cliente. Un cliente ya no puede enviar el nombre de usuario y la contraseña para iniciar sesión.
¿Qué hash utilizar?
No use nada más débil que SHA-2 en ningún sistema nuevo. Cualquier sistema heredado que use SHA-1 para el uso relacionado con la seguridad debe ser eliminado o actualizado. Cualquier sistema heredado que use MD5 para fines relacionados con la seguridad debería haberse eliminado hace una década.
La familia SHA-2 tiene seis variantes diferentes. No vayas con una salida más corta porque crees que será más rápido. En realidad, solo hay dos variantes de la función de compresión. Uno tiene un estado interno de 256 bits y está optimizado para CPU de 32 bits. El otro tiene un estado interno de 512 bits y está optimizado para CPU de 64 bits. Si su CPU es de 64 bits, entonces SHA-512 es tanto el más rápido como el más seguro.
Para el hashing de contraseñas, nunca se debe hash sin salt. Creo que ese es el único consejo completamente objetivo que se puede dar sobre la forma de hash de contraseñas. Hay muchos otros consejos que dar, pero el resto dependerá del escenario de amenaza.