【PHP8.x】openssl_verify関数の使い方

作成日: 更新日:

openssl_verify関数は、デジタル署名が正当なものであるかを検証する関数です。この関数は、あるデータに付与されたデジタル署名が、意図した送信者によって作成され、かつそのデータが途中で改ざんされていないことを確認するために使用されます。これにより、データの信頼性と完全性を保証します。

デジタル署名の検証は、現代のデジタル通信において非常に重要なセキュリティプロセスです。この関数を利用するには、検証対象となる元のデータ(例えばファイルの内容やメッセージ)、そのデータに紐付けられたデジタル署名、署名者の公開鍵、そして署名生成時に使用されたハッシュアルゴリズムを引数として指定します。関数はこれらの情報に基づいて、提供された署名が有効であるかどうかを精密に検査します。

検証が成功した場合、関数は整数値の 1 を返します。これは、データが信頼できる送信元からのものであり、その内容が署名後に一切改ざんされていないことを示します。もし署名が無効であるか、データが変更されていると判断された場合は 0 を返します。また、OpenSSLライブラリの内部エラーなど、検証処理中に何らかの問題が発生した場合は -1 を返してエラーを通知します。

この機能は、ウェブサイトからダウンロードしたソフトウェアの真偽を確認したり、セキュアなAPI通信におけるメッセージの改ざん防止や送信元認証を行うなど、多岐にわたる用途でデータの信頼性とセキュリティを確保するために不可欠な要素です。

基本的な使い方

構文(syntax)

<?php
// 検証対象の元のデータ文字列
$data = 'Original data string to be verified.';

// 署名データ (バイナリ形式)
$signature = 'バイナリ形式の署名データ'; // 例: base64_decode() でデコードされたもの

// 公開鍵 (PEM形式の文字列、または OpenSSLAsymmetricKey オブジェクト)
$publicKey = '-----BEGIN PUBLIC KEY-----PEM形式の公開鍵-----END PUBLIC KEY-----'; // 例: openssl_get_publickey() で取得

// 署名に使用されたハッシュアルゴリズム
$algorithm = OPENSSL_ALGO_SHA256; // 例: 'sha256' や OPENSSL_ALGO_SHA1 など

// openssl_verify 関数の呼び出し構文
$verificationResult = openssl_verify($data, $signature, $publicKey, $algorithm);
?>

引数(parameters)

string $data, string $signature, mixed $public_key, string|int $algorithm = OPENSSL_ALGO_SHA1

  • string $data: 検証する元のデータ
  • string $signature: 検証に使用する署名
  • mixed $public_key: 公開鍵
  • string|int $algorithm = OPENSSL_ALGO_SHA1: 使用する署名アルゴリズム

戻り値(return)

int|false

openssl_verify 関数は、指定された署名が公開鍵によって検証されたかどうかを示す整数値を返します。検証に成功した場合は 1、失敗した場合は 0、エラーが発生した場合は false を返します。

サンプルコード

PHP openssl_verify で署名を検証する

<?php

// このスクリプトは、`openssl_verify` 関数を使用してデジタル署名を検証する方法を示します。
// 署名の生成から検証、そして検証失敗のシナリオまで、完全なフローを実演します。

// 1. RSA秘密鍵を生成します。
// 2048ビットは現代において一般的に推奨される鍵長です。
$privateKey = openssl_pkey_new([
    "private_key_bits" => 2048,
    "private_key_type" => OPENSSL_KEYTYPE_RSA,
]);

if (!$privateKey) {
    die("エラー: 秘密鍵の生成に失敗しました。\n" . openssl_error_string());
}

// 2. 自己署名証明書を生成し、そこから公開鍵を抽出します。
// `openssl_verify` はPEM形式の公開鍵文字列または証明書リソースを受け入れます。
// ここでは、自己署名証明書を作成し、そこからPEM形式の公開鍵文字列を抽出して使用します。
$csr = openssl_csr_new([], $privateKey, ['digest_alg' => 'sha256']);
$certificate = openssl_csr_sign($csr, null, $privateKey, $days = 365, ['digest_alg' => 'sha256']);

if (!$certificate) {
    die("エラー: 証明書の生成に失敗しました。\n" . openssl_error_string());
}

