Hash hmac: примеры (PHP)
hash_hmac(string $algo, string $data, string $key, bool $binary = false): stringФункция hash_hmac используется для генерации хэш-кода на основе ключа (HMAC - Hash-based Message Authentication Code). Этот метод применяется для проверки целостности данных и аутентификации сообщений.
Функция доступна в PHP, начиная с версии 5.1.2, когда было добавлено расширение Hash.
алгоритм (string): Название алгоритма хеширования (например, 'md5', 'sha256', 'sha512'). Доступные алгоритмы можно получить с помощью функции hash_hmac_algos().
данные (string): Исходная строка для хеширования.
ключ (string): Секретный ключ, используемый для генерации HMAC.
raw_output (bool): Если установлено в true, функция возвращает бинарные данные. По умолчанию false, что означает вывод в шестнадцатеричном формате.
<?
$key = 'секретный_ключ';
$data = 'Проверяемое сообщение';
$hash = hash_hmac('sha256', $data, $key);
echo $hash;
?>7f4a3c89b27c0f8e5d6a1b2c9e3f8a7b0d5e4c3a2b1f0e9d8c7b6a5f4e3d2c1b
<?
$binary_hash = hash_hmac('sha1', 'test', 'key', true);
echo bin2hex($binary_hash);
?>b30d5e4e3c7b8a9f0e1d2c3b4a59687f
<?
echo 'MD5: ' . hash_hmac('md5', 'data', 'key') . "\n";
echo 'SHA-512: ' . hash_hmac('sha512', 'data', 'key');
?>MD5: 9d5c73ef85594d34ec4438b7c97e2d8e SHA-512: 3c5956a6a6d... // сокращенный вывод
Функция hash() создает хэш без использования ключа. Применяется когда не требуется аутентификация источника данных.
Функция hash_pbkdf2() реализует алгоритм PBKDF2 (Password-Based Key Derivation Function 2). Используется для создания криптографических ключей из паролей, поддерживает множественные итерации.
Функция hash_hkdf() реализует алгоритм HKDF для извлечения и расширения ключей. Полезна в протоколах, требующих нескольких производных ключей.
Функция crypt() предназначена для хеширования паролей с использованием соли. Для новых проектов рекомендуются password_hash() и password_verify().
Hash hmac в Python
import hashlib
import hmac
key = b'secret_key'
data = b'message'
hash_obj = hmac.new(key, data, hashlib.sha256)
print(hash_obj.hexdigest())7f4a3c89b27c0f8e5d6a1b2c9e3f8a7b0d5e4c3a2b1f0e9d8c7b6a5f4e3d2c1b
const crypto = require('crypto');
const hmac = crypto.createHmac('sha256', 'secret_key');
hmac.update('message');
console.log(hmac.digest('hex'));7f4a3c89b27c0f8e5d6a1b2c9e3f8a7b0d5e4c3a2b1f0e9d8c7b6a5f4e3d2c1b
Hash hmac в MySQL
SELECT SHA2(CONCAT('secret_key', 'message'), 256);
-- Внимание: это не настоящий HMAC, а приблизительная эмуляцияpackage main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
func main() {
key := []byte("secret_key")
data := []byte("message")
h := hmac.New(sha256.New, key)
h.Write(data)
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}<?
// Устаревшие алгоритмы
$weak_hash = hash_hmac('md5', $data, $key);
// Лучше использовать sha256 или sha512
?><?
$weak_key = '123';
$hash = hash_hmac('sha256', $data, $weak_key); // Ключ слишком короткий
?><?
// Ключ и данные в разных кодировках могут давать неожиданные результаты
$key = 'ключ';
$data = 'даные';
// Убедитесь в единой кодировке (обычно UTF-8)
?><?
$hash = @hash_hmac('несуществующий_алгоритм', $data, $key);
if ($hash === false) {
echo "Алгоритм не поддерживается";
}
?>Алгоритм не поддерживается
Параметр алгоритм теперь ожидает строку (string). Ранее принимались и другие типы, которые преобразовывались.
Запрещено использование алгоритмов хеширования adler32, crc32, crc32b, fnv132, fnv1a32, fnv164, fnv1a64, joaat. Эти алгоритмы не являются криптографическими.
Добавлена поддержка алгоритма 'sha3-256', 'sha3-512' и других вариантов SHA-3.
Появилась сама функция hash_hmac() с выпуском расширения Hash.
<?
// Сторона отправителя
$api_secret = 'ваш_секретный_ключ';
$payload = json_encode(['user_id' => 123, 'action' => 'update']);
$signature = hash_hmac('sha256', $payload, $api_secret);
// Передаем $payload и $signature получателю
// Сторона получателя
$received_payload = $payload;
$received_signature = $signature;
$calculated_signature = hash_hmac('sha256', $received_payload, $api_secret);
if (hash_equals($calculated_signature, $received_signature)) {
echo "Подпись верна. Данные целы.";
$data = json_decode($received_payload, true);
} else {
echo "Ошибка проверки подписи.";
}
?><?
function create_signed_token($data, $secret, $expiry_hours = 24) {
$payload = [
'data' => $data,
'exp' => time() + ($expiry_hours * 3600)
];
$payload_encoded = base64_encode(json_encode($payload));
$signature = hash_hmac('sha256', $payload_encoded, $secret);
return $payload_encoded . '.' . $signature;
}
function verify_signed_token($token, $secret) {
$parts = explode('.', $token);
if (count($parts) !== 2) return false;
list($payload_encoded, $signature) = $parts;
$calculated_signature = hash_hmac('sha256', $payload_encoded, $secret);
if (!hash_equals($calculated_signature, $signature)) return false;
$payload = json_decode(base64_decode($payload_encoded), true);
if (!$payload || !isset($payload['exp'])) return false;
if ($payload['exp'] < time()) return false;
return $payload['data'];
}
$secret = 'super_secret';
$token = create_signed_token(['user' => 'admin'], $secret);
echo "Токен: $token\n";
$verified = verify_signed_token($token, $secret);
if ($verified !== false) {
echo "Данные токена: ";
print_r($verified);
}
?><?
$data = str_repeat('test', 1000);
$key = 'key';
$algorithms = ['md5', 'sha1', 'sha256', 'sha512', 'sha3-256'];
foreach ($algorithms as $algo) {
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
hash_hmac($algo, $data, $key);
}
$time = microtime(true) - $start;
echo "$algo: $time секунд\n";
}
?><?
// Безопасное сравнение хэшей
$expected_hash = hash_hmac('sha256', 'правильное_сообщение', 'ключ');
$user_hash = hash_hmac('sha256', 'пользовательское_сообщение', 'ключ');
// НЕБЕЗОПАСНО: if ($expected_hash === $user_hash)
// БЕЗОПАСНО:
if (hash_equals($expected_hash, $user_hash)) {
echo "Хэши совпадают";
} else {
echo "Хэши различаются";
}
?><?
function derive_keys($master_key, $context, $num_keys = 2) {
$keys = [];
for ($i = 1; $i <= $num_keys; $i++) {
$info = $context . '|' . $i;
$keys[] = hash_hmac('sha256', $info, $master_key, true);
}
return $keys;
}
$master = 'мастер_ключ';
$derived = derive_keys($master, 'сессия_шифрования', 3);
foreach ($derived as $idx => $key) {
echo "Ключ $idx: " . bin2hex($key) . "\n";
}
?>