Hashing de contraseñas usando problemas NP completos


16

Los algoritmos de hashing de contraseñas de uso común funcionan de esta manera hoy en día: agregue la contraseña y alimente a un KDF. Por ejemplo, usando PBKDF2-HMAC-SHA1, el proceso de hash de contraseña es DK = PBKDF2(HMAC, Password, Salt, ...). Debido a que HMAC es un hashing de 2 rondas con teclas acolchadas, y SHA1 es una serie de permutaciones, cambios, rotaciones y operaciones bit a bit, fundamentalmente, todo el proceso son algunas operaciones básicas organizadas de cierta manera. No es obvio, fundamentalmente, cuán difíciles son realmente de calcular. Esa es probablemente la razón por la cual las funciones unidireccionales siguen siendo una creencia y hemos visto que algunas funciones hash criptográficas históricamente importantes se volvieron inseguras y obsoletas.

Me preguntaba si es posible aprovechar los problemas completos de NP para el hash de contraseñas de una manera completamente nueva, con la esperanza de darle una base teórica más sólida. La idea clave es, supongamos que P! = NP (si P == NP entonces no OWF, por lo que los esquemas actuales también se rompen), ser un problema NPC significa que la respuesta es fácil de verificar pero difícil de calcular. Esta propiedad se ajusta bien a los requisitos de hashing de contraseñas. Si vemos la contraseña como la respuesta a un problema de NPC, entonces podemos almacenar el problema de NPC como el hash de la contraseña para contrarrestar los ataques fuera de línea: es fácil verificar la contraseña, pero difícil de descifrar.

La advertencia es que la misma contraseña se puede asignar a varias instancias de un problema de NPC, probablemente no todas sean difíciles de resolver. Como primer paso en esta investigación, estaba tratando de interpretar una cadena binaria como respuesta a un problema de 3-SAT, y construir una instancia de problema de 3-SAT para la cual la cadena binaria es una solución. En su forma más simple, la cadena binaria tiene 3 bits: x_0, x_1, x_2. Luego hay 2 ^ 3 == 8 cláusulas:

000 (    (x_0) v    (x_1) v    (x_2) )
--------------------------------------
001 (    (x_0) v    (x_1) v NOT(x_2) )
010 (    (x_0) v NOT(x_1) v    (x_2) )
011 (    (x_0) v NOT(x_1) v NOT(x_2) )
100 ( NOT(x_0) v    (x_1) v    (x_2) )
101 ( NOT(x_0) v    (x_1) v NOT(x_2) )
110 ( NOT(x_0) v NOT(x_1) v    (x_2) )
111 ( NOT(x_0) v NOT(x_1) v NOT(x_2) )

Suponga que la cadena binaria es 000. Entonces solo 1 de 8 cláusula es falsa (la primera). Si descartamos la primera cláusula y las 7 cláusulas restantes, 000 es una solución de la fórmula resultante. Entonces, si almacenamos la fórmula, entonces podemos verificar 000.

El problema es que, para una cadena de 3 bits, si ve 7 cláusulas diferentes allí, sabe instantáneamente cuál falta y eso revelaría los bits.

Así que más tarde decidí descartar 3 de ellos, manteniendo solo los 4 marcados por 001, 010, 100 y 111. Esto a veces introduce colisiones pero hace que resolver el problema sea menos trivial. Las colisiones no siempre ocurren, pero aún no se sabe si seguramente desaparecerían cuando la entrada tiene más bits.

Editar. En el caso general donde la cadena binaria puede ser cualquiera de (000, 001, ..., 111), todavía hay 8 cláusulas donde 7 son verdaderas y 1 es falsa. Elija las 4 cláusulas que dan valor de verdad (001, 010, 100, 111). Esto se refleja en la implementación del prototipo a continuación.

Editar. Como la respuesta mostrada por @DW a continuación, este método de elección de cláusulas aún puede dar como resultado demasiadas cláusulas en un conjunto dado de variables que hace posible reducir rápidamente sus valores. Existen métodos alternativos para elegir las cláusulas entre el total de 7 * C (n, 3) cláusulas. Por ejemplo: Elija un número diferente de cláusulas de un conjunto dado de variables, y hágalo solo para las variables adyacentes ((x_0, x_1, x_2), (x_1, x_2, x_3), (x_2, x_3, x_4), .. .) y así formar un ciclo en lugar de una camarilla. Es probable que este método no funcione tan bien porque intuitivamente puedes probar asignaciones usando inducción para probar si se pueden cumplir todas las cláusulas. Entonces, para simplificar la explicación de la estructura general, simplemente usemos el método actual.

El número de cláusulas para una cadena de n bits es 4 * C (n, 3) = 4 * n * (n - 1) * (n - 2) / 6 = O (n ^ 3), lo que significa el tamaño de hash es un polinomio del tamaño de la contraseña.

Hay una implementación prototipo en Python aquí . Genera una instancia de problema 3-SAT a partir de una cadena binaria de entrada del usuario.


Después de esta larga introducción, finalmente mis preguntas:

  1. ¿La construcción anterior (como se implementa en el prototipo) funciona como hashing seguro de contraseñas, o al menos parece prometedor, se puede revisar, etc.? Si no, ¿dónde falla?

  2. Debido a que tenemos 7 * C (n, 3) cláusulas para elegir, ¿es posible encontrar otra forma de construir una instancia segura de 3-SAT adecuada para usar como hash de contraseña, posiblemente con la ayuda de la aleatorización?

  3. ¿Hay algún trabajo similar tratando de aprovechar la integridad de NP para diseñar esquemas de hashing de contraseñas seguros probados y ya obtuvieron algunos resultados (ya sean positivos o negativos)? Algunas introducciones y enlaces serían muy bienvenidos.