// 証明書から公開鍵の詳細を抽出し、PEM形式の公開鍵文字列を取得します。
$publicKeyDetails = openssl_pkey_get_details($certificate);
$publicKeyPem = $publicKeyDetails['key'];

// 3. 署名するデータを用意します。
$dataToSign = "これはデジタル署名される重要なデータです。";

// 4. 秘密鍵を使用してデータを署名します。
// 署名アルゴリズムにはSHA256を使用します。
$signature = '';
$signingSuccess = openssl_sign($dataToSign, $signature, $privateKey, OPENSSL_ALGO_SHA256);

if (!$signingSuccess) {
    die("エラー: データの署名に失敗しました。\n" . openssl_error_string());
}

echo "オリジナルデータ: " . $dataToSign . "\n";
echo "生成された署名 (base64エンコード): " . base64_encode($signature) . "\n\n";

// 5. 公開鍵を使用して署名を検証します。
// 検証アルゴリズムは署名時に使用したもの (OPENSSL_ALGO_SHA256) と一致させる必要があります。
echo "--- 検証試行1: 有効なデータと署名 ---\n";
$verificationResult = openssl_verify($dataToSign, $signature, $publicKeyPem, OPENSSL_ALGO_SHA256);

if ($verificationResult === 1) {
    echo "検証成功: 署名はデータに対して有効です。\n";
} elseif ($verificationResult === 0) {
    echo "検証失敗: 署名はデータに対して無効です (データまたは署名が改ざんされた可能性があります)。\n";
} else { // -1 または false の場合、関数実行中にエラーが発生
    echo "検証中にエラーが発生しました: " . openssl_error_string() . "\n";
}
echo "\n";

// --- 「検証失敗」シナリオのデモンストレーション ---

// シナリオ1: データが改ざんされた場合
echo "--- 検証試行2: データ改ざんのケース ---\n";
$tamperedData = "これは改ざんされたデータです。"; // オリジナルデータと異なる
$verificationResultTamperedData = openssl_verify($tamperedData, $signature, $publicKeyPem, OPENSSL_ALGO_SHA256);

if ($verificationResultTamperedData === 1) {
    echo "検証成功 (誤り): データが改ざんされているにもかかわらず成功してしまいました。\n";
} elseif ($verificationResultTamperedData === 0) {
    echo "検証失敗 (期待通り): データが改ざんされたため、検証に失敗しました。\n";
} else {
    echo "改ざんされたデータの検証中にエラーが発生しました: " . openssl_error_string() . "\n";
}
echo "\n";

// シナリオ2: 署名が改ざんされた場合 (または不正な署名)
echo "--- 検証試行3: 署名改ざんのケース ---\n";
$tamperedSignature = 'INVALID' . $signature; // 署名を単純に変更して無効にします
$verificationResultTamperedSignature = openssl_verify($dataToSign, $tamperedSignature, $publicKeyPem, OPENSSL_ALGO_SHA256);

if ($verificationResultTamperedSignature === 1) {
    echo "検証成功 (誤り): 署名が改ざんされているにもかかわらず成功してしまいました。\n";
} elseif ($verificationResultTamperedSignature === 0) {
    echo "検証失敗 (期待通り): 署名が改ざんされたため、検証に失敗しました。\n";
} else {
    echo "改ざんされた署名の検証中にエラーが発生しました: " . openssl_error_string() . "\n";
}
echo "\n";

// 使用したOpenSSLリソースを解放します。
openssl_pkey_free($privateKey);
openssl_x509_free($certificate);

?>

PHP 8.4.12のopenssl_verify関数は、デジタル署名が特定のデータに対して有効であるかを検証するために使用されます。これにより、データの改ざんがないことや、署名者が意図した本人であることを確認できます。

このサンプルコードでは、まずRSA秘密鍵を生成し、そこから公開鍵を抽出しています。次に、「これはデジタル署名される重要なデータです。」という文字列($data引数)を秘密鍵で署名し、その結果得られたデジタル署名($signature引数)を準備します。

openssl_verify関数は、この元のデータ、署名、そして公開鍵($public_key引数にはPEM形式の公開鍵文字列や証明書リソースが渡されます)と、署名時に使用したアルゴリズム($algorithm引数)を受け取り、検証を実行します。

