Powszechnie używane algorytmy haszujące hasła działają dzisiaj tak: Zasol hasło i wprowadź je do KDF. Na przykład przy użyciu PBKDF2-HMAC-SHA1 proces mieszania hasła toDK = PBKDF2(HMAC, Password, Salt, ...)
. Ponieważ HMAC jest 2-okrągłym skrótem z wyściełanymi klawiszami, a SHA1 szereg permutacji, przesunięć, rotacji i operacji bitowych, zasadniczo cały proces jest pewnymi podstawowymi operacjami zorganizowanymi w określony sposób. Zasadniczo nie jest oczywiste, jak trudne są obliczenia. Prawdopodobnie dlatego funkcje jednokierunkowe są nadal przekonaniem i widzieliśmy, że niektóre historycznie ważne kryptograficzne funkcje skrótu stały się niepewne i przestarzałe.
Zastanawiałem się, czy da się wykorzystać NP całkowite problemy z hashowaniem haseł w zupełnie nowy sposób, mając nadzieję, że da to solidniejsze podstawy teoretyczne. Kluczową ideą jest założenie, że P! = NP (jeśli P == NP, to nie ma MFW, więc obecne schematy również się psują), ponieważ problem NPC oznacza, że odpowiedź jest łatwa do zweryfikowania, ale trudna do obliczenia. Ta właściwość dobrze pasuje do wymagań mieszania hasła. Jeśli postrzegamy hasło jako odpowiedź na problem NPC, możemy zapisać problem NPC jako skrót hasła do przeciwdziałania atakom offline: łatwo jest zweryfikować hasło, ale trudno je złamać.
Zastrzeżenie polega na tym, że to samo hasło może być mapowane na wiele wystąpień problemu NPC, prawdopodobnie nie wszystkie z nich są trudne do rozwiązania. Jako pierwszy krok w tych badaniach próbowałem zinterpretować ciąg binarny jako odpowiedź na problem 3-SAT i skonstruować instancję problemu 3-SAT, dla którego ciąg binarny jest rozwiązaniem. W najprostszej postaci łańcuch binarny ma 3 bity: x_0, x_1, x_2. Następnie są 2 ^ 3 == 8 klauzul:
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) )
Załóżmy, że ciąg binarny ma wartość 000. Wtedy tylko 1 z 8 klauzul jest fałszywych (pierwszy). Jeśli odrzucimy pierwszą klauzulę i ORAZ pozostałe 7 klauzul, wówczas 000 jest rozwiązaniem wynikowej formuły. Więc jeśli przechowamy formułę, możemy zweryfikować 000.
Problem polega na tym, że dla 3-bitowego ciągu, jeśli zobaczysz tam 7 różnych klauzul, natychmiast wiesz, którego brakuje, a to ujawniłoby bity.
Później postanowiłem odrzucić 3 z nich, pozostawiając tylko 4 oznaczone jako 001, 010, 100 i 111. To czasami wprowadza kolizje, ale sprawia, że rozwiązanie problemu jest mniej proste. Kolizje nie zawsze się zdarzają, ale nie wiadomo, czy na pewno znikną, gdy na wejściu będzie więcej bitów.
Edytować. W ogólnym przypadku, gdy ciąg binarny może być dowolnym z (000, 001, ..., 111), nadal istnieje 8 klauzul, gdzie 7 jest prawdą, a 1 jest fałszem. Wybierz 4 zdania, które dają wartość prawdy (001, 010, 100, 111). Odzwierciedla to poniższe wdrożenie prototypu.
Edytować. Jak pokazuje odpowiedź @DW poniżej, ta metoda wybierania klauzul może nadal skutkować zbyt wieloma klauzulami na danym zbiorze zmiennych, co umożliwia szybkie zawężenie ich wartości. Istnieją alternatywne metody wybierania klauzul spośród wszystkich klauzul 7 * C (n, 3). Na przykład: Wybierz inną liczbę klauzul z danego zestawu zmiennych i zrób to tylko dla sąsiednich zmiennych ((x_0, x_1, x_2), (x_1, x_2, x_3), (x_2, x_3, x_4), .. .) i tym samym tworzą cykl zamiast kliki. Ta metoda prawdopodobnie również nie działa, ponieważ intuicyjnie możesz wypróbować przypisania za pomocą indukcji, aby sprawdzić, czy wszystkie klauzule mogą być spełnione. Aby uprościć ogólną strukturę, zastosujmy po prostu bieżącą metodę.
Liczba klauzul dla ciągu n-bitowego wynosi 4 * C (n, 3) = 4 * n * (n - 1) * (n - 2) / 6 = O (n ^ 3), co oznacza rozmiar hash jest wielomianem wielkości hasła.
Jest to realizacja prototypu w Pythonie tutaj . Generuje wystąpienie problemu 3-SAT z wejściowego ciągu binarnego wprowadzonego przez użytkownika.
Po tym długim wprowadzeniu w końcu moje pytania:
Czy powyższa konstrukcja (zaimplementowana w prototypie) działa jako bezpieczne haszowanie hasła, a przynajmniej wygląda obiecująco, może zostać zmieniona itp.? Jeśli nie, gdzie się nie udaje?
Ponieważ mamy do wyboru 7 klauzul C (n, 3), czy można znaleźć inny sposób na zbudowanie bezpiecznej instancji 3-SAT odpowiedniej do użycia jako skrótu hasła, być może przy pomocy randomizacji?
Czy istnieją podobne prace mające na celu wykorzystanie kompletności NP do zaprojektowania sprawdzonych bezpiecznych schematów mieszania haseł i już przyniosły pewne wyniki (pozytywne lub negatywne)? Niektóre informacje i linki byłyby bardzo mile widziane.
Edytować. Przyjmuję odpowiedź poniżej przez @DW, który jako pierwszy odpowiedział i dał świetny wgląd w strukturę problemu, a także przydatne zasoby. Przedstawiony tutaj naiwny schemat wyboru klauzul (zaimplementowany w prototypie Pythona) nie działał, ponieważ możliwe jest szybkie zawężanie przypisań zmiennych w małych grupach. Jednak problem pozostaje otwarty, ponieważ nie widziałem formalnego dowodu, że takie redukcje NPC do hasła nie działają wcale. Nawet w przypadku tego konkretnego problemu redukcji 3-SAT mogą istnieć różne sposoby wybierania klauzul, których nie chcę tutaj wymieniać. Wszelkie aktualizacje i dyskusje są nadal mile widziane.