Openssl verify: примеры (PHP)

Проверка цифровых подписей с помощью openssl_verify
Раздел: Шифрование (OpenSSL)
openssl_verify(string $data, string $signature, OpenSSLAsymmetricKey|OpenSSLCertificate|array|string $public_key, string|int $algorithm = OPENSSL_ALGO_SHA1): int|false
Описание функции openssl_verify

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

Аргументы функции
  • $data (string) - строковые данные, для которых создавалась подпись. Обычно это хэш (дайджест) исходных данных, но может быть и сами данные.
  • $signature (string) - сырая двоичная строка или строка в кодировке base64, содержащая подпись.
  • $public_key (OpenSSLAsymmetricKey|OpenSSLCertificate|string) - открытый ключ или сертификат X.509 в формате PEM или строке, используемый для проверки.
  • $algorithm (int|string) - алгоритм хэширования. В PHP 8 может быть строкой (напр., "sha256WithRSAEncryption") или константой (напр., OPENSSL_ALGO_SHA256).
  • flags (int) - опциональный параметр, влияющий на поведение проверки. Основные флаги: OPENSSL_ALGO_SHA256 (и другие алгоритмы), OPENSSL_PKCS1_PADDING (по умолчанию для RSA), OPENSSL_NO_PADDING (без дополнения).

Функция возвращает 1 при успешной проверке, 0 при неудаче и -1 в случае ошибки.

Короткие примеры использования
Пример 1: Базовая проверка с RSA ключом
// Генерация ключей
$config = [
    "private_key_bits" => 2048,
];
$keyPair = openssl_pkey_new($config);
openssl_pkey_export($keyPair, $privateKeyPem);
$publicKeyDetails = openssl_pkey_get_details($keyPair);
$publicKeyPem = $publicKeyDetails['key'];

// Данные и подпись
$data = "Важные данные для подписи";
openssl_sign($data, $signature, $privateKeyPem, OPENSSL_ALGO_SHA256);

// Проверка подписи
$result = openssl_verify($data, $signature, $publicKeyPem, OPENSSL_ALGO_SHA256);
echo "Результат проверки: $result\n"; // 1
Результат проверки: 1
Пример 2: Проверка с флагом OPENSSL_PKCS1_PADDING
$result = openssl_verify($data, $signature, $publicKeyPem, OPENSSL_ALGO_SHA256 | OPENSSL_PKCS1_PADDING);
echo "Результат с PKCS1: $result\n";
Результат с PKCS1: 1
Пример 3: Неверная подпись
$wrongSignature = str_repeat('0', 64); // Некорректная подпись
$result = openssl_verify($data, $wrongSignature, $publicKeyPem, OPENSSL_ALGO_SHA256);
echo "Результат с неверной подписью: $result\n";
Результат с неверной подписью: 0
Похожие функции в PHP
  • openssl_sign - создает цифровую подпись. Используется вместе с openssl_verify для полного цикла подписи и проверки.
  • openssl_pkey_verify - альтернативная функция для проверки подписи, принимающая данные в виде массива. Более гибкая для работы с различными форматами данных.
  • hash_hmac_verify - проверяет подпись HMAC, что подходит для симметричного шифрования. Работает быстрее, но требует общего секретного ключа.

Для асимметричной криптографии предпочтительнее openssl_verify, а для симметричной - hash_hmac_verify.

Типичные ошибки
Ошибка 1: Некорректный формат ключа
$wrongKey = "not a key";
$result = openssl_verify($data, $signature, $wrongKey, OPENSSL_ALGO_SHA256);
var_dump($result); // -1
int(-1)
Ошибка 2: Несоответствие алгоритмов
// Подпись создана с SHA256, а проверка с SHA1
$result = openssl_verify($data, $signature, $publicKeyPem, OPENSSL_ALGO_SHA1);
echo "Результат с неверным алгоритмом: $result\n";
Результат с неверным алгоритмом: 0
Ошибка 3: Передача данных в неверном формате
// Подпись в base64 без декодирования
$signatureBase64 = base64_encode($signature);
$result = openssl_verify($data, $signatureBase64, $publicKeyPem, OPENSSL_ALGO_SHA256);
echo "Результат с base64 без декодирования: $result\n";
Результат с base64 без декодирования: 0
Изменения в последних версиях PHP
  • В PHP 8.0 параметр $public_key теперь принимает объекты OpenSSLAsymmetricKey или OpenSSLCertificate вместо ресурсов (resource). Аргумент $algorithm может быть строкой.
  • В PHP 7.2 добавлена возможность использовать строковые имена алгоритмов (например, "sha256WithRSAEncryption") для параметра $algorithm.
  • С PHP 8.1 функция возвращает false при недопустимых значениях аргументов, что улучшает строгость типизации.
Расширенные примеры использования
Пример 1: Проверка подписи с сертификатом X.509
Пример php
// Загрузка сертификата
$certificate = file_get_contents('certificate.pem');
$data = file_get_contents('signed_data.txt');
$signature = file_get_contents('signature.bin');

$result = openssl_verify($data, $signature, $certificate, OPENSSL_ALGO_SHA384);
if ($result === 1) {
    echo "Подпись сертификата действительна.";
} elseif ($result === 0) {
    echo "Подпись недействительна.";
} else {
    echo "Ошибка при проверке: " . openssl_error_string();
}
Подпись сертификата действительна.
Пример 2: Проверка подписи для хэшированных данных
Пример php
// Иногда подпись создается для хэша данных
$rawData = "Исходные данные";
$hash = hash('sha256', $rawData, true); // true - сырой двоичный вывод

// Предположим, что $signature создана для $hash
$result = openssl_verify($hash, $signature, $publicKeyPem, OPENSSL_ALGO_SHA256);
// Важно: алгоритм должен соответствовать тому, что использовался для хэширования
Пример 3: Обработка нескольких подписей для одних данных
Пример php
$signatures = [
    'signature1.bin',
    'signature2.bin'
];
$validSignatures = [];
foreach ($signatures as $sigFile) {
    $sig = file_get_contents($sigFile);
    if (openssl_verify($data, $sig, $publicKeyPem, OPENSSL_ALGO_SHA256) === 1) {
        $validSignatures[] = $sigFile;
    }
}
print_r($validSignatures);
Array
(
    [0] => signature1.bin
)
Пример 4: Использование строкового имени алгоритма
Пример php
$result = openssl_verify(
    $data,
    $signature,
    $publicKeyPem,
    "sha512WithRSAEncryption"
);
echo "Результат со строковым алгоритмом: $result\n";
Результат со строковым алгоритмом: 1
Аналоги в других языках
Python (cryptography)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.exceptions import InvalidSignature

public_key.verify(
    signature,
    data,
    padding.PKCS1v15(),
    hashes.SHA256()
)  # Выбрасывает исключение при ошибке
JavaScript (Node.js crypto)
const crypto = require('crypto');
const verify = crypto.createVerify('SHA256');
verify.update(data);
verify.end();
const isValid = verify.verify(publicKey, signature, 'base64');
// isValid - true/false
MySQL (асимметричное шифрование)

В MySQL нет прямой аналогии для проверки подписи, но есть функции асимметричного шифрования, например, ASYMMETRIC_VERIFY() (доступна в MariaDB).

PHP openssl_verify function comments

En
Openssl verify Verify signature