Хеши, создаваемые bcrypt, имеют строго определённый формат:
$2<version>$<cost>$<salt><hash>
Где:
2 — базовый идентификатор алгоритма bcrypt<version> — версия реализации<cost> — фактор сложности (logarithmic cost
factor)salt — соль (22 символа в модифицированном base64)hash — итоговый 184-битный результатКлючевой элемент для понимания совместимости — именно версия алгоритма, которая влияет на обработку входных данных и безопасность вычислений.
Версия $2a$ стала одной из первых широко
распространённых реализаций bcrypt. Она базируется на оригинальном
Blowfish-деривативе и долгое время считалась стандартом де-факто.
Критическая проблема $2a$ связана с некорректной
обработкой Unicode-символов в ранних реализациях некоторых
библиотек:
\0) возможны
неоднозначностиВерсия $2b$ была введена как исправление дефектов
$2a$, обнаруженных в обработке длины входных данных и
некоторых краевых случаев при работе с бинарными строками.
Ключевое исправление связано с обработкой длины:
$2a$ длина строки могла быть интерпретирована
некорректно при определённых значениях$2b$ корректно обрабатывает длину до 72 байт как
строгий лимит входаНа текущий момент $2b$ считается наиболее безопасной и
стандартной версией bcrypt, используемой в современных библиотеках,
включая bcrypt.js и bcrypt для Node.js.
Версия $2y$ появилась в результате особенностей
реализации bcrypt в некоторых системах (в частности, в старых сборках
для PHP и совместимых средах). Она не вводит криптографических изменений
алгоритма.
$2y$ является по сути совместимым идентификатором для
обхода проблем интерпретации байтов в определённых языковых средах, где
$2a$ обрабатывался некорректно.
$2a$Все версии:
Криптографически:
$2a$ = базовая реализация$2b$ = исправленная и стандартизированная версия$2y$ = идентичен $2a$ по алгоритму| Версия хеша | Может проверяться как 2a | 2b | 2y |
|---|---|---|---|
| 2a | да | да | иногда |
| 2b | да | да | да |
| 2y | да | да | да |
На практике большинство современных библиотек:
$2b$В JavaScript-реализации bcrypt.js:
$2b$compare) поддерживает $2a$,
$2b$, $2y$Разделение на $2a$, $2b$, $2y$
не связано с эволюцией криптографической стойкости. Оно возникло
из-за:
С точки зрения криптографии:
$2b$ устраняет реализационные ошибки, которые могли
приводить к некорректным результатамКлючевой риск старых версий связан не с математикой алгоритма, а с интерпретацией входных данных.
В реальных приложениях:
$2b$ происходит постепенно при
пересохранении паролейТипичный сценарий:
$2a$ или $2y$
хеш$2b$$2a$ — историческая версия, с известными ограничениями
обработки входных данных$2b$ — исправленная и текущая стандартная версия
bcrypt$2y$ — совместимый маркер для специфических реализаций,
не изменяющий алгоритмАлгоритмическая база у всех версий остаётся одинаковой: различия находятся исключительно в интерпретации входных строк и совместимости между платформами.