Openssl dh compute key: примеры (PHP)

Работа с openssl_dh_compute_key в PHP для обмена ключами
Раздел: Шифрование (OpenSSL)
openssl_dh_compute_key(string $public_key, OpenSSLAsymmetricKey $private_key): string|false

Функция openssl_dh_compute_key

Функция openssl_dh_compute_key() используется для вычисления общего секретного ключа по алгоритму Диффи-Хеллмана. Этот алгоритм позволяет двум сторонам, имеющим пару открытый/закрытый ключ, получить общий секретный ключ через незащищенный канал связи. Функция применяется в криптографических протоколах для установления защищенного соединения.

Аргументы функции
  • public_key - открытый ключ другой стороны в формате строки или ресурса.
  • private_key - закрытый ключ текущей стороны в формате ресурса.
  • key_length (опционально) - длина возвращаемого ключа в байтах. Если не указана, используется полная длина.

Функция возвращает общий секретный ключ в виде строки или false в случае ошибки.

Короткие примеры использования

Пример 1: Базовое вычисление общего ключа
// Генерация ключевой пары для стороны A
$config = array("private_key_bits" => 2048);
$private_key_a = openssl_pkey_new($config);
$details_a = openssl_pkey_get_details($private_key_a);
$public_key_a = $details_a['dh']['pub_key'];

// Генерация ключевой пары для стороны B
$private_key_b = openssl_pkey_new($config);
$details_b = openssl_pkey_get_details($private_key_b);
$public_key_b = $details_b['dh']['pub_key'];

// Сторона A вычисляет общий ключ
$shared_key_a = openssl_dh_compute_key($public_key_b, $private_key_a);

// Сторона B вычисляет общий ключ
$shared_key_b = openssl_dh_compute_key($public_key_a, $private_key_b);

echo 'Ключи совпадают: ' . (bin2hex($shared_key_a) === bin2hex($shared_key_b) ? 'да' : 'нет');
Ключи совпадают: да
Пример 2: Указание длины ключа
// Вычисление ключа с ограничением длины до 128 бит (16 байт)
$shared_key_short = openssl_dh_compute_key($public_key_b, $private_key_a, 16);
echo 'Длина ключа: ' . strlen($shared_key_short) . ' байт';
Длина ключа: 16 байт

Похожие функции в PHP

В PHP для работы с асимметричной криптографией доступны другие функции:

  • openssl_pkey_derive() - более современная функция для вывода общего ключа, поддерживает различные алгоритмы, включая Диффи-Хеллман. Рекомендуется к использованию в новых проектах, так как обеспечивает лучшую гибкость.
  • sodium_crypto_scalarmult() - функция из библиотеки Libsodium для вычисления общего ключа по кривой Curve25519. Обеспечивает высокую производительность и безопасность. Предпочтительна для современных протоколов.

Функцию openssl_dh_compute_key() стоит использовать при работе с устаревшими системами или когда требуется совместимость с существующим кодом.

Типичные ошибки

Ошибка 1: Некорректный формат ключа
// Передача строки вместо ресурса
$wrong_key = "invalid_key";
$result = openssl_dh_compute_key($wrong_key, $private_key_a);
var_dump($result);
bool(false)
Ошибка 2: Использование ключей от разных параметров
// Генерация ключей с разными параметрами
$config1 = array("private_key_bits" => 2048);
$config2 = array("private_key_bits" => 4096);

$priv1 = openssl_pkey_new($config1);
$priv2 = openssl_pkey_new($config2);

$details1 = openssl_pkey_get_details($priv1);
$details2 = openssl_pkey_get_details($priv2);

$result = openssl_dh_compute_key($details2['dh']['pub_key'], $priv1);
var_dump($result);
bool(false)
Ошибка 3: Несовместимые типы ключей
// Попытка использовать RSA ключ вместо DH
$rsa_key = openssl_pkey_new(array("private_key_bits" => 2048, "private_key_type" => OPENSSL_KEYTYPE_RSA));
$result = openssl_dh_compute_key($public_key_b, $rsa_key);
var_dump($result);
bool(false)

Изменения в последних версиях PHP

В PHP 8.0 функция openssl_dh_compute_key() была модифицирована для более строгой проверки типов аргументов. Теперь при передаче некорректных значений функция выбрасывает исключение ValueError вместо возврата false.

В PHP 8.1 улучшена совместимость с различными форматами ключей и добавлена поддержка новых криптографических стандартов в рамках обновлений библиотеки OpenSSL.

