Как по строке хеша отличить схему: практическая процедура

· Обновлено: · · Хеш, Безопасность, Пароли, Повторное использование существующих активов, Техническое расследование

История изменений (2 обновлений, последнее 30 Aug 2026)

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

Переведены названия источников в списке литературы. Утверждения статьи не менялись.
Русский текст переписан как полноценный технический перевод, а не калька с японского. Утверждения статьи не менялись.
Первая публикация
Цитирование статьи(DOI (зарегистрированный архив): 10.5281/zenodo.21619828)

Приведённые ниже DOI относятся к ранее зарегистрированным архивным версиям, которые могут отличаться от текущего текста. Для ссылки на текущий текст используйте URL этой страницы.

Го Комура (2026). Как по строке хеша отличить схему: практическая процедура. KomuraSoft LLC. https://comcomponent.com/ru/blog/2026/04/10/000-hash-format-identification/

DOI (зарегистрированный архив)
10.5281/zenodo.21619828
DOI (последняя зарегистрированная версия)
10.5281/zenodo.21619829

Часто смотришь на строку вроде 5f4dcc3b5aa765d61d8327deb882cf99 или $2b$12$... в логах или БД и хочешь понять: «это хеш чего?» При миграции существующих систем, разборе метода аутентификации, анализе логов, интеграции со сторонней системой дело нередко упирается именно сюда.

Опасность здесь — сразу решать только по длине. Увидеть 64 hex-символа и сказать «это SHA-256» — слишком рано. Ту же длину дают стандартный 32-байтовый вывод SHA3-256, SHA-512/256, BLAKE2s-256, BLAKE3. Наоборот, форматы хранения, в которых есть префикс и параметры$2b$, $argon2id$ и им подобные — по одной строке определяются довольно точно.

В этой статье слово hash берём широко: не только message digest вроде MD5 / SHA-2 / SHA-3, но и строковые представления для хранения паролей — bcrypt / scrypt / Argon2 / PBKDF2. Материал собран по официальным источникам, доступным на апрель 2026 года: RFC, NIST, Linux crypt(5), Apache, Django, Spring Security и другие.

Статья рассчитана на тех, кто занимается миграцией существующих систем, разбором аутентификации или анализом логов и хочет отличить, что за «хешеподобная строка» лежит перед ним. Достаточно понимать, что такое шестнадцатеричная запись и Base64.

Процедуру из статьи применяйте только к строкам из среды, которой вы управляете, или из среды, где расследование явно разрешено. Доставать хеши паролей чужих учётных записей или разбирать хеши системы, к которой нет прав, нельзя оправдать даже целью расследования. Команды проверки в конце статьи предполагают тестовую учётную запись или образец, который вы сделали сами.

Содержание

  1. Сначала вывод
  2. Таблица определения с первого взгляда
  3. Практический порядок определения
  4. Частые ошибки определения
  5. Порядок проверки, если нужна стопроцентная уверенность
  6. Итог
  7. Услуги, связанные с этой темой
  8. Источники

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 27, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

1. Сначала вывод

Коротко, до деталей.

  • Форматы хранения с префиксом или разделителями по одной строке определяются довольно точно. Примеры: $argon2id$..., $2b$..., $5$..., $6$..., {SHA}..., pbkdf2_sha256$...

  • Обычная шестнадцатеричная строка или просто Base64 обычно дают только «сузить круг кандидатов». Пример: 32 hex = возможно MD5, но не исключены MD4 или NT-хеш

  • Набор символов важен не меньше длины. Есть + / = — похоже на Base64 по RFC 4648; есть . и разделитель $ — похоже на семейство crypt(3). Такие признаки реально работают.

  • Для стопроцентной уверенности нужен контекст. /etc/shadow, .htpasswd, auth_user в Django или Spring Security — это разные истории.

Иными словами, «схемы, которые можно определить по одной строке» и «схемы, где строка даёт только круг кандидатов» — разные вещи. Уже одно это разделение меняет ход расследования.