Editar. Acepto la respuesta a continuación de @DW, quien fue el primero en responder y me dio una gran información sobre la estructura del problema, así como recursos útiles. El ingenuo esquema de selección de cláusulas presentado aquí (como se implementó en el prototipo de Python) no pareció funcionar porque es posible reducir rápidamente las asignaciones de variables en grupos pequeños. Sin embargo, el problema sigue abierto porque no he visto una prueba formal que muestre que tales reducciones de NPC a PasswordHashing no funcionarán en absoluto. Incluso para este problema específico de reducción de 3-SAT, puede haber diferentes formas de elegir cláusulas que no quiero enumerar aquí. Por lo tanto, cualquier actualización y discusión son muy bienvenidas.


Conecté la generación de su cláusula a un solucionador de sat (picosat usando pycosat) aquí . Para nbits = 300 lo más largo es generar las cláusulas, pycosat mata la instancia. No superé los 300 porque la generación de tu cláusula es en realidad muy larga. Además, 0 ... 0 es siempre una solución en su generación. Si siempre tiene soluciones 'fáciles', entonces esto no funcionará.
holf

Respuestas:


17

Desafortunadamente, esto no parece funcionar (ver más abajo para más detalles), y parece difícil encontrar una manera de hacer que este tipo de idea produzca un esquema seguramente seguro.

El problema con tu idea general

No eres el primero en pensar en la idea de tratar de basar la criptografía en problemas NP-completos. El problema es que la dureza NP solo asegura la dureza en el peor de los casos, pero la criptografía requiere una dureza promedio en el caso. Ha habido múltiples intentos de basar la criptografía en problemas de NP completo (por ejemplo, criptosistemas de mochila), pero no les ha ido bien. Por lo general, lo que sucede es que las personas descubren algoritmos que a menudo son efectivos en promedio (o con probabilidad no trivial), aunque en el peor de los casos son exponenciales; Esto es suficiente para romper la criptografía, aunque no contradiga la dureza NP.

Sugiero leer más sobre el tema. Puede encontrar algunos puntos de partida útiles en La importancia de los problemas NP-Hard en criptografía , problemas abiertos de complejidad de caso promedio que no sean funciones unidireccionales , estado de los mundos de Impagliazzo. , Reducciones del peor caso al caso promedio .

El problema con tu esquema particular

Su propuesta específica no está completamente especificada. Para analizar un esquema, debe especificar completamente cómo funciona el esquema. En su caso, no está claro cómo seleccionar 4 de las 7 cláusulas en el ejemplo general. (Y un solo ejemplo no es un sustituto de una especificación que describe cómo lo hace en general).

X0 0,X1,X2,X3,X4 425 5posibles asignaciones a esas 5 variables, así que pruébelas todas y descarte cualquier asignación que sea violada por cualquiera de las 40 cláusulas. Predigo que esto te dejará con solo una asignación que sea consistente con todas las cláusulas.

1/ /21/ /21025 5-17 7/ /8(7 7/ /8)402-7.7(25 5-1)×2-7.70,15

Esto se puede repetir para cada grupo de 5 variables, recuperando de manera única la asignación satisfactoria única para cada uno. Si hay alguna ambigüedad, las asignaciones de candidatos se pueden verificar con otras cláusulas.

De esta manera, vemos que hay un algoritmo eficiente que generalmente resolverá la clase de instancias 3SAT generadas por su procedimiento. No resolverá todas las instancias de 3SAT, pero las instancias que genera tienen una estructura especial, y resuelve instancias con esa estructura especial de manera efectiva. Esto ilustra bien el punto: algunas instancias de 3SAT son más fáciles que otras, y la dureza de 3SAT (en el peor de los casos) dice poco o nada sobre la dureza de las instancias especiales que genera o la dureza de una instancia promedio de 3SAT.


Hay una implementación de referencia que actúa como una especificación completa. En este primer intento, el esquema es realmente simple. Simplemente elegí las 4 cláusulas que darían 001, 010, 100 y 111 al sustituir la contraseña. Esto proporciona 4 combinaciones válidas de 8 para cada cláusula.
Cyker

Probablemente tenga razón en que esto rápido, sin embargo, da demasiadas cláusulas que hacen posible reducir la solución rápidamente. Sin embargo, comenzamos con las cláusulas O (n ^ 3) y somos libres de elegir cuál guardar. Los trillizos pueden no ser independientes. Entonces, me pregunto si las cláusulas se eligen con un patrón que intenta eliminar instancias de problemas fáciles, si su análisis heurístico aún se mantiene.
Cyker

1
Pero lo más interesante es, en términos generales, ¿no tenemos ningún problema NPC de caso promedio?
Cyker

1
@Cyker, tienes toda la razón. Estrictamente hablando, no puede multiplicar las probabilidades ya que no hay garantías de que las probabilidades sean independientes. Es solo una heurística para tratar de predecir qué tan bien podría funcionar el algoritmo. La heurística podría estar equivocada. La prueba final es implementar el algoritmo y ver si funciona o no.
DW

2
Una prueba rápida podría ser probar sus instancias en un solucionador SAT. Creo que los SAT Solvers serán eficientes en sus instancias, pero no intenté entender completamente sus especificaciones. Intente generar una instancia de 10000 variables y ejecute un SAT Solver (por cierto, sin relleno / sal, las contraseñas serán mucho más pequeñas ...)
holf
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.