Расширенные примеры

Пример 1: Обмен ключами между клиентом и сервером
Пример php
// Серверная сторона: генерация параметров и ключа
$server_params = openssl_pkey_new(array(
    "private_key_bits" => 2048,
    "private_key_type" => OPENSSL_KEYTYPE_DH
));
$server_details = openssl_pkey_get_details($server_params);
$server_public = $server_details['dh']['pub_key'];

// Клиентская сторона: генерация ключа на основе параметров сервера
$client_key = openssl_pkey_new($server_details['dh']);
$client_details = openssl_pkey_get_details($client_key);
$client_public = $client_details['dh']['pub_key'];

// Сервер вычисляет общий ключ, используя публичный ключ клиента
$server_shared = openssl_dh_compute_key($client_public, $server_params);

// Клиент вычисляет общий ключ
$client_shared = openssl_dh_compute_key($server_public, $client_key);

echo 'Совпадение ключей: ' . (bin2hex($server_shared) === bin2hex($client_shared) ? 'успешно' : 'ошибка');
Совпадение ключей: успешно
Пример 2: Использование с заданными параметрами (простые числа)
Пример php
// Задание собственных параметров DH
$p = hex2bin('F518AA8781A8DF278ABA4E7D64B7CB9D49462353');
$g = hex2bin('05');

$params = openssl_pkey_new(array(
    'dh' => array('p' => $p, 'g' => $g, 'priv_key' => 'some_private_value')
));

$details = openssl_pkey_get_details($params);
$public1 = $details['dh']['pub_key'];

// Вторая сторона использует те же параметры
$key2 = openssl_pkey_new($details['dh']);
$details2 = openssl_pkey_get_details($key2);
$public2 = $details2['dh']['pub_key'];

$shared1 = openssl_dh_compute_key($public2, $params);
$shared2 = openssl_dh_compute_key($public1, $key2);

echo 'Длина общего ключа: ' . strlen($shared1) . ' байт';
Длина общего ключа: 20 байт
Пример 3: Сериализация и восстановление ключей
Пример php
// Генерация и экспорт ключа
$key_resource = openssl_pkey_new(array("private_key_bits" => 2048));
openssl_pkey_export($key_resource, $private_pem);
$details = openssl_pkey_get_details($key_resource);
$public_pem = $details['key'];

// Восстановление ключа из PEM формата
$restored_key = openssl_pkey_get_private($private_pem);

// Использование восстановленного ключа
$new_public_key = openssl_pkey_get_public($public_pem);
$new_details = openssl_pkey_get_details($new_public_key);

$shared_key = openssl_dh_compute_key($new_details['dh']['pub_key'], $restored_key);
echo 'Ключ вычислен: ' . (strlen($shared_key) > 0 ? 'да' : 'нет');
Ключ вычислен: да

Альтернативы в других языках

Python: cryptography.hazmat.primitives.asymmetric.dh
from cryptography.hazmat.primitives.asymmetric import dh
from cryptography.hazmat.primitives import serialization

# Генерация параметров
parameters = dh.generate_parameters(generator=2, key_size=2048)

# Генерация ключей
private_key_a = parameters.generate_private_key()
private_key_b = parameters.generate_private_key()

# Вычисление общего ключа
shared_key_a = private_key_a.exchange(private_key_b.public_key())
shared_key_b = private_key_b.exchange(private_key_a.public_key())

print(shared_key_a == shared_key_b)
True
JavaScript (Node.js): crypto.createDiffieHellman
const crypto = require('crypto');

// Создание экземпляров Диффи-Хеллмана
const alice = crypto.createDiffieHellman(2048);
const bob = crypto.createDiffieHellman(alice.getPrime(), alice.getGenerator());

// Генерация ключей
alice.generateKeys();
bob.generateKeys();

// Вычисление общего секрета
const secretAlice = alice.computeSecret(bob.getPublicKey());
const secretBob = bob.computeSecret(alice.getPublicKey());

console.log(secretAlice.equals(secretBob));
true
Отличия от PHP

В Python и JavaScript, как правило, используются более высокоуровневые API, которые инкапсулируют детали реализации. В PHP функция openssl_dh_compute_key() требует ручного управления ресурсами ключей.

PHP openssl_dh_compute_key function comments

En
Openssl dh compute key Computes shared secret for public value of remote DH public key and local DH key