Hashing della password utilizzando NP problemi completi


16

Gli algoritmi di hashing delle password comunemente usati funzionano così oggi: Saltare la password e inserirla in un KDF. Ad esempio, utilizzando PBKDF2-HMAC-SHA1, il processo di hashing della password è DK = PBKDF2(HMAC, Password, Salt, ...). Poiché HMAC è un hashing a 2 round con tasti imbottiti e SHA1 una serie di permutazioni, spostamenti, rotazioni e operazioni bit a bit, fondamentalmente l'intero processo è costituito da alcune operazioni di base organizzate in un certo modo. Fondamentalmente, non è ovvio quanto siano difficili da calcolare. Questo è probabilmente il motivo per cui le funzioni a senso unico sono ancora una convinzione e abbiamo visto alcune funzioni di hash crittografiche storicamente importanti diventare insicure e deprecate.

Mi chiedevo se fosse possibile sfruttare i problemi completi di NP per hash delle password in un modo completamente nuovo, sperando di dargli una base teorica più solida. L'idea chiave è, supponiamo che P! = NP (se P == NP quindi nessun OWF così anche gli schemi attuali si rompano), essendo un problema NPC significa che la risposta è facile da verificare ma difficile da calcolare. Questa proprietà si adatta bene ai requisiti di hashing della password. Se consideriamo la password come la risposta a un problema NPC, possiamo archiviare il problema NPC come hash della password per contrastare gli attacchi offline: è facile verificare la password, ma difficile da decifrare.

Un avvertimento è che la stessa password può essere mappata su più istanze di un problema NPC, probabilmente non tutte sono difficili da risolvere. Come primo passo in questa ricerca, stavo cercando di interpretare una stringa binaria come una risposta a un problema 3-SAT e di costruire un'istanza del problema 3-SAT in cui la stringa binaria è una soluzione. Nella sua forma più semplice, la stringa binaria ha 3 bit: x_0, x_1, x_2. Quindi ci sono 2 ^ 3 == 8 clausole:

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) )

Supponiamo che la stringa binaria sia 000. Quindi solo 1 di 8 clausole è falsa (la prima). Se eliminiamo la prima clausola e le rimanenti 7 clausole, allora 000 è una soluzione della formula risultante. Quindi, se memorizziamo la formula, possiamo verificarne 000.

Il problema è, per una stringa a 3 bit, se vedi 7 diverse clausole lì, allora sai immediatamente quale manca e ciò rivelerebbe i bit.

Quindi in seguito ho deciso di scartarne 3, mantenendo solo i 4 contrassegnati da 001, 010, 100 e 111. Questo a volte introduce collisioni ma rende la risoluzione del problema meno banale. Le collisioni non sempre si verificano, ma non è ancora noto se scomparirebbero sicuramente quando l'ingresso ha più bit.

Modificare. Nel caso generale in cui la stringa binaria può essere qualsiasi (000, 001, ..., 111), ci sono ancora 8 clausole in cui 7 sono vere e 1 è falsa. Scegli le 4 clausole che danno valore di verità (001, 010, 100, 111). Ciò si riflette nell'implementazione del prototipo di seguito.

Modificare. Come la risposta mostrata da @DW di seguito, questo metodo di scelta delle clausole può comunque comportare troppe clausole su un dato insieme di variabili che consente di restringere rapidamente i loro valori. Esistono metodi alternativi per scegliere le clausole tra le clausole 7 * C (n, 3) totali. Ad esempio: Scegli un numero diverso di clausole da un determinato set di variabili e fallo solo per variabili adiacenti ((x_0, x_1, x_2), (x_1, x_2, x_3), (x_2, x_3, x_4), .. .) e quindi formare un ciclo anziché una cricca. È probabile che questo metodo non funzioni anche perché intuitivamente puoi provare le assegnazioni utilizzando l'induzione per verificare se tutte le clausole possono essere soddisfatte. Quindi, per semplificare la spiegazione della struttura generale, utilizziamo semplicemente il metodo corrente.

Il numero di clausole per una stringa n-bit è 4 * C (n, 3) = 4 * n * (n - 1) * (n - 2) / 6 = O (n ^ 3), che indica la dimensione di l'hash è un polinomio delle dimensioni della password.

C'è un'implementazione del prototipo in Python qui . Genera un'istanza del problema 3-SAT da una stringa binaria di input dell'utente.


Dopo questa lunga introduzione, finalmente le mie domande:

  1. La costruzione di cui sopra (come implementata nel prototipo) funziona come hashing sicuro della password, o almeno sembra promettente, può essere rivista, ecc.? In caso contrario, dove fallisce?

  2. Dato che abbiamo 7 * C (n, 3) clausole tra cui scegliere, è possibile trovare un altro modo per costruire un'istanza 3-SAT sicura adatta all'uso come hash della password, possibilmente con l'aiuto della randomizzazione?

  3. Esistono lavori simili che cercano di sfruttare la completezza di NP per progettare schemi di hashing delle password sicuri e comprovati e hanno già ottenuto alcuni risultati (positivi o negativi)? Alcune introduzioni e collegamenti sarebbero i benvenuti.