2. Таблица определения с первого взгляда

Перед таблицей зафиксируем четыре названия «форматов», которые дальше встречаются рядом, но означают разное.

Термин Полная форма Что обозначает
crypt(3) - Сама функция хеша пароля в Unix. Имя функции библиотеки C; так пишут, потому что она в главе 3 man (библиотечные функции)
crypt(5) - Страница man про строковый формат, который эта функция читает и пишет. Глава 5 man (форматы файлов); запись вида $6$salt$hash описана именно здесь
MCF Modular Crypt Format Разговорное имя записи «в начале ставят $id$ и этим показывают схему». Отдельной спецификации нет: название закрепилось как соглашение, пока росло число реализаций семейства crypt(3)
PHC string format Password Hashing Competition string format Спецификация, которая заново упорядочила MCF. Задаёт даже запись версии и параметров, например $argon2id$v=19$m=65536,t=3,p=4$salt$hash

Грубо: crypt(3) — функция, crypt(5) — спецификация её выходного формата, MCF — разговорное имя этого формата, PHC string format — его же письменная спецификация. Когда в таблицах ниже написано «PHC string format» или «семейство crypt», читайте в этом смысле.

2.1 То, что почти однозначно определяется по префиксу или маркеру формата

«Уверенность» в таблице значит следующее.

  • Высокая: почти можно определить только по строке
  • Средняя: круг кандидатов сильно сужается, но нужно учитывать различия реализаций
  • Низкая: по длине и внешнему виду нельзя утверждать однозначно
