【PHP8.x】sodium_crypto_sign_open()関数の使い方
sodium_crypto_sign_open関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
sodium_crypto_sign_open関数は、デジタル署名が施されたメッセージを検証し、元のメッセージを安全に復元する関数です。この関数は、受け取ったメッセージが途中で改ざんされていないこと、そして特定の送信者(公開鍵の持ち主)によって署名されたものであることを確認するために使用されます。
具体的には、署名付きのメッセージと、その署名を作成した送信者の公開鍵の2つを引数として受け取ります。内部で署名を検証し、メッセージが公開鍵に対応する秘密鍵で正しく署名されており、かつメッセージの内容が検証時から変更されていないことを確認します。
検証に成功した場合、つまりメッセージが真正であり改ざんされていないと判断された場合のみ、元の(署名される前の)メッセージのデータが返されます。もし署名が無効である、あるいはメッセージが改ざんされていると検出された場合は、検証が失敗し、安全なメッセージの復元は行われません。
この機能は、セキュアな通信やデータ保存において、情報の信頼性(インテグリティ)と認証(オーセンティケーション)を保証するための重要な要素となります。特に、信頼できない環境下でデータを受け取る際に、そのデータの正当性を確認する場面で不可欠です。
構文(syntax)
1<?php 2 3$original_message = sodium_crypto_sign_open($signed_message, $public_key); 4 5?>
引数(parameters)
string $signed_message, string $public_key
- string $signed_message: 署名されたメッセージ本体と署名が含まれる文字列。
- string $public_key: 検証に使用する公開鍵の文字列。
戻り値(return)
string|false
指定された署名を検証し、元のメッセージ(平文)を返します。検証に失敗した場合は false を返します。
サンプルコード
PHP sodium_crypto_sign_openでメッセージ検証する
1<?php 2 3// Check if the sodium extension is loaded. 4// If you encounter an 'undefined symbol' error like 'crypto_core_ristretto255_sub', 5// it often means your PHP 'sodium' extension was compiled against a newer version of 6// the 'libsodium' library than is currently available on your system. 7// Ensure 'libsodium' (version 1.0.18 or newer for ristretto255 functions, though not directly used by sign_open) 8// is installed and the PHP 'sodium' extension is properly linked against it. 9if (!extension_loaded('sodium')) { 10 echo "Error: The 'sodium' PHP extension is not loaded.\n"; 11 echo "Please ensure it is installed and enabled in your php.ini.\n"; 12 exit(1); 13} 14 15/** 16 * Demonstrates how to use sodium_crypto_sign to sign a message 17 * and then sodium_crypto_sign_open to verify it. 18 * 19 * This process ensures message integrity (it hasn't been altered) 20 * and authenticity (it comes from the expected sender). 21 */ 22function demonstrate_sodium_signing_and_verification(): void 23{ 24 echo "--- Cryptographic Message Signing and Verification (Ed25519) ---\n\n"; 25 26 // 1. Generate a signing key pair. 27 // This creates a pair of keys: a secret key for signing and a public key for verification. 28 // The secret key must be kept confidential by the signer. 29 $keypair = sodium_crypto_sign_keypair(); 30 $secretKey = sodium_crypto_sign_secretkey($keypair); 31 $publicKey = sodium_crypto_sign_publickey($keypair); 32 33 echo "Generated Key Pair (Public Key shown, Secret Key kept confidential):\n"; 34 echo "Public Key (hex): " . bin2hex($publicKey) . "\n\n"; 35 36 // 2. Define the original message to be signed. 37 $originalMessage = "Hello, System Engineer Beginner! This message is for integrity testing."; 38 echo "Original Message: \"" . $originalMessage . "\"\n\n"; 39 40 // 3. Sign the message using the secret key. 41 // The `sodium_crypto_sign` function prepends the signature to the original message. 42 $signedMessage = sodium_crypto_sign($originalMessage, $secretKey); 43 44 echo "Message successfully signed.\n"; 45 echo "Length of signed message (signature + original message): " . strlen($signedMessage) . " bytes\n"; 46 echo "Length of signature itself: " . SODIUM_CRYPTO_SIGN_BYTES . " bytes\n\n"; 47 48 // 4. Verify the signed message using `sodium_crypto_sign_open` and the public key. 49 // If the signature is valid, `sodium_crypto_sign_open` returns the original message. 50 // If the signature is invalid (e.g., message tampered with or wrong key used), it returns `false`. 51 $verifiedMessage = sodium_crypto_sign_open($signedMessage, $publicKey); 52 53 if ($verifiedMessage === false) { 54 echo "Verification FAILED: The message could not be verified (signature invalid or tampered).\n\n"; 55 } else { 56 echo "Verification SUCCESSFUL!\n"; 57 echo "Extracted Message: \"" . $verifiedMessage . "\"\n\n"; 58 59 // Compare the extracted message with the original to confirm integrity. 60 if ($verifiedMessage === $originalMessage) { 61 echo "The extracted message matches the original. Integrity and authenticity confirmed.\n\n"; 62 } else { 63 // This case should ideally not happen if verification succeeds with the correct key. 64 echo "Error: Extracted message did not match the original, despite successful verification.\n\n"; 65 } 66 } 67 68 // --- Example of a failed verification (e.g., message tampering) --- 69 echo "--- Demonstrating a failed verification (simulated tampering) ---\n"; 70 71 // Create a tampered version of the signed message by changing one byte in the message part. 72 $tamperedSignedMessage = $signedMessage; 73 // Change a byte *after* the signature, within the message part 74 $tamperedSignedMessage[SODIUM_CRYPTO_SIGN_BYTES + 10] = chr(ord($tamperedSignedMessage[SODIUM_CRYPTO_SIGN_BYTES + 10]) ^ 0xFF); // Flip some bits 75 76 $verifiedTamperedMessage = sodium_crypto_sign_open($tamperedSignedMessage, $publicKey); 77 78 if ($verifiedTamperedMessage === false) { 79 echo "Verification correctly FAILED for the tampered message. Security check passed.\n\n"; 80 } else { 81 echo "Error: Tampered message was incorrectly verified as valid!\n\n"; 82 } 83 84 // --- Example of a failed verification (e.g., wrong public key) --- 85 echo "--- Demonstrating a failed verification (simulated wrong public key) ---\n"; 86 $wrongKeypair = sodium_crypto_sign_keypair(); // Generate a different keypair 87 $wrongPublicKey = sodium_crypto_sign_publickey($wrongKeypair); 88 89 $verifiedWithWrongKey = sodium_crypto_sign_open($signedMessage, $wrongPublicKey); 90 91 if ($verifiedWithWrongKey === false) { 92 echo "Verification correctly FAILED using a different (wrong) public key. Security check passed.\n\n"; 93 } else { 94 echo "Error: Message was incorrectly verified with a wrong public key!\n\n"; 95 } 96} 97 98// Execute the demonstration function. 99demonstrate_sodium_signing_and_verification(); 100 101?>
PHP 8のsodium_crypto_sign_open関数は、電子署名付きメッセージの検証を行うために利用されます。この関数は、メッセージが改ざんされていないか、そして期待される送信者から送られたものか(真正性)を確認する重要なセキュリティ機能を提供します。
引数としては、string $signed_messageにsodium_crypto_sign関数で署名されたメッセージ全体を、string $public_keyにそのメッセージを署名した者の公開鍵を指定します。もし署名が正しく、メッセージが改ざんされていない場合は、署名を取り除いた元のメッセージがstringとして返されます。しかし、署名が不正であるか、メッセージが少しでも改ざんされていた場合はfalseが戻り値として返され、検証に失敗したことを示します。
サンプルコードでは、まず秘密鍵と公開鍵のペアを生成し、秘密鍵でメッセージを署名します。その後、sodium_crypto_sign_open関数と公開鍵を使ってこの署名済みメッセージを検証し、元のメッセージが正しく復元されることを示しています。また、意図的にメッセージを改ざんしたり、異なる公開鍵を使用したりした場合に検証が失敗する例も示されており、この関数のセキュリティ特性を理解できます。
この機能を使用するにはPHPのsodium拡張機能が有効になっている必要があります。もし「undefined symbol」のようなエラーが発生する場合は、libsodiumライブラリの適切なバージョンがシステムにインストールされており、PHPのsodium拡張機能がそれに正しくリンクされているかを確認してください。
PHPのsodium_crypto_sign_open関数を利用するには、まずsodium拡張機能が有効であることを確認してください。もしundefined symbolのようなエラーが発生した場合は、PHP拡張機能とlibsodiumライブラリのバージョンが一致しているか確認が必要です。この関数は、署名されたメッセージと公開鍵を使い、メッセージが改ざんされていないか、正しい送信者からのものかを検証します。検証に失敗した場合、戻り値はfalseとなるため、必ずこのfalseをチェックし、適切なエラー処理を行うようにしてください。メッセージの署名に用いる秘密鍵は厳重に管理し、決して外部に漏らさないことが重要です。公開鍵はメッセージの検証にのみ利用します。
PHP Sodium: 署名検証でメッセージを復元する
1<?php 2 3/** 4 * PHPのSodium拡張を利用してデジタル署名の生成と検証を行うサンプルコードです。 5 * sodium_crypto_sign_open関数は、署名されたメッセージと公開鍵から、 6 * メッセージの正当性を検証し、元のメッセージを復元するために使用されます。 7 * 8 * システムエンジニアを目指す初心者の方にも理解しやすいよう、 9 * 以下の流れで処理をデモンストレーションします。 10 * 1. 署名用の鍵ペア(公開鍵と秘密鍵)を生成します。 11 * 2. 秘密鍵を使用してメッセージに署名し、署名済みメッセージを生成します。 12 * 3. 公開鍵を使用して署名済みメッセージを検証し、元のメッセージを復元します。 13 * 4. メッセージが改ざんされた場合の検証失敗例を示します。 14 * 5. 異なる公開鍵で検証した場合の失敗例を示します。 15 */ 16function demonstrateSodiumSignatureVerification(): void 17{ 18 echo "--- Sodium デジタル署名検証デモンストレーション ---\n\n"; 19 20 // 1. 署名用の鍵ペア(公開鍵と秘密鍵)を生成します。 21 // sodium_crypto_sign_keypair() は、署名と検証に必要な鍵のペアを生成します。 22 // 生成された鍵ペアから、それぞれ秘密鍵と公開鍵を抽出します。 23 $keyPair = sodium_crypto_sign_keypair(); 24 $publicKey = sodium_crypto_sign_publickey($keyPair); 25 $secretKey = sodium_crypto_sign_secretkey($keyPair); 26 27 echo "✅ 鍵ペアを生成しました。\n"; 28 // 実際のアプリケーションでは秘密鍵は厳重に管理する必要があります。 29 // echo "公開鍵 (Hex): " . bin2hex($publicKey) . "\n"; 30 // echo "秘密鍵 (Hex): " . bin2hex($secretKey) . "\n\n"; // デバッグ目的以外では表示しない 31 32 // 署名するオリジナルのメッセージ 33 $originalMessage = "これはデジタル署名によって保護されるべき重要なメッセージです。"; 34 echo "オリジナルメッセージ: '" . $originalMessage . "'\n\n"; 35 36 // 2. メッセージを秘密鍵で署名します。 37 // sodium_crypto_sign() は、オリジナルメッセージと署名を連結したバイナリ文字列を返します。 38 echo "➡️ メッセージを秘密鍵で署名しています...\n"; 39 $signedMessage = sodium_crypto_sign($originalMessage, $secretKey); 40 echo "✅ メッセージが署名されました。\n"; 41 // echo "生成された署名済みメッセージ (Hex): " . bin2hex($signedMessage) . "\n\n"; // デバッグ目的以外では表示しない 42 43 echo "--- 署名済みメッセージの検証 --- \n"; 44 45 // 3. 署名済みメッセージを公開鍵で検証します。 46 // sodium_crypto_sign_open() は、署名が有効であれば元のメッセージを返します。 47 // 署名が無効な場合(メッセージが改ざんされた、または異なる鍵で署名された)は false を返します。 48 echo "➡️ 署名済みメッセージを公開鍵で検証しています...\n"; 49 $verifiedMessage = sodium_crypto_sign_open($signedMessage, $publicKey); 50 51 if ($verifiedMessage !== false) { 52 echo "✅ 署名検証成功! メッセージの正当性が確認されました。\n"; 53 echo "復元されたメッセージ: '" . $verifiedMessage . "'\n\n"; 54 } else { 55 echo "❌ 署名検証失敗! メッセージの正当性を確認できませんでした。\n\n"; 56 } 57 58 // 4. メッセージを改ざんした場合の検証失敗の例 59 echo "--- 改ざんされたメッセージでの検証 --- \n"; 60 echo "➡️ 署名済みメッセージの一部を意図的に改ざんします...\n"; 61 // 署名済みメッセージの末尾の1バイトを意図的に変更して改ざんをシミュレート 62 $tamperedSignedMessage = substr($signedMessage, 0, -1) . chr(ord($signedMessage[strlen($signedMessage) - 1]) ^ 0xFF); 63 // 署名の長さが足りない場合など、不正な形式のデータが渡された場合もfalseが返る 64 if (strlen($tamperedSignedMessage) < SODIUM_CRYPTO_SIGN_BYTES + 1) { // SODIUM_CRYPTO_SIGN_BYTES は署名部分のサイズ 65 $tamperedSignedMessage = $signedMessage . 'A'; // 長さを変える改ざん 66 } 67 echo "✅ メッセージが改ざんされました。\n"; 68 // echo "改ざんされた署名済みメッセージ (Hex): " . bin2hex($tamperedSignedMessage) . "\n\n"; 69 70 echo "➡️ 改ざんされたメッセージを公開鍵で検証しています...\n"; 71 $verifiedTamperedMessage = sodium_crypto_sign_open($tamperedSignedMessage, $publicKey); 72 73 if ($verifiedTamperedMessage !== false) { 74 echo "❌ 署名検証成功!? (これは起こるべきではありません - セキュリティ上の問題です)\n\n"; 75 } else { 76 echo "✅ 署名検証失敗(期待通り):メッセージが改ざんされているため、正当性を確認できませんでした。\n\n"; 77 } 78 79 // 5. 異なる公開鍵で検証した場合の失敗の例 80 echo "--- 異なる公開鍵での検証 --- \n"; 81 echo "➡️ 新しい、別の鍵ペアを生成します...\n"; 82 $anotherKeyPair = sodium_crypto_sign_keypair(); 83 $anotherPublicKey = sodium_crypto_sign_publickey($anotherKeyPair); 84 echo "✅ 別の公開鍵を生成しました。\n"; 85 // echo "別の公開鍵 (Hex): " . bin2hex($anotherPublicKey) . "\n\n"; 86 87 echo "➡️ 元の署名済みメッセージを別の公開鍵で検証しています...\n"; 88 $verifiedWithWrongKey = sodium_crypto_sign_open($signedMessage, $anotherPublicKey); 89 90 if ($verifiedWithWrongKey !== false) { 91 echo "❌ 署名検証成功!? (これは起こるべきではありません - セキュリティ上の問題です)\n\n"; 92 } else { 93 echo "✅ 署名検証失敗(期待通り):署名に使用された鍵とは異なる鍵で検証しようとしたため、正当性を確認できませんでした。\n\n"; 94 } 95 96 echo "--- デモンストレーション終了 ---\n"; 97} 98 99// 関数の実行 100// PHPのSodium拡張が有効になっていることを確認してください。 101// php.iniで extension=sodium を有効にするか、 102// `php -m | grep sodium` コマンドで確認できます。 103if (extension_loaded('sodium')) { 104 demonstrateSodiumSignatureVerification(); 105} else { 106 echo "エラー: Sodium拡張が有効になっていません。\n"; 107 echo "php.iniファイルで 'extension=sodium' を有効にしてください。\n"; 108}
このサンプルコードは、PHPのSodium拡張を利用したデジタル署名の生成と検証について、システムエンジニアを目指す初心者にも理解できるように解説しています。特にsodium_crypto_sign_open関数は、デジタル署名されたメッセージの正当性を検証し、元のメッセージを安全に復元する役割を担います。
最初にsodium_crypto_sign_keypair()で署名に必要な鍵ペア(公開鍵と秘密鍵)を生成し、sodium_crypto_sign()を使って秘密鍵でオリジナルメッセージに署名します。
sodium_crypto_sign_open関数は、署名済みメッセージ(引数$signed_message)と、それに対応する公開鍵(引数$public_key)を受け取ります。署名が有効でメッセージが改ざんされていないと判断された場合、関数は元のメッセージを文字列として返します。一方、メッセージが改ざんされている場合や、署名に使用された鍵とは異なる公開鍵で検証しようとした場合は、falseを戻り値として返し、メッセージの正当性が確認できなかったことを示します。
サンプルコードでは、署名成功例に加えて、意図的にメッセージを改ざんした場合や、別の公開鍵で検証した場合にfalseが返される失敗例も示しています。これにより、デジタル署名がデータの完全性(改ざんされていないこと)と、認証(誰が署名したか)をどのように保証するかを具体的に確認できます。
PHPのsodium_crypto_sign_open関数は、署名されたメッセージと公開鍵を用いてメッセージの正当性を検証し、元のメッセージを復元する際に使用します。この関数は検証に成功すると元のメッセージを、失敗した場合はfalseを返しますので、戻り値は必ず!== falseで厳密にチェックすることが重要です。署名と検証には、必ず対応する秘密鍵と公開鍵のペアを使用してください。異なる公開鍵では検証が失敗します。特に秘密鍵は、メッセージの署名に用いられるため、厳重に管理し、決して外部に公開しないように細心の注意を払う必要があります。また、この機能を利用するには、PHPのSodium拡張が有効になっている必要がありますので、実行環境の確認も忘れないでください。