Prueba de comprobación de contraseña SHA-3

2

Estoy en una situación en la que necesito endurecer un hash de contraseña, pero no se me permite traer dependencias adicionales, así que estoy bastante obligado a hacer lo único que todos parecen desaconsejar: implementar mi propia implementación.

La familia SHA, considerada hash rápida, no parece adecuada para el hashing de contraseñas. Y también existe el riesgo de pérdida de entropía debido a los hashes repetidos de hash.

La intención de "hash lento" parece ser un aumento del tiempo de CPU y los requisitos de memoria, por lo que concibí la siguiente estrategia.

  • la contraseña está oculta a través de SHA-3 512
  • el valor de hash se envía a un PRNG mt19937 a través de una secuencia semilla
  • se genera una larga secuencia aleatoria para rehacerse
  • repetir el mismo número de veces n
  • el valor de hash final se deriva del hash de todas las secuencias al revés

Eso parece introducir una cantidad extra configurable justa de trabajo y requisitos de memoria.

Entonces, mi pregunta es si esta es una estrategia razonable y, de ser así, qué longitud de secuencia y profundidad de recursión deberían ser suficientes.

Actualización:

Terminé expandiendo un poco la implementación, al incorporar también un algoritmo de hash en "aleatorio" para cada paso del proceso, 12 en total: SHA2, RealSHA3 y Keccak con un tamaño de resumen de 224, 256, 384 y 512. utilizando un doble fijo como selector.

En general, en comparación con un solo hash SHA3 simple, esta implementación es aproximadamente 100k veces más lenta, e incurre en un costo adicional de ~ 20 MB de RAM en una recursión bastante profunda y arbitrariamente ramificada para producir el hash final, que es lo que puede permitirse el lujo de permanecer dentro de límites razonables teniendo en cuenta las especificaciones mínimas de la plataforma de destino. Pero posiblemente igual de importante, esto brinda una diversidad computacional adicional en comparación con el ingenuo enfoque "rehash n times", mediante el uso de múltiples algoritmos de hashing, la generación de PRN con un estado interno bastante grande, std::seed_seq siempre se alimenta de la salida hash completa y realiza condicionamiento adicional "de los valores, y por último, pero no menos importante, agregar algunas operaciones de punto flotante de precisión doble para unirlos todos, con suerte haciendo que todo el procedimiento sea hostil para GPU / ASIC.

El hash ahora toma aproximadamente 500 ms, comparado con los 5000 nsegs, en una CPU de 4 Ghz i7. Dado el total de 95 símbolos permitidos en una contraseña, y suponiendo una escala perfecta de hasta 8 hilos, a esta PC le tomará ~ 1450 años probar cada combinación posible para una contraseña de 6 caracteres, o ~ 130 años para una contraseña de 8 caracteres con 100k Tales CPUs, que parecen razonablemente exigentes.

¿Se considera esto "endurecido" lo suficiente y, de no ser así, cómo puedo mejorarlo?

    
pregunta dtech 23.11.2018 - 23:19
fuente

3 respuestas

3

Hay una solución a esto que no requiere que incluyas otras dependencias como Argon2. Puede implementar el algoritmo utilizado por OpenPGP, denominado String-to-Key , o S2K. Este algoritmo funciona al alimentar la contraseña y la sal repetidas a una función hash. La contraseña y la sal se repiten lo suficiente como para que la función hash tome un tiempo no despreciable para procesarla. Este es un KDF lento tan simple que incluso se puede hacer usando las utilidades estándar de Linux (en este ejemplo con SHA-256):

yes "$pass$salt" | head -c 50M | sha256sum

Si alguna vez puede incorporar sus propias dependencias, le recomiendo escuchar a Future Security, cuya excelente respuesta enumera alternativas superiores a S2K y su esquema personalizado.

    
respondido por el forest 24.11.2018 - 02:48
fuente
2

Vale la pena agregar Argon2 como una dependencia. O bcrypt si no puedes usar Argon2 optimizado y logras evitar todas las formas en que bcrypt te permite dispararte en el pie. Si no te queda ninguna buena opción, entonces ten una consideración adicional a no permitir que los humanos elijan sus propias contraseñas.

Perder la entropía mediante el hash repetido no es algo que deba preocuparte a menos que trunques la salida de hash entre iteraciones o si usas una función hash realmente mala. No es un problema para una función segura con salida grande. Solo cuando dos contraseñas diferentes conducen a cadenas de hashes que se fusionan, perderá algo. En otras palabras, solo cuando tienes una colisión accidental.

El uso de un RNG para generar una nueva entrada es completamente innecesario. La salida de hashes criptográficos es igual de aleatoria, ya sea que utilice entradas de apariencia aleatoria o no aleatoria. Podría empeorar las cosas si alguien pudiera usar una implementación de hardware optimizada mientras tuviera que usar una implementación de software más lenta. Usted está definitivamente empeorando las cosas si hay algún error en la implementación o si se reduce el valor de inicialización, un número de 64 bits.

Su método específico puede permitir un intercambio de memoria de tiempo. Algunos candidatos en la competencia de hashing de contraseñas , incluido Argon2, fueron diseñados para que no pueda reducir a la mitad el requisito de memoria si solo está dispuesto a reducir a la mitad la velocidad. (Scrypt le permite hacer tales concesiones y ese problema fue una de las motivaciones para buscar un mejor algoritmo). Podría pensar que duplicar el tiempo de cómputo no vale la pena ahorrar memoria, pero al final puede terminar con un rendimiento más alto, menos energía consumida, o menor costo si puede comprar hardware de bajo consumo de memoria más barato o más eficiente y hacer más operaciones en paralelo.

Cualquiera que sea el algoritmo que pueda encontrar probablemente sería, en el mejor de los casos, competitivo con PBKDF2. (PBKDF2 no es excelente, pero es lo suficientemente simple de implementar si ya tiene una función hash).

Si usa PBKDF2 o algo parecido, probablemente no debería usar SHA-3. Los hashes SHA-3 pueden calcularse de manera bastante eficiente, pero es relativamente lento en las CPU. Eso podría beneficiar a los crackers de contraseñas si pudieran usar implementaciones más rápidas y eficientes. Sería mejor usar SHA-2-512, en realidad. O Blake2.

    
respondido por el Future Security 24.11.2018 - 01:42
fuente
0

Si realmente no puede incluir nuevas dependencias o código de terceros (y realmente, su primer paso debería ser hacer retroceder esta limitación), es mucho mejor implementar un algoritmo estándar y verificado que crear su propio algoritmo. . Entonces, no solo se beneficia con el uso de un algoritmo con seguridad conocida, reconocido por expertos en seguridad y demostrado durante años de uso en el campo, sino que también tiene la oportunidad de probar contra implementaciones estándar o vectores de prueba para asegurarse de que no realizó Cualquier error en la implementación que arruine la seguridad, como accidentalmente solo hash hasta el primer byte cero o algo así. El algoritmo más fácil y menos propenso a errores para su implementación es probablemente PBKDF2, ya que en su mayoría solo necesita un hash criptográfico y una fuente de aleatoriedad para la sal, que parece que ya tiene.

    
respondido por el Ben 24.11.2018 - 15:23
fuente

Lea otras preguntas en las etiquetas