Hash hmac: примеры (PHP)

HMAC-хэширование в PHP с помощью функции hash_hmac
Раздел: Хеширование и шифрование
hash_hmac(string $algo, string $data, string $key, bool $binary = false): string
Описание функции hash_hmac

Функция 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, что означает вывод в шестнадцатеричном формате.

Базовые примеры использования
Простой пример с SHA-256
<?
$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... // сокращенный вывод
Похожие функции в PHP

Функция hash() создает хэш без использования ключа. Применяется когда не требуется аутентификация источника данных.

Функция hash_pbkdf2() реализует алгоритм PBKDF2 (Password-Based Key Derivation Function 2). Используется для создания криптографических ключей из паролей, поддерживает множественные итерации.

hash_hkdf()

Функция 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
JavaScript (Node.js)
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, а приблизительная эмуляция
Golang
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 "Алгоритм не поддерживается";
}
?>
Алгоритм не поддерживается
Изменения в последних версиях PHP
PHP 8.0.0

Параметр алгоритм теперь ожидает строку (string). Ранее принимались и другие типы, которые преобразовывались.

PHP 7.2.0

Запрещено использование алгоритмов хеширования adler32, crc32, crc32b, fnv132, fnv1a32, fnv164, fnv1a64, joaat. Эти алгоритмы не являются криптографическими.

PHP 5.5.0

Добавлена поддержка алгоритма 'sha3-256', 'sha3-512' и других вариантов SHA-3.

PHP 5.1.2

Появилась сама функция hash_hmac() с выпуском расширения Hash.

Расширенные примеры
Проверка целостности данных API
Пример php
<?
// Сторона отправителя
$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 "Ошибка проверки подписи.";
}
?>
Создание безопасных токенов
Пример php
<?
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);
}
?>
Сравнение времени выполнения для разных алгоритмов
Пример php
<?
$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";
}
?>
Использование с hash_equals для предотвращения атак по времени
Пример php
<?
// Безопасное сравнение хэшей
$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 "Хэши различаются";
}
?>
Генерация производных ключей (упрощенная эмуляция HKDF)
Пример php
<?
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";
}
?>

PHP hash_hmac function comments

En
Hash hmac Generate a keyed hash value using the HMAC method