Загальновживані алгоритми хешування паролів працюють так, як сьогодні: соліть пароль і подайте його в KDF. Наприклад, використовуючи PBKDF2-HMAC-SHA1, процес переміщення пароля є DK = PBKDF2(HMAC, Password, Salt, ...)
. Оскільки HMAC - це 2-х кругле хешування з м'якими клавішами, а SHA1 - це серія перестановок, зсувів, обертання та побітових операцій, по суті, весь процес є деякими базовими операціями, організованими певним чином. Принципово не очевидно, наскільки важко їм насправді обчислити. Напевно, тому односторонні функції все ще є вірою, і ми побачили, що деякі історично важливі криптографічні хеш-функції стали небезпечними та застарілими.
Мені було цікаво, чи можна використовувати NP повних проблем для хеш-паролів абсолютно новим способом, сподіваючись дати йому більш міцну теоретичну основу. Ключова ідея: припустимо, що P! = NP (якщо P == NP, тоді не існує OWF, так що поточні схеми також не розбиваються), оскільки проблема NPC означає, що відповідь легко перевірити, але важко обчислити. Ця властивість добре відповідає вимогам хешування паролів. Якщо ми розглядаємо пароль як відповідь на проблему NPC, ми можемо зберігати проблему NPC як хеш пароля для протидії офлайн-атакам. Це легко перевірити пароль, але важко зламати.
Зауважте, той самий пароль може бути відображений у декількох екземплярах проблеми NPC, напевно, не всі їх важко вирішити. В якості першого кроку в цьому дослідженні я намагався інтерпретувати бінарний рядок як відповідь на проблему 3-SAT і побудувати екземпляр проблеми 3-SAT, для вирішення якої є двійкова рядок. У своїй найпростішій формі двійковий рядок має 3 біти: x_0, x_1, x_2. Тоді є 2 ^ 3 == 8 статей:
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) )
Припустимо, двійковий рядок дорівнює 000. Тоді лише 1 із 8 пропозицій є помилковим (перший). Якщо ми відкинемо перший пункт та AND, що залишилися 7, то 000 - це рішення отриманої формули. Отже, якщо ми зберігаємо формулу, то можемо перевірити 000.
Проблема полягає в тому, що для 3-бітового рядка, якщо ви бачите там 7 різних пропозицій, ви моментально знаєте, який з них відсутній, і це виявить біти.
Тож пізніше я вирішив відкинути 3 з них, залишивши лише 4, позначені 001, 010, 100 та 111. Це іноді призводить до зіткнень, але робить вирішення проблеми менш тривіальним. Зіткнення не завжди бувають, але чи точно вони зникнуть, коли вхід має більше бітів, поки не відомо.
Редагувати. У загальному випадку, коли двійковий рядок може бути будь-яким із (000, 001, ..., 111), все ж є 8 пропозицій, де 7 є істинними, а 1 - помилковими. Виберіть 4 пункти, які дають значення істини (001, 010, 100, 111). Це відображено в реалізації прототипу нижче.
Редагувати. Як відповідь, представлена нижче @DW, цей спосіб вибору застережень все ще може призвести до занадто великої кількості пропозицій щодо заданого набору змінних, що дозволяє швидко звузити їх значення. Існують альтернативні методи вибору застережень серед загальних пропозицій 7 * C (n, 3). Наприклад: Виберіть іншу кількість пропозицій із заданого набору змінних і зробіть це лише для суміжних змінних ((x_0, x_1, x_2), (x_1, x_2, x_3), (x_2, x_3, x_4), .. .) і таким чином утворюють цикл замість кліки. Цей метод, ймовірно, не працює, тому що інтуїтивно ви можете спробувати завдання, використовуючи індукцію, щоб перевірити, чи всі умови можуть бути виконані. Тож для спрощення пояснення загальної структури давайте просто скористаємося поточним методом.
Кількість пропозицій для n-розрядних рядків становить 4 * C (n, 3) = 4 * n * (n - 1) * (n - 2) / 6 = O (n ^ 3), що означає розмір хеш - поліном розміру пароля.
Там є реалізація прототипу в Python тут . Він генерує проблемний екземпляр 3-SAT з введеного користувачем бінарного рядка.
Після цього тривалого вступу нарешті мої запитання:
Чи працює вищезгадана конструкція (як це реалізовано в прототипі) як захищене хешування паролів, або, принаймні, перспективне, може бути переглянуто тощо? Якщо ні, то де це не вдається?
Оскільки у нас є пункти 7 * C (n, 3) на вибір, чи можливо знайти інший спосіб побудувати захищений 3-SAT-примірник, придатний для використання в якості хешу паролів, можливо, за допомогою рандомізації?
Чи є якась подібна робота, яка намагається використовувати повноту NP для створення перевірених схем безпечного пароля, і вже отримали певні результати (позитивні чи негативні)? Деякі вступи та посилання дуже вітаються.
Редагувати. Я прийняв би відповідь нижче від @DW, який першим відповів і дав чудові уявлення про структуру проблеми, а також корисні ресурси. Створена тут схема набору наївних пропозицій (як це реалізовано в прототипі Python), здається, не працює, тому що можна швидко звузити змінні призначення в малих групах. Однак проблема залишається відкритою, оскільки я не бачив офіційного підтвердження, що показувало б такі скорочення NPC-до-пароля взагалі не працюватимуть. Навіть для цієї конкретної проблеми зменшення 3-SAT можливі різні способи вибору пунктів, які я не хочу тут перераховувати. Тож будь-які оновлення та обговорення все ще дуже вітаються.