Modificare. Accetterei la risposta di seguito da @DW, che è stato il primo a rispondere e ha dato grandi spunti sulla struttura del problema e risorse utili. Lo schema di selezione della clausola ingenua introdotto qui (come implementato nel prototipo di Python) non sembra funzionare perché è possibile restringere rapidamente le assegnazioni di variabili in piccoli gruppi. Tuttavia, il problema rimane aperto perché non ho visto una prova formale che mostri tali riduzioni dell'HPC-to-PasswordHashing non funzionerà affatto. Anche per questo specifico problema di riduzione 3-SAT, potrebbero esserci diversi modi di scegliere le clausole che non voglio elencare qui. Quindi eventuali aggiornamenti e discussioni sono ancora i benvenuti.


Ho collegato la tua generazione di clausole a un risolutore di sat (picosat usando pycosat) qui . Per nbits = 300 il più lungo è generare le clausole, pycosat uccide l'istanza. Non ho superato i 300 perché la generazione della tua clausola è in realtà molto lunga. Inoltre, 0 ... 0 è sempre una soluzione nella tua generazione. Se hai sempre soluzioni così 'facili', allora non funzionerà.
lupo,

Risposte:


17

Sfortunatamente, questo non sembra funzionare (vedi sotto per i dettagli), e sembra difficile trovare un modo per far sì che questo tipo di idea produca uno schema dimostrabilmente sicuro.

Il problema con la tua idea generale

Non sei il primo a pensare all'idea di provare a basare la crittografia su problemi NP-completi. Il problema è che la durezza NP garantisce solo la durezza peggiore, ma la crittografia richiede durezza media. Ci sono stati diversi tentativi di basare la crittografia su problemi NP completi (ad esempio, i criptosistemi a zaino), ma non sono andati bene. In genere ciò che accade è che le persone scoprono algoritmi che sono spesso efficaci in media (o con probabilità non banale), anche se nel peggiore dei casi sono esponenziali; questo è abbastanza per rompere la criptovaluta, anche se non contraddice la durezza NP.

Suggerisco di leggere di più sull'argomento. Puoi trovare alcuni utili punti di partenza in Il significato di NP-Hard Problems in Cryptography , complessità del caso medio apre problemi diversi dalle funzioni a senso unico , lo stato dei mondi di Impagliazzo? , Riduzioni dal caso peggiore al caso medio .

Il problema con il tuo schema particolare

La tua proposta specifica non è completamente specificata. Per analizzare uno schema, è necessario specificare completamente come funziona lo schema. Nel tuo caso, non è chiaro come selezioni 4 delle 7 clausole nell'esempio generale. (E un singolo esempio non sostituisce una specifica che descrive come lo si fa in generale.)

X0,X1,X2,X3,X425possibili assegnazioni a quelle 5 variabili, quindi provale tutte e scarta tutte le assegnazioni violate da una qualsiasi delle 40 clausole. Prevedo che questo ti lascerà con solo un incarico coerente con tutte le clausole.

1/21/21025-17/8 , così euristicamente la probabilità che soddisfa tutte le 40 clausole è circa(7/8)402-7.7(25-1)×2-7.70.15

Questo può essere ripetuto per ogni gruppo di 5 variabili, recuperando in modo univoco l'assegnazione soddisfacente unica per ciascuna. Se c'è qualche ambiguità, le assegnazioni dei candidati possono essere verificate rispetto ad altre clausole.

In questo modo, vediamo che esiste un algoritmo efficiente che in genere risolve la classe di istanze 3SAT generata dalla tua procedura. Non risolverà tutte le istanze 3SAT, ma le istanze generate generano una struttura speciale e risolvono in modo efficace le istanze con quella struttura speciale. Questo illustra bene il punto: alcune istanze di 3SAT sono più facili di altre, e la durezza di 3SAT (nella complessità del caso peggiore) dice poco o nulla sulla durezza delle istanze speciali generate o sulla durezza di un'istanza 3SAT media.


Esiste un'implementazione di riferimento che funge da specifica completa. In questo primo tentativo, lo schema è davvero semplice. Ho semplicemente scelto le 4 clausole che darebbero 001, 010, 100 e 111 quando si sostituisce la password. Ciò fornisce 4 combinazioni valide su 8 per ogni clausola.
Cyker,

Probabilmente hai ragione nel dire che questo rapido fornisce troppe clausole che rendono possibile restringere rapidamente la soluzione. Tuttavia, iniziamo con le clausole O (n ^ 3) e siamo liberi di scegliere quale mantenere. Le terzine potrebbero non essere indipendenti. Quindi mi chiedo se le clausole siano scelte con uno schema che tenti di rimuovere semplici istanze problematiche, se la tua analisi euristica è ancora valida.
Cyker,

1
Ma la cosa più interessante è che, approssimativamente, non abbiamo problemi di NPC nel caso medio?
Cyker,

1
@Cyker, hai assolutamente ragione. A rigor di termini, non è possibile moltiplicare le probabilità in quanto non vi sono garanzie che le probabilità siano indipendenti. È solo un'euristica cercare di prevedere quanto bene l'algoritmo potrebbe funzionare. L'euristico potrebbe essere sbagliato. Il test finale è implementare l'algoritmo e vedere se funziona o no.
DW,

2
Un test rapido potrebbe essere quello di provare le tue istanze su un solutore SAT. Penso che i Solutori SAT saranno efficienti nelle tue istanze ma non ho provato completamente a capire le tue specifiche. Prova a generare un'istanza di 10000 variabili ed esegui un Risolutore SAT (a proposito, senza imbottitura / salatura, le password saranno molto più piccole ...)
holf
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.