Глава 88 · Поддержка старого проекта
Mhash: полный справочник старого API и перенос на Hash
Все пять функций и 39 констант Mhash: диагностика deprecation, бинарный формат, HMAC, Salted S2K и проверяемая миграция.
Старый экспорт перестал работать: сначала разберём, что он вычислял
Сохранить старый формат при переходе на Hash
Старая интеграция подписывает одно сообщение Mhash. Для обновления важны те же байты, алгоритм и представление результата.
- Сообщение abc
Фиксируем точные входные байты и отсутствие HMAC-ключа.
- MHASH_SHA256
Старый вызов возвращает 32 raw-байта SHA-256.
- hash('sha256', …, true)
Современный вызов с true тоже возвращает raw-байты.
- Сравнение fixture
Сначала проверяем совпадение результата; смена алгоритма или формата — отдельное изменение протокола.
Mhash устарел. Для нового протокола выбирают подходящий современный Hash, а пароли пользователей обрабатывают специальным Password Hashing.
Вы открыли модуль обмена старого магазина и встретили mhash(MHASH_SHA256, $data). Нужно обновить PHP, сохранив чтение старых файлов и подписи партнёра. Первая задача — понять входные байты, алгоритм и формат результата. Переименование функции без этой проверки может сломать обмен даже при правильном новом алгоритме.
- Старый пример: зафиксировать сообщение и ожидаемые байты
- Узнать digest или HMAC, вариант алгоритма и raw/hex/base64
- Выполнить соответствующий Hash-вызов на той же fixture
- Совпадение → перенос API; смена алгоритма → отдельная версия протокола
Начнём с современного простого вызова без устаревших конструкций. hash — имя функции. В скобках "sha256" выбирает алгоритм, "abc" передаёт сообщение. Знак = сохраняет результат в переменной. По умолчанию результат hash — печатная строка hex, а echo выводит её.
<?php
declare(strict_types=1);
$digest = hash('sha256', 'abc');
echo $digest, "\n";
echo strlen($digest), "\n";
Ожидаемый результат
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
64
Вход здесь вымышленный и несекретный. digest помогает сопоставить содержимое, но без доверенного ожидаемого значения сам не подтверждает автора сообщения. Один hex-символ кодирует четыре бита; два — один байт.
Исторический Mhash использует числовые константы алгоритмов и возвращает raw-байты. Все его функции исследуются ниже с измеримым результатом. Если старого формата в проекте нет, используйте полный современный Hash; для аккаунтов — хеширование паролей. Не нужно осваивать legacy API перед написанием первого сайта.
Для дальнейших опытов понадобятся вызовы функций, строки и байты, условия и циклы. Для диагностической обвязки ниже полезны анонимные функции и обработка сообщений PHP.
Где находится Mhash и почему extension_loaded вводит в заблуждение
Современная PHP предоставляет Mhash как слой совместимости расширения Hash; отдельная внешняя библиотека libmhash для этого слоя не требуется. С PHP 7.0 Mhash полностью интегрирован в Hash и больше не регистрируется самостоятельным расширением. Поэтому extension_loaded("mhash") и поиск имени в get_loaded_extensions не являются проверкой доступности mhash().
- Нужный процесс PHP: CLI или веб-SAPI
- function_exists("mhash") → есть ли совместимость
- Hash доступен, но Mhash мог не включаться при сборке
- Планируем перенос на hash_*, а не добавляем случайную DLL
<?php
declare(strict_types=1);
var_dump(extension_loaded('hash'));
var_dump(extension_loaded('mhash'));
var_dump(function_exists('mhash'));
var_dump(defined('MHASH_SHA256'));
Ожидаемый результат
bool(true)
bool(false)
bool(true)
bool(true)
Это фактический вывод проверенной PHP 8.5.11. false для имени расширения не противоречит доступности функции. defined только проверяет существование имени; чтение самой устаревшей константы отдельно создаёт diagnostic.
| Официальный узел | Правило установки |
|---|---|
| Requirements | Внешняя библиотека не нужна: функции предоставляет совместимость Hash. |
| Installation | Для включения совместимости при сборке указан --with-mhash. Этот configure-параметр устарел с PHP 8.1 и предупреждает при сборке. |
| Hash и готовые дистрибутивы | Hash всегда доступен в современном PHP, но наличие mhash* проверяется отдельно. У Windows/готового пакета состав определяется сборщиком; строка extension=mhash не является универсальным решением. |
| Настройка процесса | У семейства нет отдельной страницы runtime configuration или своего набора INI-настроек. CLI и веб-сервер могут запускать разные бинарники и конфигурации. |
Не применяйте старые советы «установить php5-mhash» или добавить mhash.so к PHP 8.5 без понимания версии и сборки. Для планового обновления сначала подготовьте замену API, контрольные примеры и проверку сохранённых данных. Закрытая диагностика окружения должна выполняться именно там, где запускается интеграция, а не на другом компьютере.
Как читать E_DEPRECATED в учебных примерах
Устаревший вызов в PHP 8.5 может дать правильный результат и одновременно сообщить о необходимости миграции. Это не один взаимоисключающий исход «сработало или ошибка». В примерах явно учитываются E_DEPRECATED от функций mhash* и констант MHASH_*, а остальные сообщения остаются обычной обработке PHP.
- PHP сообщает об устаревшем символе
- Лабораторный обработчик отмечает это сообщение
- Функция возвращает результат либо отказывает по своим правилам
- finally восстанавливает обработчик, последняя строка сообщает о deprecation
Обвязка использует set_error_handler(function (...) {...}): передаёт PHP функцию, которую следует вызвать при сообщении. use (&$legacyNotice) позволяет ей изменить флаг снаружи. Она возвращает true только для ожидаемого сообщения Mhash, false — передаёт другие сообщения обычному механизму. try/finally обеспечивает восстановление обработчика после опыта. Это уже вспомогательный приём; сам исследуемый вызов находится внутри try.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$digest = mhash(MHASH_SHA256, 'abc');
echo strlen($digest), "\n";
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
32
Устаревший API: да
Последняя строка вывода показывает, что ожидаемое предупреждение было замечено. Счётчик всех предупреждений не нужен: число чтений констант и вызовов зависит от примера. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
В приложении следует сохранять диагностические сообщения в закрытом журнале и устранять зависимость. Не переносите лабораторный перехват в production как «исправление», не выключайте E_ALL и не добавляйте @ перед каждым вызовом. Ключи, пароли и полные HTTP payload не нужны в журнале deprecation. В отличие от современных hash_hmac/password_hash, старые сигнатуры mhash и mhash_keygen_s2k в PHP 8.5 не помечают секретный аргумент SensitiveParameter: не рассчитывайте на автоматическое скрытие в трассировке.
Все 39 констант: точное соответствие современным именам
Константы MHASH_* имеют тип int, доступны только при включённом слое совместимости и все устарели с PHP 8.5. Таблица фиксирует соответствия PHP 8.5.11; она нужна для миграции, а не для выбора алгоритма по порядковому номеру. Числа полезны при чтении старого сохранённого формата, но новый код использует имена Hash.
- MHASH_HAVAL256 → ID 3
- Старая таблица указывает haval256,3
- Hash-вызов сохраняет этот вариант
- Смена варианта означает другой digest
| Старое имя и ID | Точное имя Hash | Версия / назначение |
|---|---|---|
MHASH_CRC32 · ID 0 | crc32 | Исторический API; Некриптографический checksum/хеш |
MHASH_MD5 · ID 1 | md5 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_SHA1 · ID 2 | sha1 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_HAVAL256 · ID 3 | haval256,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_RIPEMD160 · ID 5 | ripemd160 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_TIGER · ID 7 | tiger192,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_GOST · ID 8 | gost | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_CRC32B · ID 9 | crc32b | Исторический API; Некриптографический checksum/хеш |
MHASH_HAVAL224 · ID 10 | haval224,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_HAVAL192 · ID 11 | haval192,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_HAVAL160 · ID 12 | haval160,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_HAVAL128 · ID 13 | haval128,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_TIGER128 · ID 14 | tiger128,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_TIGER160 · ID 15 | tiger160,3 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_MD4 · ID 16 | md4 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_SHA256 · ID 17 | sha256 | Исторический API; Криптографический digest; назначение зависит от протокола |
MHASH_ADLER32 · ID 18 | adler32 | Исторический API; Некриптографический checksum/хеш |
MHASH_SHA224 · ID 19 | sha224 | Исторический API; Криптографический digest; назначение зависит от протокола |
MHASH_SHA512 · ID 20 | sha512 | Исторический API; Криптографический digest; назначение зависит от протокола |
MHASH_SHA384 · ID 21 | sha384 | Исторический API; Криптографический digest; назначение зависит от протокола |
MHASH_WHIRLPOOL · ID 22 | whirlpool | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_RIPEMD128 · ID 23 | ripemd128 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_RIPEMD256 · ID 24 | ripemd256 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_RIPEMD320 · ID 25 | ripemd320 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_SNEFRU256 · ID 27 | snefru256 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_MD2 · ID 28 | md2 | Исторический API; Исторический вариант; не выбор защиты по одному имени |
MHASH_FNV132 · ID 29 | fnv132 | Исторический API; Некриптографический checksum/хеш |
MHASH_FNV1A32 · ID 30 | fnv1a32 | Исторический API; Некриптографический checksum/хеш |
MHASH_FNV164 · ID 31 | fnv164 | Исторический API; Некриптографический checksum/хеш |
MHASH_FNV1A64 · ID 32 | fnv1a64 | Исторический API; Некриптографический checksum/хеш |
MHASH_JOAAT · ID 33 | joaat | Исторический API; Некриптографический checksum/хеш |
MHASH_CRC32C · ID 34 | crc32c | PHP 7.4+; Некриптографический checksum/хеш |
MHASH_MURMUR3A · ID 35 | murmur3a | PHP 8.1+; Некриптографический checksum/хеш |
MHASH_MURMUR3C · ID 36 | murmur3c | PHP 8.1+; Некриптографический checksum/хеш |
MHASH_MURMUR3F · ID 37 | murmur3f | PHP 8.1+; Некриптографический checksum/хеш |
MHASH_XXH32 · ID 38 | xxh32 | PHP 8.1+; Некриптографический checksum/хеш |
MHASH_XXH64 · ID 39 | xxh64 | PHP 8.1+; Некриптографический checksum/хеш |
MHASH_XXH3 · ID 40 | xxh3 | PHP 8.1+; Некриптографический checksum/хеш |
MHASH_XXH128 · ID 41 | xxh128 | PHP 8.1+; Некриптографический checksum/хеш |
В диапазоне 0…41 пусты ID 4, 6 и 26. Не создавайте несуществующие MHASH_* по догадке. Старые названия не описывают полный каталог современного Hash: например, одно семейство может иметь дополнительные варианты в hash_algos(). Для HMAC список ещё уже: проверьте hash_hmac_algos.
MD2/MD4/MD5/SHA-1 и другие исторические варианты в этой таблице документируют старый формат; присутствие в библиотеке не означает пригодность для новых задач защиты. CRC, Adler, FNV, JOAAT, Murmur и xxHash не предназначены для противодействия умышленной подмене. Более длинный вывод сам по себе не даёт криптографическую гарантию.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$cases = [[MHASH_SHA256, 'sha256'], [MHASH_TIGER, 'tiger192,3'],
[MHASH_HAVAL128, 'haval128,3'], [MHASH_XXH128, 'xxh128']];
foreach ($cases as [$legacyId, $name]) {
echo $name, ': ', mhash($legacyId, 'catalog fixture') === hash($name, 'catalog fixture', true) ? 'OK' : 'FAIL', "\n";
}
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
sha256: OK
tiger192,3: OK
haval128,3: OK
xxh128: OK
Устаревший API: да
XXH128 здесь проверяется только как некриптографический формат. Вычисление одинакового результата не является доказательством безопасности алгоритма. Полный каталог и все 39 соответствий дополнительно проверены авторским тестом этой главы. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
Практика переноса: digest, HMAC и формат транспорта
Официальный раздел Examples показывает digest и HMAC в hex. Сохраним учебную цель, но используем собственные входные данные и современный SHA-256. Сначала отметьте, что хранится в старой БД/пакете: бинарные байты, hex или base64. Затем сравнивайте одинаковые представления.
- Строка заказа и серверный ключ
- HMAC даёт бинарный результат
- Протокол требует base64 → кодируем raw-байты
- На новой реализации проверяем ту же строку base64
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$body = 'order=42&status=paid';
$key = 'demo-transport-key';
$oldEncoded = base64_encode(mhash(MHASH_SHA256, $body, $key));
$newEncoded = base64_encode(hash_hmac('sha256', $body, $key, true));
$wrongEncoded = base64_encode(hash_hmac('sha256', $body, $key));
var_dump($oldEncoded === $newEncoded);
var_dump($oldEncoded === $wrongEncoded);
echo strlen($oldEncoded), '/', strlen($wrongEncoded), "\n";
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
bool(true)
bool(false)
44/88
Устаревший API: да
Третий вариант кодирует 64 ASCII-символа hex вместо 32 исходных байтов. Base64 — представление, а не шифрование; кодирование не скрывает секрет и не добавляет подписи. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
Если ключ хранится в hex, сначала проверьте его формат и декодируйте hex2bin; если хранится обычная строка, не декодируйте её по догадке. Согласуйте кодировку текста, переносы строк, порядок полей, способ сериализации и представление подписи. У паролей и ключей нет автоматического trim: изменение байтов меняет криптографическую операцию.
Для большого файла не загружайте весь файл в строку только ради замены mhash: hash_file или hash_init → hash_update_stream → hash_final поддерживают соответствующие маршруты. Формат и обработку ошибок всё равно надо сохранить; benchmark сравнивает одинаковый объём данных и одинаковую задачу.
Старый ключ из пароля: что можно заменить сразу, а что требует миграции
В старом архиве функция mhash_keygen_s2k могла получать пароль человека и выводить байты ключа. Для чтения архива нужны тот же алгоритм, соль и длина. PBKDF2, HKDF или современная парольная KDF могут решать родственную задачу, но вычисляют другие байты: замена по смыслу не сохраняет доступ к старому шифртексту.
- Версия старого контейнера выбирает точный S2K-контракт
- Старая соль и пароль → старый ключ → чтение старого формата
- После проверки содержимого создаётся новый формат и ключ
- Версия нового контейнера сохраняет свои параметры, соль и nonce
Соль хранится рядом с метаданными, потому что без неё восстановить ключ нельзя; соль не является паролем. Сам производный ключ рядом со шифртекстом в открытом виде не хранится. Фраза «добавить соль к ключу» в старой документации не означает, что безопасно раскрыть этот ключ. Одно наличие KDF не добавляет аутентификацию шифртексту.
| Потребность | Следующий инструмент |
|---|---|
| Проверять пароль аккаунта | password_hash / password_verify; это не ключ для шифрования. |
| Случайный новый секретный ключ | Криптографический генератор случайных байтов; хранение по отдельной политике секретов. |
| Ключ из уже сильного секрета | hash_hkdf с контекстом назначения; не средство замедления угадывания человеческого пароля. |
| Ключ из пароля по заданному протоколу | hash_pbkdf2 либо согласованная современная password KDF; параметры и ограничения выбираются по протоколу и актуальной политике. |
| Прочитать существующий Salted S2K | mhash_keygen_s2k в ограниченном миграторе с контрольными векторами; это не новый рекомендуемый формат. |
Демонстрации в карточке показывают дополнение/усечение соли, несколько digest-блоков и неэквивалентность PBKDF2. Здесь нет универсального дешифратора: формат архива, режим шифрования, проверка целостности и управление ключами требуют отдельного точного договора. Не пишите «совместимый» новый KDF без векторов реального формата и проверки его владельца.
Карта функций и порядок изменения старого проекта
| Что встретилось в коде | Разбор |
|---|---|
| Вычисление digest или HMAC | mhash |
| Перебор ID | mhash_count |
| Чтение длины поля | mhash_get_block_size |
| Название старого варианта | mhash_get_hash_name |
| Ключ из старого пароля/соли | mhash_keygen_s2k |
- Записать тестовые входы и точные ожидаемые байты, включая пустые строки, NUL, переводы строк и Unicode; реальные секреты в fixtures не переносить.
- Разделить замену API и смену алгоритма/формата. Для hash/hash_hmac явно сохранить binary=true, когда старый вызов возвращал raw.
- Проверить каждый используемый старый вариант через явную таблицу; не применять strtolower ко всем историческим именам.
- Обработать false и исключения до bin2hex, strlen и сравнения. В новом Hash неизвестное имя может вызывать ValueError вместо старого false.
- Не считать отсутствие E_DEPRECATED доказательством безопасности протокола. Удаление предупреждения и обновление криптографической схемы — разные задачи.
Упражнение: старый партнёр ожидает hex-подпись SHA-256. Напишите современный вызов, который сохранит эту строку. Проверка должна сравнить свою fixture, а не отправлять данные партнёру.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$message = 'invoice=42';
$key = 'demo-exercise-key';
$old = bin2hex(mhash(MHASH_SHA256, $message, $key));
$replacement = hash_hmac('sha256', $message, $key);
var_dump(hash_equals($old, $replacement));
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
bool(true)
Устаревший API: да
По умолчанию hash_hmac уже возвращает hex, поэтому дополнительный bin2hex сделал бы двойное кодирование. При сравнении реальной подписи отдельно проверьте её формат и длину, а затем используйте hash_equals. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
Дальше: современный Hash, пароли аккаунтов, ядро интеграционного сервиса.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
mhashВоспроизвести бинарный digest или HMAC старого протокола и проверить современную замену.
function mhash(int $algo, string $data, ?string $key = null): string|falseПеренести проверку старой выгрузки на Hash. Старый вызов принимает числовую константу и возвращает бинарную строку. Чтобы сравнить с новым Hash без изменения формата, третьим аргументом hash указываем true.
- Задан старый формат SHA256 и учебные байты
- Вызов mhash проверяет конкретную часть совместимости
- Миграция сохраняет байты либо явно останавливается
Распакуйте все файлы архива вместе. Команда php example.php выполняет этот пример; файлы из архива не нужно придумывать самостоятельно.
Воспроизвести бинарный digest или HMAC старого протокола и проверить современную замену.
| Параметр / результат | Контракт |
|---|---|
| algo | Числовой ID через MHASH_*; неверный ID или незанятая позиция возвращает false. Не заменяйте ID строкой sha256: это другой интерфейс. |
| data | Все байты сообщения, включая NUL, пробелы и переводы строк. mhash получает готовую строку; потоковой обработки у этого вызова нет. |
| key | Пропущен или null — обычный digest. Любая строка, включая пустую, включает HMAC. Явный nullable-контракт с PHP 8.0. Ключ берут из серверной конфигурации, не из недоверенного запроса. |
| Возврат | Бинарная строка digest/HMAC либо false для неизвестного ID. Для печатного hex используется bin2hex(); для base64 кодируются именно исходные байты результата. |
| Ошибки и версии | В PHP 8.5 не подходящий для HMAC алгоритм, например CRC32, вызывает ValueError; неверный тип при strict_types — TypeError. Поэтому string|false не обещает отсутствие исключений. Вызов даёт E_DEPRECATED с 8.1; константа — с 8.5. |
Сначала прочтите вызов: первый аргумент выбирает алгоритм, второй передаёт сообщение. $raw = ... сохраняет результат. Слово raw здесь означает «исходные байты», а не текст из нулей и единиц. Указание true третьим аргументом современного hash сохраняет этот формат.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$data = file_get_contents(__DIR__ . '/invoice.txt');
if ($data === false) { throw new RuntimeException('Выгрузка недоступна'); }
$old = mhash(MHASH_SHA256, $data);
$new = hash('sha256', $data, true);
echo 'invoice.txt: ', bin2hex($new), "\n";
echo hash_equals($old, $new) ? "Старый формат подтверждён; получатель примет тот же digest.\n" : "Миграция меняет байты.\n";
} finally { restore_error_handler(); }
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
invoice.txt: 36c43bb2eda40f4ea02f6ef2b7a4d0dbf7754df0c0f2c88fb1b120d6d2b1bdb2
Старый формат подтверждён; получатель примет тот же digest.
Устаревший API: да
Обработчик предупреждений временно собирает только ожидаемые deprecation Mhash; finally восстанавливает обычную обработку. Все mhash-функции устарели с8.1, MHASH-константы с8.5. Этот код нужен для изучения/переноса существующих данных, новые проекты используют Hash/password API. Сбой чтения или чужое предупреждение не маскируются.
Перевод строки меняет подписанные байты. В webhook проверяют исходное тело до повторного json_encode; защищённое сравнение не заменяет проверку времени/повтора, TLS и защиту ключа. Здесь только локальная вымышленная подпись. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$body = '{"order":42}';
$key = 'demo-key-not-a-real-secret';
$legacy = mhash(MHASH_SHA256, $body, $key);
$modern = hash_hmac('sha256', $body, $key, true);
var_dump(hash_equals($legacy, $modern));
var_dump(base64_encode($legacy) === base64_encode($modern));
var_dump(hash_equals($modern, hash_hmac('sha256', $body . "\n", $key, true)));
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
bool(true)
bool(true)
bool(false)
Устаревший API: да
Пустая строка всё равно выбирает HMAC, но не является подходящим секретом. Не проверяйте key через truthy/falsy при написании адаптера: это может незаметно сменить операцию. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$plain = mhash(MHASH_SHA256, 'abc', null);
$emptyKey = mhash(MHASH_SHA256, 'abc', '');
var_dump($plain === hash('sha256', 'abc', true));
var_dump($emptyKey === hash_hmac('sha256', 'abc', '', true));
var_dump($plain === $emptyKey);
var_dump(mhash(-1, 'abc'));
try { mhash(MHASH_CRC32, 'abc', 'demo'); }
catch (ValueError $error) { echo "Алгоритм не подходит для HMAC\n"; }
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
bool(true)
bool(true)
bool(false)
bool(false)
Алгоритм не подходит для HMAC
Устаревший API: да
Заменить функцию и заменить алгоритм — разные миграции. MD5→SHA-256 меняет результат; hash("md5", ...) лишь воспроизводит прежний MD5 через другой API. Пароли не сохраняют через этот быстрый digest: нужен отдельный password_* справочник.
Начало и границы лаборатории: переход со старого интерфейса.
Связанные функции: hash, hash_hmac, hash_equals, mhash_get_hash_name.
mhash_countПолучить верхнюю границу старых числовых ID для исследования наследованного каталога.
function mhash_count(): intНайти алгоритм в старой таблице с пропусками. Название count вводит в заблуждение: возвращается максимальный ID, поэтому цикл включает саму границу через <=. mhash_get_hash_name может вернуть false для пустой позиции.
- Задан старый формат SHA256 и учебные байты
- Вызов mhash_count проверяет конкретную часть совместимости
- Миграция сохраняет байты либо явно останавливается
Распакуйте все файлы архива вместе. Команда php example.php выполняет этот пример; файлы из архива не нужно придумывать самостоятельно.
Получить верхнюю границу старых числовых ID для исследования наследованного каталога.
| Параметр / результат | Контракт |
|---|---|
| Аргументы | Нет. |
| Возврат | Наибольший предусмотренный ID, не число существующих алгоритмов. Диапазон включает 0 и может содержать незанятые позиции. |
| Версия и диагностические сообщения | С PHP 8.1 E_DEPRECATED. В проверенной PHP 8.5.11 возвращает 41; это снимок реализации, не число, которое надо зашить в приложение. |
Скобки пусты, потому что функции не требуется входное значение. <= включает последний ID: если написать только <, последний алгоритм потеряется. Переменная со счётчиком найденных имён выполняет другую работу, чем верхняя граница.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$found = false;
for ($id = 0; $id <= mhash_count(); ++$id) {
$name = mhash_get_hash_name($id);
if ($name === 'SHA256') { $found = true; echo 'Найден старый формат: ', $name, " → hash('sha256', данные, true)\n"; }
}
if (!$found) { echo "Формат SHA256 отсутствует: импорт остановлен.\n"; }
} finally { restore_error_handler(); }
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
Найден старый формат: SHA256 → hash('sha256', данные, true)
Устаревший API: да
Обработчик предупреждений временно собирает только ожидаемые deprecation Mhash; finally восстанавливает обычную обработку. Все mhash-функции устарели с8.1, MHASH-константы с8.5. Этот код нужен для изучения/переноса существующих данных, новые проекты используют Hash/password API. Сбой чтения или чужое предупреждение не маскируются.
Современный hash_algos сразу возвращает имена, но его набор не обязан совпадать с исторической таблицей Mhash. Это не равнозначные способы получить количество «всех криптографических алгоритмов». Некоторые элементы вообще не криптографические. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$lastId = mhash_count();
$names = [];
$gaps = [];
for ($id = 0; $id <= $lastId; ++$id) {
$name = mhash_get_hash_name($id);
if ($name === false) { $gaps[] = $id; continue; }
$names[$id] = $name;
}
echo count($names), "\n";
echo implode(',', $gaps), "\n";
echo in_array('sha256', hash_algos(), true) ? "SHA-256 доступен в Hash\n" : "Нет SHA-256\n";
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
39
4,6,26
SHA-256 доступен в Hash
Устаревший API: да
Начало и границы лаборатории: переход со старого интерфейса.
Связанные функции: mhash_get_hash_name, hash_algos, hash_hmac_algos.
mhash_get_block_sizeУзнать длину бинарного результата старого алгоритма, например для чтения сохранённого формата.
function mhash_get_block_size(int $algo): int|falseОтклонить обрезанное поле старого пакета. Несмотря на имя, функция возвращает размер digest в байтах, а не внутренний размер блока алгоритма. У SHA256 это32. Длина подтверждает форму поля, не подлинность его содержимого.
- Задан старый формат SHA256 и учебные байты
- Вызов mhash_get_block_size проверяет конкретную часть совместимости
- Миграция сохраняет байты либо явно останавливается
Распакуйте все файлы архива вместе. Команда php example.php выполняет этот пример; файлы из архива не нужно придумывать самостоятельно.
Узнать длину бинарного результата старого алгоритма, например для чтения сохранённого формата.
| Параметр / результат | Контракт |
|---|---|
| algo | Числовой идентификатор MHASH_*. |
| Возврат | Число байтов digest; неизвестный/незанятый ID — false. В PHP 8.5 реализация читает digest_size, несмотря название block_size. |
| Что это не означает | Не длина блока, который алгоритм обрабатывает внутри, не размер ключа HMAC, не рекомендуемая длина пароля. |
| Ошибки и версии | Неверный тип при strict_types — TypeError; вызов устарел с PHP 8.1. Обрабатывайте false до арифметики и чтения байтов. |
Размер помогает разобрать формат сообщения, но одинаковая длина двух строк не доказывает одинаковое содержимое. Для сравнения криптографической подписи нужен hash_equals. У SHA-256 размер digest — 32 байта, тогда как внутренний блок алгоритма — 64 байта: это разные величины.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$size = mhash_get_block_size(MHASH_SHA256);
if ($size === false) { throw new RuntimeException('Алгоритм неизвестен'); }
$full = mhash(MHASH_SHA256, 'invoice=42');
$short = substr($full, 0, -1);
echo strlen($full) === $size ? "Полный пакет: поле SHA256 можно читать.\n" : "Полный пакет: ошибка.\n";
echo strlen($short) === $size ? "Короткий пакет принят.\n" : "Короткий пакет: импорт остановлен, не хватает байта.\n";
} finally { restore_error_handler(); }
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
Полный пакет: поле SHA256 можно читать.
Короткий пакет: импорт остановлен, не хватает байта.
Устаревший API: да
Обработчик предупреждений временно собирает только ожидаемые deprecation Mhash; finally восстанавливает обычную обработку. Все mhash-функции устарели с8.1, MHASH-константы с8.5. Этот код нужен для изучения/переноса существующих данных, новые проекты используют Hash/password API. Сбой чтения или чужое предупреждение не маскируются.
Это структурная проверка собственной fixture. Подлинность файла требует отдельной доверенной подписи/канала; атакующий легко создаст строку правильной длины. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$expectedBytes = mhash_get_block_size(MHASH_SHA256);
if ($expectedBytes === false) { throw new RuntimeException('Unknown format algorithm'); }
$raw = mhash(MHASH_SHA256, 'record=42');
$short = substr($raw, 0, -1);
echo strlen($raw) === $expectedBytes ? "Поле полное\n" : "Поле обрезано\n";
echo strlen($short) === $expectedBytes ? "Поле полное\n" : "Поле обрезано\n";
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
Поле полное
Поле обрезано
Устаревший API: да
Начало и границы лаборатории: переход со старого интерфейса.
Связанные функции: mhash, hash, mhash_get_hash_name, hash_equals.
mhash_get_hash_nameПрочитать историческое имя по ID, чтобы понять старую настройку и построить явное соответствие Hash.
function mhash_get_hash_name(int $algo): string|falseПеревести известный старый ID в явную политику. Функция возвращает историческое имя по ID. strtolower не является универсальным преобразованием: TIGER/HAVAL имеют варианты, указанные в таблице ниже. Для SHA256 выбираем соответствие явно.
- Задан старый формат SHA256 и учебные байты
- Вызов mhash_get_hash_name проверяет конкретную часть совместимости
- Миграция сохраняет байты либо явно останавливается
Распакуйте все файлы архива вместе. Команда php example.php выполняет этот пример; файлы из архива не нужно придумывать самостоятельно.
Прочитать историческое имя по ID, чтобы понять старую настройку и построить явное соответствие Hash.
| Параметр / результат | Контракт |
|---|---|
| algo | ID из старого формата или MHASH_*. |
| Возврат | Имя в историческом каталоге, например SHA256 или TIGER, либо false для отсутствующего ID. Это имя не обязано напрямую приниматься hash(). |
| Ошибки и версии | Неверный тип при strict_types — TypeError. E_DEPRECATED с PHP 8.1; константы MHASH_* тоже устарели с 8.5. |
Удобно показать оператору читаемое имя, а затем проверить mapping. Привести имя к нижнему регистру недостаточно: TIGER соответствует tiger192,3, HAVAL256 — haval256,3. Числа относятся к варианту алгоритма; их потеря меняет контракт.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$legacyName = mhash_get_hash_name(MHASH_SHA256);
if ($legacyName !== 'SHA256') { throw new RuntimeException('Неизвестный формат'); }
echo $legacyName, " → sha256\n";
echo 'Отпечаток invoice=42: ', hash('sha256', 'invoice=42'), "\n";
} finally { restore_error_handler(); }
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
SHA256 → sha256
Отпечаток invoice=42: 75bc7941966514f9788ff7c2126ee3384aeb0039bd7934b543aa7d3dc58875b7
Устаревший API: да
Обработчик предупреждений временно собирает только ожидаемые deprecation Mhash; finally восстанавливает обычную обработку. Все mhash-функции устарели с8.1, MHASH-константы с8.5. Этот код нужен для изучения/переноса существующих данных, новые проекты используют Hash/password API. Сбой чтения или чужое предупреждение не маскируются.
Полная таблица вариантов приведена в разделе констант. Мы проверяем совместимость записи старого приложения, а не выбираем эти алгоритмы для новой защиты. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$variants = [[MHASH_TIGER, 'tiger192,3'], [MHASH_HAVAL256, 'haval256,3']];
foreach ($variants as [$oldId, $newName]) {
$oldResult = mhash($oldId, 'demo fixture');
echo mhash_get_hash_name($oldId), ' -> ', $newName, ': ';
echo $oldResult === hash($newName, 'demo fixture', true) ? "совпало\n" : "различается\n";
}
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
TIGER -> tiger192,3: совпало
HAVAL256 -> haval256,3: совпало
Устаревший API: да
Начало и границы лаборатории: переход со старого интерфейса.
Связанные функции: mhash_count, mhash, hash_algos, hash.
mhash_keygen_s2kВоспроизвести ключ исторического Salted S2K формата при чтении старых данных.
function mhash_keygen_s2k(int $algo, string $password, string $salt, int $length): string|falseВосстановить точные байты старого S2K перед миграцией. Старый формат использует соль длиной8байтов и особое построение блоков. Это не PBKDF2. Воспроизводимый тест показывает ключ открытого учебного вектора; настоящие ключи так не печатают.
- Задан старый формат SHA256 и учебные байты
- Вызов mhash_keygen_s2k проверяет конкретную часть совместимости
- Миграция сохраняет байты либо явно останавливается
Распакуйте все файлы архива вместе. Команда php example.php выполняет этот пример; файлы из архива не нужно придумывать самостоятельно.
Воспроизвести ключ исторического Salted S2K формата при чтении старых данных.
| Параметр / результат | Контракт |
|---|---|
| algo | Числовой MHASH_* ID. Неизвестный ID возвращает false, если остальные проверки входа пройдены. |
| password | Исходные байты старой парольной фразы. Метод преобразует их в ключ заданного формата; не шифрует данные и не является password_hash. |
| salt | Историческая соль ровно 8 байтов: короткая дополняется NUL справа, длинная обрезается до первых 8 байтов. Для восстановления нужен исходный договор хранения соли; соль не секрет. |
| length | Запрошенная длина ключа в байтах. В PHP 8.5 значение 0 или отрицательное вызывает ValueError. Ограничивайте длину доверенным форматом; это не произвольный размер из HTTP. |
| Возврат и ошибки | Бинарная строка указанной длины либо false для неизвестного ID; неверные типы при strict_types — TypeError. Полученный ключ секретен: не выводить и не складывать рядом с защищаемыми данными. |
| Версии | С PHP 4.0.4; устарела с 8.1. Современные KDF имеют другой формат и параметры, поэтому замена одним именем обычно несовместима. |
S2K означает string-to-key — преобразование строки в ключ. Это Salted S2K из старого OpenPGP RFC 2440, без настраиваемого количества итераций. Более длинный результат не увеличивает непредсказуемость слабого пароля до длины ключа. Не используйте эту функцию для новых паролей аккаунтов или нового формата шифрования.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$key = mhash_keygen_s2k(MHASH_SHA256, 'legacy phrase', '12345678', 16);
if ($key === false) { throw new RuntimeException('Старый ключ не получен'); }
echo 'Учебный S2K: ', bin2hex($key), "\n";
$different = hash_pbkdf2('sha256', 'legacy phrase', '12345678', 2, 16, true);
echo hash_equals($key, $different) ? "Можно заменить без смены формата.\n" : "PBKDF2 даёт другой ключ; нужна миграция формата.\n";
} finally { restore_error_handler(); }
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
Учебный S2K: 98c2114895f7b2d04475053341fb14f9
PBKDF2 даёт другой ключ; нужна миграция формата.
Устаревший API: да
Обработчик предупреждений временно собирает только ожидаемые deprecation Mhash; finally восстанавливает обычную обработку. Все mhash-функции устарели с8.1, MHASH-константы с8.5. Этот код нужен для изучения/переноса существующих данных, новые проекты используют Hash/password API. Сбой чтения или чужое предупреждение не маскируются.
Длинная соль не добавляет защиту этому API после восьмого байта. При переносе старых данных необходимо сохранить именно его правило, а не подставить полный salt в другую функцию. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$base = mhash_keygen_s2k(MHASH_SHA256, 'demo', '12345678', 16);
$long = mhash_keygen_s2k(MHASH_SHA256, 'demo', '12345678EXTRA', 16);
$short = mhash_keygen_s2k(MHASH_SHA256, 'demo', 'abc', 16);
$padded = mhash_keygen_s2k(MHASH_SHA256, 'demo', "abc\0\0\0\0\0", 16);
var_dump(hash_equals($base, $long));
var_dump(hash_equals($short, $padded));
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
bool(true)
bool(true)
Устаревший API: да
Здесь SHA-1 и одна итерация PBKDF2 — только сравнение старых формул, не рекомендуемая политика. Salted S2K для дополнительных блоков добавляет 0, 1, 2… NUL перед солью/паролем, объединяет digest и обрезает до length. Это не последовательное «хешировать предыдущий блок» и не PBKDF2. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
$salt = '12345678';
$password = 'demo legacy phrase';
$legacy = mhash_keygen_s2k(MHASH_SHA1, $password, $salt, 40);
$firstBlock = hash('sha1', $salt . $password, true);
$secondBlock = hash('sha1', "\0" . $salt . $password, true);
var_dump(hash_equals($legacy, $firstBlock . $secondBlock));
$different = hash_pbkdf2('sha1', $password, $salt, 1, 40, true);
var_dump(hash_equals($legacy, $different));
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
bool(true)
bool(false)
Устаревший API: да
Параметры архива проверяются до выделения памяти. PHP 8.5 внутри использует C int для длины; технические пределы не должны становиться политикой обработки недоверенного ввода. Огромные размеры в этих опытах не выделяются. Обработчик учитывает только ожидаемые E_DEPRECATED этого семейства, сообщает о них последней строкой и восстанавливает прежний обработчик. Другие ошибки не скрываются; это лаборатория совместимости, не настройка журналирования сервера.
<?php
declare(strict_types=1);
$legacyNotice = false;
set_error_handler(function (int $level, string $message) use (&$legacyNotice): bool {
if ($level === E_DEPRECATED
&& (str_starts_with($message, 'Function mhash') || str_starts_with($message, 'Constant MHASH_'))) {
$legacyNotice = true;
return true;
}
return false;
});
try {
var_dump(mhash_keygen_s2k(-1, 'demo', '12345678', 16));
foreach ([0, -1] as $length) {
try { mhash_keygen_s2k(MHASH_SHA256, 'demo', '12345678', $length); }
catch (ValueError $error) { echo "Неверная длина\n"; }
}
} finally {
restore_error_handler();
}
echo $legacyNotice ? "Устаревший API: да\n" : "Устаревший API: нет\n";
Ожидаемый результат
bool(false)
Неверная длина
Неверная длина
Устаревший API: да
Для нового случайного ключа используют криптографический генератор, для ключа из пароля — согласованную современную KDF, для хранения пароля — password_hash. hash_pbkdf2 и hash_hkdf не являются побайтовыми заменами S2K, а HKDF не превращает слабый пароль в стойкий секрет. Миграция зашифрованного архива требует прочитать его старым форматом и записать новым с отдельной версией, солью/nonce и аутентификацией; эта глава не реализует шифрование.
Начало и границы лаборатории: переход со старого интерфейса.
Связанные функции: hash_pbkdf2, hash_hkdf, hash_equals, mhash.
Источники и обсуждения
- PHP: book.mhash
- PHP: mhash.setup
- PHP: mhash.requirements
- PHP: mhash.installation
- PHP: mhash.constants
- PHP: mhash.examples
- PHP: ref.mhash
- PHP: function.mhash
- PHP: function.mhash-count
- PHP: function.mhash-get-block-size
- PHP: function.mhash-get-hash-name
- PHP: function.mhash-keygen-s2k
- PHP 8.5.11: Mhash compatibility source