Краткая история bcrypt: от blowfish до современных реализаций

В конце 1990-х годов проблема безопасного хранения паролей уже была очевидной: традиционные криптографические хеш-функции, такие как MD5 и SHA-1, проектировались для скорости, а не для устойчивости к перебору. Быстрое вычисление, являвшееся преимуществом для проверки целостности данных, становилось уязвимостью в контексте защиты паролей.

На этом фоне особое внимание привлек алгоритм шифрования Blowfish, разработанный Брюсом Шнайером в 1993 году. Blowfish представлял собой симметричный блочный шифр с переменной длиной ключа и сложной процедурой инициализации ключевого расписания. Ключевая особенность — значительное время, требуемое для генерации внутреннего состояния (key setup), что делало его интересным кандидатом для задач, где важна вычислительная «дороговизна».

Eksblowfish: адаптация Blowfish для хеширования

В 1999 году Нильс Провос и Дэвид Мазьерес предложили алгоритм bcrypt, основанный на модифицированной версии Blowfish — Eksblowfish (expensive key schedule Blowfish). Основная идея заключалась в намеренном усложнении процесса инициализации ключа.

В классическом Blowfish ключ используется для генерации P-массивов и S-блоков. В Eksblowfish этот процесс повторяется многократно, причём в качестве входных данных используются:

  • пароль пользователя
  • соль (salt)
  • параметр стоимости (cost factor)

Таким образом, вычисление хеша становится управляемо медленным процессом.

Введение bcrypt: алгоритм адаптивного хеширования

bcrypt был представлен как часть системы OpenBSD для безопасного хранения паролей. Его ключевые характеристики:

  • Адаптивность — параметр cost определяет количество итераций (2^cost), позволяя увеличивать сложность по мере роста вычислительных мощностей
  • Использование соли — предотвращает атаки с использованием радужных таблиц
  • Медленная функция — делает перебор паролей затратным по времени

Структура bcrypt-хеша включает:

  • версию алгоритма (например, $2a$, $2b$)
  • параметр cost
  • соль
  • результат хеширования

Пример:

$2b$10$eImiTXuWVxfM37uY4JANjQ==Xq7vV9kK8P5s6z3v9w0qZcY1FZC1K

Эволюция версий: исправления и улучшения

Со временем в bcrypt были обнаружены и устранены различные проблемы, что привело к появлению нескольких версий:

  • 2a — оригинальная версия, использовалась в OpenBSD
  • 2x и 2y — введены в PHP для устранения бага, связанного с обработкой 8-битных символов
  • 2b — актуальная версия, исправляющая ошибки переполнения буфера

Эти различия важны при реализации, так как несовместимость форматов может привести к невозможности проверки пароля.

Проблемы и ограничения bcrypt

Несмотря на широкое распространение, bcrypt имеет ряд ограничений:

  • Ограничение длины пароля — учитываются только первые 72 байта
  • Отсутствие защиты от атак с использованием GPU/ASIC — алгоритм не является memory-hard
  • Фиксированная структура — сложнее адаптировать под новые угрозы по сравнению с более современными алгоритмами

Тем не менее, благодаря своей адаптивности и проверенной временем архитектуре, bcrypt остаётся актуальным выбором для многих систем.

Появление bcrypt.js: перенос в экосистему JavaScript

С развитием Node.js и браузерных приложений возникла потребность в реализации bcrypt на JavaScript. Так появилась библиотека bcrypt.js — чистая реализация алгоритма без использования нативных модулей.

Особенности bcrypt.js:

  • полностью написан на JavaScript
  • работает в Node.js и браузере
  • не требует компиляции или установки зависимостей на уровне системы
  • обеспечивает совместимость с оригинальным bcrypt

Однако из-за отсутствия нативной оптимизации bcrypt.js работает медленнее, чем реализации на C/C++ (например, bcrypt для Node.js). Это может быть как недостатком, так и преимуществом — в контексте клиентских приложений дополнительная задержка может повысить безопасность.

Современное положение bcrypt

bcrypt остаётся одним из наиболее распространённых алгоритмов хеширования паролей, наряду с PBKDF2, scrypt и Argon2. Его простота, адаптивность и широкая поддержка делают его удобным выбором для большинства задач.

В контексте JavaScript bcrypt.js играет важную роль, обеспечивая переносимость и доступность криптографических механизмов в средах, где использование нативных модулей ограничено.

Развитие вычислительных мощностей и появление специализированного оборудования продолжают оказывать давление на алгоритмы хеширования, однако архитектурные решения, заложенные в bcrypt ещё в конце XX века, по-прежнему обеспечивают приемлемый уровень защиты при корректной настройке параметров.