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

作成日: 更新日:

openssl_sign関数は、指定されたデータに対するデジタル署名を生成する関数です。この関数は、データの送信元が本物であること(認証)と、データが途中で改ざんされていないこと(完全性)を保証するために利用されます。デジタル署名は、手書きのサインのように、特定のデータが特定の秘密鍵の所有者によって承認されたことを証明する電子的な証拠となります。

具体的には、署名したいデータと、その署名に使用する秘密鍵(プライベートキー)および署名アルゴリズムを引数として受け取ります。そして、これらの情報をもとに、一意のデジタル署名データを生成し、出力します。生成されたデジタル署名は、元のデータと共に送信され、受信者は対応する公開鍵(パブリックキー)を使用して、その署名が有効であるか、データが改ざんされていないかを確認することができます。

ウェブアプリケーションやAPI連携など、データが信頼できる形でやり取りされる必要がある様々な場面で、この関数は暗号学的セキュリティの重要な要素として活用され、セキュアな通信やデータの信頼性を確立するのに役立ちます。

基本的な使い方

構文(syntax)

<?php
$dataToSign = 'Message content for digital signature.';
$outputSignature = '';
$privateKeyObject = openssl_pkey_new(['private_key_type' => OPENSSL_KEYTYPE_RSA, 'private_key_bits' => 2048]);
$algorithm = OPENSSL_ALGO_SHA256;

$signingSuccess = openssl_sign($dataToSign, $outputSignature, $privateKeyObject, $algorithm);

openssl_pkey_free($privateKeyObject);

引数(parameters)

string $data, string &$signature, OpenSSLAsymmetricKey|string $private_key, OpenSSLCertificate|string|int $algorithm = OPENSSL_ALGO_SHA1

  • string $data: 署名したいデータ
  • string &$signature: 生成された署名が格納される変数 (参照渡し)
  • OpenSSLAsymmetricKey|string $private_key: 署名に使用する秘密鍵
  • OpenSSLCertificate|string|int $algorithm = OPENSSL_ALGO_SHA1: 署名に使用するアルゴリズム (デフォルトは SHA-1)

戻り値(return)

bool

openssl_sign 関数は、指定されたデータに署名を生成することに成功した場合は true を、失敗した場合は false を返します。

サンプルコード

PHP openssl_signでRSA SHA256署名を生成・検証する

<?php

/**
 * 指定されたデータに対してRSA SHA256署名を生成し、その署名を検証する関数。
 *
 * この関数は、OpenSSL拡張機能を使用してRSA鍵ペアを生成し、
 * 元のデータに秘密鍵で署名を生成します。
 * その後、生成された署名が公開鍵で有効であることを検証します。
 *
 * @param string $originalData 署名する元のデータ。
 * @return bool 署名生成と検証が成功した場合は true、それ以外は false。
 */
function generateAndVerifyRsaSha256Signature(string $originalData): bool
{
    // 1. RSA鍵ペアの生成
    // 秘密鍵と公開鍵のオプションを指定
    $config = [
        "private_key_bits" => 2048, // 鍵のビット長(強度)
        "private_key_type" => OPENSSL_KEYTYPE_RSA, // 鍵のタイプをRSAに指定
    ];

    // 新しい秘密鍵リソースを生成
    $privateKeyResource = openssl_pkey_new($config);

    if ($privateKeyResource === false) {
        echo "エラー: 秘密鍵の生成に失敗しました。\n";
        return false;
    }

    // 秘密鍵をPEM形式の文字列としてエクスポート
    openssl_pkey_export($privateKeyResource, $privateKeyPem);

    // 公開鍵の詳細を取得し、PEM形式の文字列として取得
    $publicKeyDetails = openssl_pkey_get_details($privateKeyResource);
    $publicKeyPem = $publicKeyDetails['key'];

    echo "--- 鍵情報 ---\n";
    echo "秘密鍵 (PEM形式の一部):\n" . substr($privateKeyPem, 0, 100) . "...\n";
    echo "公開鍵 (PEM形式の一部):\n" . substr($publicKeyPem, 0, 100) . "...\n";
    echo "----------------\n\n";

    // 2. データの署名
    $signature = ''; // 生成された署名が格納される変数

    // openssl_sign関数を使用して、元のデータに秘密鍵で署名を生成
    // アルゴリズムとして OPENSSL_ALGO_SHA256 を指定
    $signed = openssl_sign($originalData, $signature, $privateKeyResource, OPENSSL_ALGO_SHA256);

    if ($signed === false) {
        echo "エラー: データの署名に失敗しました。\n";
        // OpenSSLのエラーキューからエラーメッセージを取得
        while ($msg = openssl_error_string()) {
            echo $msg . "\n";
        }
        return false;
    }

    echo "--- 署名情報 ---\n";
    echo "元のデータ: " . $originalData . "\n";
    // 署名はバイナリデータなので、表示のためにBase64エンコード
    echo "署名 (Base64エンコード): " . base64_encode($signature) . "\n";
    echo "----------------\n\n";

    // 3. 署名の検証
    // openssl_verify関数を使用して、公開鍵で署名を検証
    $verified = openssl_verify($originalData, $signature, $publicKeyPem, OPENSSL_ALGO_SHA256);

    echo "--- 検証結果 ---\n";
    if ($verified === 1) {
        echo "署名は有効です。\n";
        return true;
    } elseif ($verified === 0) {
        echo "署名は無効です。\n";
        return false;
    } else {
        echo "エラー: 署名の検証中に問題が発生しました。\n";
        // OpenSSLのエラーキューからエラーメッセージを取得
        while ($msg = openssl_error_string()) {
            echo $msg . "\n";
        }
        return false;
    }
    echo "----------------\n";
}