検証が成功した場合は戻り値として整数1を返し、署名が無効(データや署名が改ざんされた可能性)な場合は0を返します。関数実行中にエラーが発生した場合は-1またはfalseを返します。サンプルコードでは、データの改ざんや署名の改ざんといった「検証失敗」シナリオも具体的に示されており、この関数がデータの完全性を保証する上で重要であることを理解できます。

openssl_verify関数はデジタル署名の正当性を確認する際に用いられます。この関数を使用する際は、署名時に利用したアルゴリズム(例: OPENSSL_ALGO_SHA256)と検証時に指定するアルゴリズムが完全に一致しているか、必ず確認してください。また、公開鍵はPEM形式の文字列または適切なOpenSSLリソースとして提供する必要があります。関数の戻り値は、検証成功が1、失敗が0、関数実行中のエラーが-1またはfalseとなるため、それぞれのケースを厳密に判断し、適切なエラーハンドリングを行うことが重要です。エラー発生時はopenssl_error_string()で詳細を確認し、デバッグに活用してください。鍵などのOpenSSLリソースは、使用後に必ず解放するようにしてください。

PHP openssl_verifyで署名を検証する

<?php

/**
 * openssl_verify 関数を使用したデジタル署名検証のサンプルコードです。
 *
 * この関数は、データが秘密鍵で署名され、その署名が公開鍵によって
 * 正しく検証できることを示します。
 *
 * システムエンジニアを目指す初心者向けに、デジタル署名の基本的な流れと
 * PHPでの実装方法を理解しやすいように構成されています。
 */