Внешний признак Первый кандидат Уверенность Примечание Пример
$argon2id$... Argon2id Высокая PHC string format. Часто дальше идут v=, m=, t=, p= $argon2id$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$uKZLaN6muIyoyIYr5waqw3y+zaDbe9aLSPj6Ln/rbz4
$argon2i$... Argon2i Высокая То же $argon2i$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$Kx1koF/7n8EytGJYTS5krh+ag+FlG5ksM4xOsjOSDvo
$argon2d$... Argon2d Высокая То же $argon2d$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$HLIGA+T1bwK8akx3LGOco+Df+PvxX6cIXhycO7O7t6c
$2a$... / $2b$... / $2y$... bcrypt Высокая Двузначная стоимость + алфавит семейства crypt $2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO
$1$... md5crypt Высокая Unix-формат хранения паролей на MD5 $1$vA7mQ9xZ$Erz32JUFnZ9991KdU5.N3.
$5$... sha256crypt Высокая Это не обычный SHA-256 $5$rounds=5000$N3v8Kx2Lq9Rt$uOTla5GAHaRH2aHlUSjkrZUBCuFiahQZ36O/seB39r3
$6$... sha512crypt Высокая Это не обычный SHA-512 $6$rounds=5000$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1
$7$... scrypt (семейство crypt) Высокая Встречается в реализациях семейства Linux crypt(5) $7$CU..../....k2XAnEHBqQ1Ct2aMXFKNa/$y3Q0e/UlCHacIGWQshgvvz6UIbP.BCja.5BfVWP2Ml8
$y$... yescrypt Высокая Встречается в более новых Linux-системах $y$j9T$k2XAnEHBqQ1Ct2aMXFKNa/$OVYXzjlkiQpWT/F1CUE0JrvV4phLY8FB.ofDttnrSQ7
$apr1$... Apache APR1-MD5 Высокая Часто в .htpasswd $apr1$vA7mQ9xZ$ZE64.ohiyK11sPZmtnJZQ.
{SHA}... Base64-представление digest SHA-1 Высокая Часто в Apache / LDAP {SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE=
{SSHA}... salted SHA-1 Высокая Семейство LDAP {SSHA}/OczD0GNNkOAUPbYhA3L9fjmcyBCbHVlTWVzYTQyIQ==
{MD5}... / {SMD5}... MD5 / salted MD5 Высокая Семейство LDAP {MD5}X03MO1qnZdYdgyfeuILPmQ==
{SMD5}fOn1rOv4ZH0OrO/KT9H0fEJsdWVNZXNhNDIh
pbkdf2_sha256$... PBKDF2-HMAC-SHA256 Средняя–высокая Django и другие: реализация ставит имя формата в начало pbkdf2_sha256$600000$N3v8Kx2Lq9Rt$CLxGB+zTiV1IdOt2y4m9JpaAONzHuRTOd96xKQwRQAs
{bcrypt}$2b$... bcrypt Высокая С обёрткой {id} из Spring Security {bcrypt}$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO
{pbkdf2}... / {scrypt}... Схема с меткой реализации Средняя–высокая Spring Security и подобные; важнее распознать формат обёртки, чем сам алгоритм {pbkdf2}sha256$600000$Qmx1ZU1lc2E0MiE$4eNuai1qNkgs1kXz3+tBUMzAexVsSUz9SrQKEhbk0Cw
{scrypt}ln=14,r=8,p=1$Qmx1ZU1lc2E0MiE$xAgBRhXbMtHB1UHUR0br5bI+1XdXWKbwauiFv5VRQBY

Смысл таблицы: форматы, в которых первые несколько символов несут смысл, определяются надёжно. Строки, разрезанные $...$, с высокой вероятностью относятся к Unix crypt(3) / MCF / PHC, и смотреть на prefix быстрее, чем на длину.

2.2 Таблица, которой сужают кандидатов по длине обычного hex / Base64

Эта таблица — для «голой» строки digest без префикса. Если в записи смешаны :, - или пробелы, сначала уберите разделители и посчитайте длину.

Длина в сырых байтах Число hex-символов Число символов Base64 (с = / без) Основные кандидаты Пример
4 8 8 / 6 Контрольные суммы вроде CRC32 cbf43926
16 32 24 / 22 MD5, MD4, NT-хеш (на базе MD4) 5f4dcc3b5aa765d61d8327deb882cf99
20 40 28 / 27 SHA-1, RIPEMD-160 da39a3ee5e6b4b0d3255bfef95601890afd80709
28 56 40 / 38 SHA-224, SHA-512/224, SHA3-224 d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f
32 64 44 / 43 SHA-256, SHA-512/256, SHA3-256, BLAKE2s-256, вывод BLAKE3 по умолчанию (32 байта) e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
48 96 64 / 64 SHA-384, SHA3-384, BLAKE2b-384 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
64 128 88 / 86 SHA-512, SHA3-512, BLAKE2b-512, Whirlpool cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e

Как читать столбец «Число символов Base64»: здесь рядом стоят два варианта — с padding = и без него. Base64 по RFC 4648 выравнивается по 4 символа, поэтому один или два = в конце появляются только тогда, когда длина в сырых байтах не кратна 3. В JWT и во встраивании в URL = часто отбрасывают, так что у одного и того же digest бывают и 43, и 44 символа. Наоборот, при 48 байтах (кратно 3) padding не возникает, поэтому в таблице стоит 64 / 64. Когда сужаете кандидатов по длине, сверяйтесь с обоими числами.

Главное: совпадение длины не делает схему однозначной. У шестнадцатеричных строк длиной 32 / 64 / 128 символов кандидатов особенно много; вывод только по длине легко промахивается.

2.3 Типичные примеры, в которых легко ошибиться

Как выглядит строка Типичный поспешный вывод Как смотреть на самом деле Пример
5f4dcc3b5aa765d61d8327deb882cf99 Точно MD5 Похоже на MD5, но возможны MD4, NT-хеш или прикладное использование MD5 8846f7eaee8fb117ad06bdd830b7586c
64 hex, вроде 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 Точно SHA-256 SHA-256 — кандидат, но возможны SHA3-256 / SHA-512/256 / BLAKE2s-256 / BLAKE3 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
$6$rounds=5000$salt$hash Hex-представление SHA-512 Нет: это строка password hash sha512crypt $6$rounds=5000$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1
{SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE= Какой-то «SHA» В Apache / LDAP чаще всего digest SHA-1, закодированный в Base64 {SHA}VBPuJHI7uixaa6LQGWx4s+5GKNE=
{bcrypt}$2b$12$... Некая собственная схема {bcrypt} bcrypt с обёрткой Spring Security {bcrypt}$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO

3. Практический порядок определения

Дальше — как смотреть по шагам. Рекомендуемый порядок: prefix → разделитель → набор символов → длина → контекст.

3.1 Сначала смотрим на первые символы

Уже по первым 1–10 символам круг сильно сужается.

  • $argon2id$ / $argon2i$ / $argon2d$ Сильно подозреваем PHC string format Argon2. Составные части удобно смотреть в столбце «Пример» раздела 2.1.

  • $2a$ / $2b$ / $2y$ Сильно подозреваем bcrypt.

  • $1$ / $5$ / $6$ / $7$ / $y$ Подозреваем password hash семейства Unix crypt(3).

  • {SHA} / {SSHA} / {MD5} / {SMD5} Подозреваем представление семейства LDAP / Apache.

  • {bcrypt} / {pbkdf2} / {scrypt} Подозреваем формат хранения с меткой реализации, как в Spring Security.

Приём здесь: смотреть не только на сам алгоритм, но и на формат хранения. Например, $6$ — это не «digest SHA-512», а «строка password hash, которая использует SHA-512». Если их перепутать, дальше расследование поедет не туда.

3.2 Смотрим, сколько разделителей

Дальше смотрим на разделители вроде $, :, {}, ,, =.

  • Несколько $ Подозреваем формат, который вместе хранит параметры, salt и hash. Типичны Argon2, bcrypt, sha256crypt, sha512crypt.

  • Начинается с {name} Подозреваем обёртку с явно названной схемой, как в LDAP / Spring Security.

  • Форма вроде algo:salt:hash или algo$iterations$salt$hash Подозреваем формат фреймворка или приложения. Классика — pbkdf2_sha256$iterations$salt$hash в Django.

Чем больше разделителей, тем легче определить схему. Наоборот, один сплошной кусок hex или Base64 остаётся довольно неопределённым.

3.3 Смотрим на набор символов

Набор символов важен не меньше длины.

Шестнадцатеричное представление

Если строка состоит только из [0-9a-fA-F], сначала подозреваем hex. Тогда число символов ÷ 2 = длина в сырых байтах.

  • 32 hex → 16 байт
  • 40 hex → 20 байт
  • 64 hex → 32 байта
  • 128 hex → 64 байта

Base64 / Base64url по RFC 4648

Есть + / = — сначала подозреваем обычный Base64. Есть - _ — подозреваем Base64url. Padding = иногда опускают, поэтому длина бывает «одной из двух», например 43 / 44, 86 / 88.

radix64 семейства crypt

Если встречаются . и /, да ещё разделитель $...$, естественнее подозревать не обычный Base64, а алфавит семейства crypt. bcrypt, sha256crypt, sha512crypt, md5crypt, yescrypt, scrypt используют именно этот набор символов.

Момент неброский, но очень рабочий. Решить, что «раз есть точка, это сломанный Base64», — лёгкий способ пропустить bcrypt и семейство crypt(3).

3.4 Считаем длину

После набора символов — длина. Логика простая.

  • Для hex: длина в сырых байтах = число символов / 2
  • Для Base64: число символов ≈ 4 × ceil(длина в сырых байтах / 3) Если padding = опущен, строка короче на 0–2 символа

На этом этапе круг кандидатов сужается. Но безопаснее не прыгать от «64 hex» сразу к «точно SHA-256».

3.5 Подтверждаем контекстом

В конце решает контекст. Здесь можно приблизиться к 100%.

  • Лежит в /etc/shadow Подозреваем Linux-форматы password hash: $y$, $6$, $5$, $1$

  • Лежит в .htpasswd Подозреваем семейство Apache: $apr1$, {SHA}, bcrypt

  • Лежит в настройках Django или в auth_user.password Подозреваем форматы Django: pbkdf2_sha256$..., argon2$...

  • Лежит в таблице аутентификации Spring Security Подозреваем форматы с {id}: {bcrypt}..., {pbkdf2}...

  • 32 hex рядом с интеграцией SMB / AD Сильно рассматриваем NT-хеш (на базе MD4)

На практике нередко быстрее посмотреть на продукт, фреймворк или имя файла конфигурации, откуда взялась строка, чем разбирать саму строку.

4. Частые ошибки определения

4.1 Жёстко решать «64 hex = SHA-256»

Так делают очень часто. SHA-256, конечно, сильный кандидат, но тот же 32-байтовый вывод дают несколько схем. SHA3-256, SHA-512/256, BLAKE2s-256, вывод BLAKE3 по умолчанию — той же длины.

Длина — материал для круга кандидатов, а не для окончательного вывода.

4.2 Принимать $6$ за обычный SHA-512

$6$... — префикс sha512crypt. Это не «hex digest SHA-512», а строка password hash, в которой есть salt и rounds.

Аналогично:

  • $5$ — sha256crypt
  • $1$ — md5crypt

Уже сам префикс означает, что перед вами не «просто digest».

4.3 Считать {SHA} «то ли SHA-256, то ли SHA-512»

В контексте Apache или LDAP {SHA} не означает расплывчато «что-то из семейства SHA». В большинстве случаев это digest SHA-1, закодированный в Base64. {SSHA} — salted SHA-1.

Обращаться с {SHA} как с «каким-то SHA» по одному внешнему виду — способ ошибиться в коде проверки и в миграции.

4.4 Считать хеш пароля и хеш содержимого одним и тем же

Обе строки называют «хешем», но назначение разное.

  • digest для проверки целостности файла
  • digest для подписи API
  • строка hash / KDF для хранения пароля

Внешне они похожи, обращаться с ними нужно по-разному. В частности, password hash часто включает в строку salt, rounds, memory cost, parallelism; подход «сравнить сырые digest» здесь не сработает.

4.5 Забывать про XOF и digest переменной длины

SHAKE128 / SHAKE256 — это XOF, длину вывода можно выбирать свободно. У BLAKE2 тоже можно менять длину digest, у BLAKE3 есть extendable output.

То есть вывод «такая длина, значит такая схема» промахивается, если слишком опирается на классический digest фиксированной длины.

4.6 Считать «NTLM» и «NT-хеш» одним и тем же

Это вопрос терминов, но в расследованиях вокруг Windows / AD он очень важен.

  • NT-хеш: пароль кодируют в UTF-16LE и пропускают через MD4; получается 16-байтовое значение. На письме это 32 hex, например 8846f7eaee8fb117ad06bdd830b7586c. В спецификации это NTOWFv1(Passwd, User, UserDom) = MD4(UNICODE(Passwd)). Определение дословно приведено в пункте NTLM v1 Authentication документа MS-NLMP — источник 13 в конце статьи.
  • NTLM: имя протокола аутентификации, который берёт это значение как ключ и делает challenge / response. Это не имя формата строки.

В разговоре «NTLM-хеш» тоже поймут, но в таблицу определения точнее писать NT-хеш (на базе MD4). Если разделить эти два смысла, не смешаются определение формата («эти 32 hex — MD5 или NT-хеш?») и разговор про протокол («этот обмен — NTLM или Kerberos?»).

У NT-хеша нет salt. Один и тот же пароль всегда даёт одни и те же 32 hex, поэтому сама картина «в таблице из AD лежат 32 hex без salt» уже подсказка.

5. Порядок проверки, если нужна стопроцентная уверенность

При миграции или стыковке аутентификации в конце концов нужна определённость. Тогда смотреть в таком порядке — меньше шансов ошибиться.

5.1 Определить источник хранения

Сначала устанавливаем, откуда строка.

  • Linux shadow?
  • basic auth Apache / Nginx?
  • LDAP?
  • Django / Spring Security?
  • БД собственного приложения?

Часто спецификация источника сильнее, чем сама строка.

5.2 Искать в официальной документации именно «формат хранения»

Дальше ищем не имя алгоритма, а формат хранения.

  • Django password format
  • Spring Security password storage format
  • crypt(5) sha512crypt format
  • Apache htpasswd password formats

Искать по словам format / storage / encoding обычно быстрее.

5.3 Если есть известный открытый текст — сверить с кандидатами напрямую

Есть тестовая учётная запись или известный открытый текст — быстрее всего посчитать значение по каждой кандидатной схеме и сравнить. Для password hash при этом нужно достать salt и rounds из строки и пересчитать.

Шаблон один и тот же, три шага для любой схемы.

  1. Достать salt и параметры из строки
  2. Пересчитать известный открытый текст с теми же salt и параметрами
  3. Посмотреть, полностью ли совпадает получившаяся строка с исходной

Проверяем digest без префикса

Сначала «просто digest». Хватает стандартной библиотеки Python 3.

# Python 3.8+ / только стандартная библиотека
import base64
import hashlib

target = "5f4dcc3b5aa765d61d8327deb882cf99"   # строка, которую определяем
plain = b"password"                            # известный открытый текст

for name in ("md5", "sha1", "sha256", "sha512", "sha3_256", "blake2s"):
    digest = hashlib.new(name, plain).digest()
    if digest.hex() == target.lower():
        print("совпало hex:", name)
    if base64.b64encode(digest).decode() == target:
        print("совпало base64:", name)

В этом примере печатается совпало hex: md5. Базовая форма — поставить в for те схемы, которые вынесли в кандидаты в таблице 2.2.

Если захотите проверить NT-хеш, пишут что-то вроде hashlib.new("md4", "password".encode("utf-16-le")), но в Python, собранном с OpenSSL 3, legacy provider по умолчанию выключен, поэтому бывает unsupported hash type md4. Это лучше заранее проверить на своей машине.

Проверяем password hash семейства crypt

$1$ / $5$ / $6$ / $apr1$ можно пересчитать, передав salt в openssl passwd. Примеры из таблицы 2.1 воспроизводятся именно так.

# OpenSSL 3.x
openssl passwd -6 -salt N3v8Kx2Lq9Rt password
# $6$N3v8Kx2Lq9Rt$6LUcSUAELX3aC/.60pTB.TFLTQi1mOGRCwKqNCqtRSaXjorxj01HJ9oNni97Kci1uDt7a/Kn4t3OS20Dw/.vi1

openssl passwd -5 -salt N3v8Kx2Lq9Rt password    # sha256crypt
openssl passwd -1 -salt vA7mQ9xZ password        # md5crypt
openssl passwd -apr1 -salt vA7mQ9xZ password     # Apache APR1-MD5

Если вывод совпал с проверяемой строкой, в этот момент подтверждаются и схема, и открытый текст. Если в строке есть rounds=, это значение тоже нужно передать. $6$rounds=5000$... — значение по умолчанию, поэтому с явным указанием и без него digest один и тот же; если же стоит, например, rounds=100000 и это не значение по умолчанию, считать нужно обязательно с ним.

На Debian / Ubuntu то же самое умеет mkpasswd из пакета whois (вид mkpasswd -m sha512crypt -S N3v8Kx2Lq9Rt password).

Проверяем bcrypt и Argon2

У bcrypt и Argon2 salt закодирован собственным алфавитом, поэтому надёжнее не вырезать его вручную, а отдать строку целиком в verify библиотеки.

# pip install "passlib[bcrypt]" argon2-cffi
from passlib.hash import argon2, bcrypt

samples = [
    (bcrypt, "$2b$12$9YQ2u/e5Y/ArOnG.gJKxK.0makLATcYLP1q.Nsabzrw7XErYCfoYO"),
    (argon2, "$argon2id$v=19$m=65536,t=3,p=4$MDEyMzQ1Njc4OWFiY2RlZg$uKZLaN6muIyoyIYr5waqw3y+zaDbe9aLSPj6Ln/rbz4"),
]

for handler, stored in samples:
    # identify — тот ли это формат; verify — совпадает ли открытый текст
    print(handler.name, handler.identify(stored), handler.verify("password", stored))

verify сам читает cost, rounds и salt из строки и пересчитывает, поэтому доставать параметры вручную не нужно. В примере bcrypt открытый текст — password, поэтому вернётся True.

Модуль crypt из стандартной библиотеки Python объявлен нерекомендуемым и удалён в Python 3.13. Если на 3.13 и новее нужно работать с семейством crypt, опирайтесь на openssl passwd или на passlib.

5.4 Перевести кандидатную схему в номер hashcat или имя john

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

Внешний вид Схема Режим hashcat (-m)
32 hex MD5 0
32 hex (из AD) NT-хеш 1000
40 hex SHA-1 100
64 hex SHA-256 1400
128 hex SHA-512 1700
$1$... md5crypt 500
$apr1$... Apache APR1-MD5 1600
$2a$ / $2b$ / $2y$ bcrypt 3200
$5$... sha256crypt 7400
$6$... sha512crypt 1800
pbkdf2_sha256$... Django PBKDF2-HMAC-SHA256 10000
формат хранения семейства scrypt scrypt 8900

Номера режимов растут от версии к версии, поэтому для более новых схем вроде Argon2 или yescrypt сверяйтесь со списком в справке той hashcat, которая стоит у вас.

John the Ripper задаёт схему не числом, а именем. В базовой сборке (1.8.0) доступны descrypt, bsdicrypt, md5crypt, bcrypt, LM, AFS, tripcode, dummy, crypt; большая часть остальных добавляется в jumbo. Если нужного имени нет в базовой сборке, смотрите документацию jumbo.

Ещё раз: эти инструменты используйте только против своей среды или среды, где расследование разрешено.

5.5 Проверить код реализации или конфигурацию

Если исследуемая система своя, в конце надёжнее всего посмотреть код и конфигурацию.

  • используемая библиотека
  • настройки фреймворка
  • опции на этапе генерации
  • способ кодирования вывода (hex / Base64 / Base64url / алфавит crypt)

Обычно на этом вопрос закрывается.

5.6 На будущее — хранить с меткой схемы

Если систему проектируете вы, формат, который встраивает имя схемы в строку, сильно облегчит будущую миграцию.

  • PHC string format Argon2
  • {id}encodedPassword в Spring Security
  • algo$iterations$salt$hash в Django
  • форматы семейства Unix crypt(3) с префиксом

Тогда тому, кто будет смотреть позже, проще не заблудиться. Наоборот, класть в БД «просто 64 hex» к будущему себе недоброжелательно.

6. Итог

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

  1. Есть ли prefix
  2. Какие разделители
  3. Какой набор символов
  4. Скольким байтам соответствует длина
  5. Каков контекст источника хранения

Важнее всего два пункта.

  • Форматы хранения с префиксом определяются довольно точно
  • Обычный hex / Base64 чаще дают только круг кандидатов

Поэтому на практике решение такое.

  • Для $argon2id$..., $2b$..., $6$..., {SHA}..., pbkdf2_sha256$... одной строки уже достаточно, чтобы сильно продвинуться
  • Для просто 32 / 40 / 64 / 128 hex думаем «сужаем кандидатов», а не «выносим вердикт»
  • Если действительно нужна определённость, смотрим продукт-источник, конфигурацию и реализацию

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

7. Услуги, связанные с этой темой

Техническая консультация и ревью архитектуры

Определить схему хеша пароля, оставшегося в существующей БД, спланировать миграцию платформы аутентификации, разобрать логи смешанной системы Windows / Web — для этого нужно упорядочить не только внешний вид строки, но и реализацию источника, и политику миграции. Если смотреть целиком, от определения схемы до проектирования миграции, ошибок обычно меньше.

Расследование сбоев и анализ причин

Нередки расследования, которые упираются в «непонятно, что это за строка, и проверка не движется». Если отделить, где именно задаётся схема — в логах, файлах конфигурации, схеме БД или в коде приложения, — причина находится заметно быстрее.

8. Источники

  1. RFC 1321 - The MD5 Message-Digest Algorithm
  2. NIST FIPS 180-4 - Secure Hash Standard (SHA-1, SHA-2, SHA-512/224, SHA-512/256)
  3. NIST FIPS 202 - SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions
  4. PHC string format specification
  5. Argon2 reference implementation
  6. RFC 7693 - The BLAKE2 Cryptographic Hash and Message Authentication Code (MAC)
  7. BLAKE3 C README - default output length and extendable output
  8. crypt(5) - prefixes and hashed passphrase formats
  9. Apache HTTP Server 2.4 - Password Formats
  10. slappasswd(8) - RFC 2307 schemes such as {SHA} and {SSHA}
  11. Django documentation - example of pbkdf2_sha256$...
  12. Spring Security - DelegatingPasswordEncoder storage format {id}encodedPassword
  13. MS-NLMP: NTLM v1 Authentication - NTOWFv1(Passwd, User, UserDom) = MD4(UNICODE(Passwd))
  14. hashcat wiki - example hashes(список режимов)
  15. John the Ripper - command line options(имена для --format=NAME
  16. passlib - PasswordHash API(identify и verify
  17. openssl-passwd(1) - -1 / -apr1 / -5 / -6 и -salt

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

Политика аудита безопасности Windows и расследование журнала событий на практике — как стать ИТ-службой, которая умеет читать 4625

Практическое руководство, чтобы ответить на просьбу «посмотрите журналы неудачных входов». Разбирает связь базовой и расширенной политики...

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

В каком порядке смотреть, чтобы отличить схему по строке хеша?
Удобнее идти в порядке prefix → разделитель → набор символов → длина → контекст. Форматы, в которых первые несколько символов несут смысл, определяются легко: $argon2id$ — сильно подозреваем Argon2, $2b$ — bcrypt, $5$ — sha256crypt, $6$ — sha512crypt. Наоборот, обычный hex или Base64 без префикса позволяют лишь сузить круг кандидатов, поэтому окончательно схему подтверждают по продукту-источнику, фреймворку и конфигурации.
Можно ли утверждать, что 64-символьная шестнадцатеричная строка — это SHA-256?
Утверждать опасно. SHA-256 — сильный кандидат, но тот же 32-байтовый вывод дают SHA3-256, SHA-512/256, BLAKE2s-256, вывод BLAKE3 по умолчанию и другие схемы; по одной длине их не различить. Длина — материал для круга кандидатов, а не для окончательного вывода. Если нужна определённость, придётся дойти до спецификации источника, формата хранения в официальной документации, сверки с известным открытым текстом и проверки кода реализации или конфигурации.
Строка, которая начинается с $6$, — это хеш SHA-512?
Нет. $6$ — префикс Unix-формата хранения паролей sha512crypt. Это не hex digest SHA-512 как таковой, а строка хеша пароля, в которой есть salt и rounds. Аналогично $5$ — sha256crypt, $1$ — md5crypt. Уже сам префикс означает, что перед вами не «просто digest»; если их перепутать, разъедутся миграция и код проверки.
Что можно понять по набору символов в строке?
Набор символов — такая же важная подсказка, как длина. Если встречаются только символы 0-9a-fA-F, это шестнадцатеричное представление, и половина числа символов — длина в сырых байтах. + / = говорят о Base64 по RFC 4648, - и _ — о Base64url. Если есть точка и слэш, а разделитель — $, естественнее подозревать не обычный Base64, а алфавит семейства crypt, как у bcrypt или sha512crypt. Принять строку с точкой за «сломанный» Base64 — значит пропустить форматы crypt.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

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

Публичные ссылки

Вернуться в блог