Как может быть bcrypt иметь встроенные соли?

Статья Коды Хейл «Как безопасно хранить пароль» утверждает, что:

bcrypt имеет встроенные соли, чтобы предотвратить атаки радужного стола.

Он цитирует этот документ , в котором говорится, что в реализации OpenBSD bcrypt :

OpenBSD генерирует 128-битную соль bcrypt из ключевого streamа arcfour (arc4random (3)), засеянного случайными данными, которое kernel ​​собирает из таймингов устройства.

Я не понимаю, как это может работать. В моей концепции соли:

  • Для каждого сохраненного пароля он должен быть разным, так что отдельная таблица радуги должна быть сгенерирована для каждого
  • Его нужно хранить где-то так, чтобы он повторялся: когда пользователь пытается войти в систему, мы предпринимаем попытку пароля, повторяем ту же соль-hash-процедуру, что и мы, когда мы изначально храним их пароль, и сравниваем

Когда я использую Devise (менеджер входа Rails) с помощью bcrypt, в базе данных нет столбца солей, поэтому я смущен. Если соль случайна и не хранится нигде, как мы можем надежно повторить процесс хеширования?

Короче говоря, как может bcrypt иметь встроенные соли ?

Это bcrypt:

Генерировать случайную соль. Фактор «стоимость» был предварительно настроен. Соберите пароль.

Выведите ключ шифрования из пароля, используя соль и коэффициент затрат. Используйте его для шифрования известной строки. Храните стоимость, соль и шифрованный текст. Поскольку эти три элемента имеют известную длину, их легко конкатенировать и хранить в одном поле, но они могут разделить их позже.

Когда кто-то пытается аутентифицироваться, извлеките сохраненную стоимость и соль. Выведите ключ из пароля ввода, стоимости и соли. Зашифруйте одну и ту же хорошо известную строку. Если сгенерированный текст шифрования соответствует сохраненному зашифрованному тексту, пароль является совпадением.

Bcrypt работает очень похоже на более традиционные схемы, основанные на таких алгоритмах, как PBKDF2. Основное различие заключается в использовании производного ключа для шифрования известного простого текста; другие схемы (разумно) предполагают, что функция деривации ключей необратима и непосредственно сохраняет производный ключ.


Хранимый в базе данных, «hash» bcrypt может выглядеть примерно так:

$ 2a $ 10 $ vI8aWBnW3fID.ZQ4 / zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

Это фактически три поля, разделенные символом «$»:

  • 2a идентифицирует используемую версию алгоритма bcrypt .
  • 10 – коэффициент затрат; 2 10 итераций функции деривации ключа используются (кстати, этого недостаточно. Я бы рекомендовал стоимость 12 или более).
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa – это соль и шифрованный текст, конкатенированные и закодированные в модифицированном Base-64. Первые 22 символа декодируют до 16-байтового значения для соли. Остальные символы – это шифрованный текст для сравнения.

Этот пример взят из документации для rubyовой реализации Coda Hale.

Я считаю, что фраза должна была быть сформулирована следующим образом:

bcrypt имеет соли, встроенные в генерируемые хеши, чтобы предотвратить атаки радужного стола.

Сама утилита bcrypt не поддерживает список солей. Скорее, соли генерируются случайным образом и добавляются к выходу функции, чтобы впоследствии их запоминали (в соответствии с реализацией Java bcrypt ). Иными словами, «хеш», создаваемый bcrypt – это не только хеш. Скорее, это hash и соль сцеплены.

Давайте будем гением компьютера.