// サンプルデータの定義と関数の実行
$testData = "これはRSA SHA256で署名されるべき重要なデータです。セキュリティテストのために使用します。";

if (generateAndVerifyRsaSha256Signature($testData)) {
    echo "\nプロセス全体が成功しました。署名が正しく生成され、検証されました。\n";
} else {
    echo "\nプロセス中にエラーが発生しました。署名または検証に失敗しました。\n";
}

?>

このPHPサンプルコードは、openssl_sign関数を利用したデジタル署名の生成と検証のプロセスを、システムエンジニアを目指す初心者の方にも分かりやすく解説しています。

まず、openssl_pkey_new関数により、署名に用いるRSA鍵ペア(秘密鍵と公開鍵)を生成します。

次に、openssl_sign関数が呼び出されます。この関数は、最初の引数 $data で指定された元のデータに対して、第三引数 $private_key の秘密鍵を用いてデジタル署名を生成します。第二引数 $signature は参照渡しで、ここに生成されたバイナリ形式の署名データが格納されます。第四引数 $algorithm には OPENSSL_ALGO_SHA256 を指定し、SHA256ハッシュアルゴリズムを利用することを示しています。この関数は、署名処理が成功した場合にブール値の true を、失敗した場合に false を返します。

生成された署名は、対応する公開鍵とopenssl_verify関数を使って検証されます。検証が成功すれば、データが改ざんされておらず、秘密鍵の所有者によって署名されたことが保証されます。この一連の処理は、データの完全性と送信者の認証を確保するために重要な技術です。

このサンプルコードで生成される秘密鍵は極めて重要であり、本番環境ではコードに直接記述せず、安全なファイルや専用のサービスから読み込むなど厳重な管理を徹底してください。署名アルゴリズムには常に安全性が確認されているものを選択し、鍵のビット長もセキュリティ要件に合わせて適切に設定することが重要です。openssl_signで得られる署名はバイナリデータのため、データベース保存やネットワーク転送の際にはBase64エンコードなどでテキスト化する必要があります。エラー発生時にはopenssl_error_string()を使って詳細なエラーメッセージを必ず取得し、適切なエラー処理を実装してください。鍵の生成は処理コストがかかるため、実際のシステムでは一度生成またはロードした鍵を再利用するのが一般的です。

PHP OpenSSL で署名と検証を行う

<?php

/**
 * Demonstrates how to sign data with a private key and verify it with a public key using OpenSSL functions.
 *
 * This function generates a new private/public key pair, signs a sample string,
 * and then attempts to verify the signature.
 */