function verifyDigitalSignatureExample(): void
{
    echo "--- デジタル署名検証サンプル開始 ---\n\n";

    // 1. 署名対象の元のデータを用意します。
    // このデータが後で秘密鍵によって署名され、公開鍵で検証されます。
    $originalData = "このメッセージはデジタル署名によって保護されます。";
    echo "元のデータ: \"" . $originalData . "\"\n\n";

    // 2. 秘密鍵と公開鍵のペアを生成します。
    // 実際のシステムでは、通常、これらの鍵は事前に生成され、安全に保管されます。
    // ここではデモンストレーションのためにコード内で一時的に生成します。
    $config = [
        "private_key_bits" => 2048, // 鍵のビット長(強度の指標、一般的に2048ビット以上が推奨)
        "private_key_type" => OPENSSL_KEYTYPE_RSA, // RSAアルゴリズムを使用
    ];

    // openssl_pkey_new() は新しい秘密鍵を生成し、そのリソースを返します。
    $privateKeyResource = openssl_pkey_new($config);

    if ($privateKeyResource === false) {
        echo "エラー: 秘密鍵の生成に失敗しました。\n";
        // openssl_error_string() でOpenSSLのエラーメッセージを取得できます。
        while ($msg = openssl_error_string()) {
            echo "OpenSSLエラー: " . $msg . "\n";
        }
        return;
    }

    // 秘密鍵をPEM形式の文字列としてエクスポートします。
    $privateKey = '';
    if (!openssl_pkey_export($privateKeyResource, $privateKey)) {
        echo "エラー: 秘密鍵のエクスポートに失敗しました。\n";
        while ($msg = openssl_error_string()) {
            echo "OpenSSLエラー: " . $msg . "\n";
        }
        openssl_free_key($privateKeyResource);
        return;
    }

    // 公開鍵の詳細を取得し、PEM形式の文字列として抽出します。
    $publicKeyDetails = openssl_pkey_get_details($privateKeyResource);
    if ($publicKeyDetails === false || !isset($publicKeyDetails['key'])) {
        echo "エラー: 公開鍵の取得に失敗しました。\n";
        while ($msg = openssl_error_string()) {
            echo "OpenSSLエラー: " . $msg . "\n";
        }
        openssl_free_key($privateKeyResource);
        return;
    }
    $publicKey = $publicKeyDetails['key'];

    echo "--- 鍵ペア生成完了 ---\n";
    // 秘密鍵はセキュリティ上の理由から表示しません。
    echo "公開鍵の一部 (PEM):\n" . substr($publicKey, 0, 100) . "...\n\n"; // 長いので一部のみ表示

    // 3. 秘密鍵を使ってデータを署名します。
    // openssl_sign() は、指定されたデータと秘密鍵を使用してデジタル署名を作成します。
    // OPENSSL_ALGO_SHA256 は、署名にSHA256ハッシュアルゴリズムを使用することを示します。
    $signature = ''; // 署名結果を格納する変数
    if (!openssl_sign($originalData, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
        echo "エラー: データの署名に失敗しました。\n";
        while ($msg = openssl_error_string()) {
            echo "OpenSSLエラー: " . $msg . "\n";
        }
        openssl_free_key($privateKeyResource);
        return;
    }

    echo "--- 署名処理完了 ---\n";
    // 署名はバイナリデータなので、表示のためにBase64エンコードします。
    echo "生成された署名 (Base64エンコード): " . base64_encode($signature) . "\n\n";

    // 4. 公開鍵を使って署名を検証します。
    // openssl_verify() は、元のデータ、生成された署名、および公開鍵が一致するかを検証します。
    // 署名アルゴリズムも、署名時と同じものを指定する必要があります。
    //
    // 戻り値:
    //   1: 署名が有効である (データは改ざんされておらず、署名が正しい)
    //   0: 署名が無効である (データが改ざんされたか、署名が正しくない)
    //  -1: 検証中にエラーが発生した
    $verificationResult = openssl_verify($originalData, $signature, $publicKey, OPENSSL_ALGO_SHA256);

    echo "--- 署名検証結果 ---\n";
    if ($verificationResult === 1) {
        echo "✓ 署名が正常に検証されました。データは改ざんされていません。\n";
    } elseif ($verificationResult === 0) {
        echo "✗ 署名検証に失敗しました。データが改ざんされたか、署名が正しくありません。\n";
    } else { // $verificationResult === -1
        echo "✗ 署名検証中にエラーが発生しました。\n";
        while ($msg = openssl_error_string()) {
            echo "OpenSSLエラー: " . $msg . "\n";
        }
    }
    echo "\n--- デジタル署名検証サンプル終了 ---\n";

    // 使用した鍵リソースを解放します。
    openssl_free_key($privateKeyResource);
}

// サンプル関数を実行します。
verifyDigitalSignatureExample();

PHPのopenssl_verify関数は、デジタル署名の検証を行うために使用されます。この関数は、あるデータが秘密鍵によって署名され、その署名が対応する公開鍵によって正しく作成されたものであるかを確認します。これにより、データの改ざんがないことと、署名者が確かに意図した本人であること(認証)を保証できます。

この関数は四つの引数を取ります。$dataは検証対象の元のデータ、$signatureは検証したいデジタル署名、$public_keyは署名作成時に使用された秘密鍵と対になる公開鍵、そして$algorithmは署名生成時に使用したハッシュアルゴリズムを指定します。

検証の結果は整数値で返されます。戻り値が1の場合、署名が有効であり、データが改ざんされていないことを示します。0の場合は署名が無効であり、データが改ざんされたか、署名が正しくない可能性を示唆します。また、-1が返された場合は、検証処理中にエラーが発生したことを意味します。この関数は、openssl_sign関数で作成された署名の正当性を確認する際に不可欠です。

openssl_verify関数はデジタル署名の正当性を確認する際に利用されます。この関数の利用で最も重要なのは、署名を作成した際の元のデータ、秘密鍵に対応する公開鍵、そして使用されたハッシュアルゴリズムが、検証時と完全に一致していることです。特にアルゴリズムは、署名時と検証時で異なる場合、正しい署名であっても検証に失敗しますので注意してください。秘密鍵は決して外部に漏らしてはならず、本番環境では鍵の厳重な管理と安全な生成方法を考慮する必要があります。また、検証結果が-1の場合はエラーが発生しているため、openssl_error_string()関数で詳細を確認し、適切なエラーハンドリングを行うことが重要です。鍵リソースを使い終わったらopenssl_free_key()で必ず解放しましょう。

【PHP8.x】openssl_verify関数の使い方 | いっしー@Webエンジニア