function demonstrateOpensslSignatureVerification(): void
{
    // 1. Generate a new private key and extract the corresponding public key.
    // In a real application, keys would typically be loaded from secure storage, not generated on-the-fly.
    $privateKeyResource = openssl_pkey_new([
        'private_key_bits' => 2048,           // Key length in bits (e.g., 2048, 4096)
        'private_key_type' => OPENSSL_KEYTYPE_RSA, // Type of key to generate
    ]);

    if (!$privateKeyResource) {
        echo "Error: Could not generate private key. Check OpenSSL configuration.\n";
        return;
    }

    // Export the private key to a string
    openssl_pkey_export($privateKeyResource, $privateKeyString);

    // Get details from the private key resource to extract the public key
    $keyDetails = openssl_pkey_get_details($privateKeyResource);
    $publicKeyString = $keyDetails['key'];

    echo "--- Key Pair Generated Successfully ---\n";
    // For demonstration purposes, we acknowledge keys are generated.
    // In production, NEVER output private keys.
    echo "Private key and public key strings are now available.\n\n";

    // 2. Define the data that needs to be signed.
    $dataToSign = "This is the sensitive data that will be signed to ensure its integrity and authenticity.";
    echo "Data to sign: \"" . $dataToSign . "\"\n\n";

    // 3. Sign the data using the private key.
    // The signature is returned by reference in the $signature variable.
    // OPENSSL_ALGO_SHA256 is commonly used for hashing before signing.
    $signature = ''; // Initialize the signature variable
    $signedSuccessfully = openssl_sign($dataToSign, $signature, $privateKeyString, OPENSSL_ALGO_SHA256);

    if (!$signedSuccessfully) {
        echo "Error: Data signing failed.\n";
        openssl_pkey_free($privateKeyResource);
        return;
    }

    echo "Data signed successfully. Signature (base64 encoded for display): " . base64_encode($signature) . "\n\n";

    // 4. Verify the signature using the public key, the original data, and the generated signature.
    // The public key can only verify a signature created by its corresponding private key.
    $verificationResult = openssl_verify($dataToSign, $signature, $publicKeyString, OPENSSL_ALGO_SHA256);

    echo "--- Signature Verification Result ---\n";
    if ($verificationResult === 1) {
        echo "Verification SUCCESS: The signature is valid. The data is authentic and has not been tampered with.\n";
    } elseif ($verificationResult === 0) {
        echo "Verification FAILED: The signature is invalid. The data might have been altered or the signature is incorrect.\n";
    } else { // Returns -1 on error
        echo "Verification ERROR: An error occurred during the verification process.\n";
        while ($msg = openssl_error_string()) {
            echo "OpenSSL Error: " . $msg . "\n";
        }
    }

    // Clean up the key resource to free memory.
    openssl_pkey_free($privateKeyResource);
}

// Execute the demonstration function.
demonstrateOpensslSignatureVerification();

PHPのopenssl_sign関数は、指定されたデータのデジタル署名を作成するために使用されます。デジタル署名は、データが改ざんされていないこと(データの完全性)や、それが信頼できる送り手によって作成されたものであること(データの認証)を保証する重要な手段です。

この関数は、署名したいデータ本体を$dataとして受け取ります。生成された署名データは、&$signatureに参照渡しで格納されます。署名処理には、署名者の秘密鍵が$private_keyとして必要です。また、署名前にデータをハッシュ化するアルゴリズムを$algorithmで指定できますが、指定しない場合はOPENSSL_ALGO_SHA1がデフォルトで使用されます。関数が署名に成功した場合はtrueを、失敗した場合はfalseを返します。

サンプルコードでは、まず秘密鍵と公開鍵のペアを生成し、その秘密鍵を使って「This is the sensitive data...」という文字列をopenssl_sign関数で署名しています。生成された署名は、対応する公開鍵と元のデータ、そして署名データをopenssl_verify関数に渡すことで検証可能です。検証結果が1であれば署名が有効であり、データが改ざんされていないことを示します。0であれば署名が無効、-1であれば検証中にエラーが発生したことを意味します。この一連の流れにより、データの信頼性とセキュリティを確保できます。

実際のシステムでは、秘密鍵は通常安全な場所から読み込み、毎回生成しない点に注意してください。秘密鍵は非常に重要であり、絶対に公開せず厳重に管理する必要があります。漏洩するとデータの偽造につながります。署名時に指定するハッシュアルゴリズムは、OPENSSL_ALGO_SHA256のように安全性の高いものを選びましょう。古いアルゴリズムは脆弱である可能性があります。openssl_sign関数は署名結果を引数($signature)の参照に格納します。また、OpenSSL関数の実行後は常にエラーチェックを行い、openssl_error_string()で詳細を確認する習慣をつけましょう。署名には秘密鍵を使い、その検証には対応する公開鍵を使うという非対称暗号の基本を理解することが重要です。

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