【PHP8.x】sodium_crypto_kx_seed_keypair()関数の使い方
sodium_crypto_kx_seed_keypair関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
sodium_crypto_kx_seed_keypair関数は、鍵交換プロトコルで使用される公開鍵と秘密鍵のペアを、与えられたシード(種)から決定論的に生成する関数です。この関数は、PHPの暗号ライブラリであるSodium拡張の一部として提供されています。
通常、暗号化に利用する鍵ペアは、予測不可能な乱数を用いてランダムに生成されます。しかし、このsodium_crypto_kx_seed_keypair関数では、ユーザーが指定した固定の32バイトのシード値を用いることで、常に同じ鍵ペアを再現して生成することができます。これは、例えばテスト環境で同じ鍵ペアを繰り返し使用したい場合や、特定のプロトコル設計上、シードから鍵ペアを派生させる必要がある場合などに役立ちます。
引数として32バイトの文字列形式のシードを受け取ります。そして、戻り値として、秘密鍵と公開鍵が連結された64バイトの文字列を返します。この64バイトのうち、最初の32バイトが秘密鍵、続く32バイトが公開鍵となります。シードが外部に漏れると、同じシードから誰でも同じ鍵ペアを生成できてしまうため、シードの管理には十分な注意が必要です。セキュリティ要件の高い本番環境では、通常はランダムな鍵生成関数であるsodium_crypto_kx_keypairの利用が推奨されます。
構文(syntax)
1sodium_crypto_kx_seed_keypair(string $seed): string
引数(parameters)
string $seed
- string $seed: 鍵ペア生成に使用するシード値(バイト列)を指定する文字列
戻り値(return)
string
この関数は、暗号化通信の鍵ペア(公開鍵と秘密鍵)を生成します。生成された鍵ペアは、バイナリ形式の文字列として返されます。
サンプルコード
PHP Sodium 拡張:鍵ペア生成と暗号化/復号化
1<?php 2 3// PHPのSodium拡張がロードされているかを確認します。 4// この拡張は、暗号化機能を提供するために必要です。 5if (!extension_loaded('sodium')) { 6 die('PHPのSodium拡張がロードされていません。インストールと有効化を確認してください。'); 7} 8 9/** 10 * sodium_crypto_kx_seed_keypair を利用して鍵ペアを生成し、 11 * sodium_crypto_box によるメッセージの暗号化・復号化を実演します。 12 * 13 * この関数は、システムエンジニアを目指す初心者向けに、 14 * 鍵ペアの生成からメッセージの暗号化、復号化までの一連の流れを簡潔に示します。 15 * 16 * sodium_crypto_box は「認証付き暗号化」を提供します。これは、 17 * メッセージの内容が他人に読まれないこと(機密性)と、 18 * メッセージが送られてから改ざんされていないこと(完全性)の両方を保証します。 19 * 20 * @param string $initialSeed 鍵ペア生成のための初期シード。 21 * 実運用では、予測不可能な安全な乱数として生成されるべきです。 22 * @return void 23 */ 24function demonstrateSodiumCryptoBoxWithKxKeypair(string $initialSeed): void 25{ 26 echo "--- sodium_crypto_kx_seed_keypair と sodium_crypto_box のデモンストレーション ---\n\n"; 27 28 // 1. ユーザー(アリスとボブ)の鍵ペアを生成します。 29 // sodium_crypto_kx_seed_keypair は、指定されたシードからX25519形式の「秘密鍵」を生成します。 30 // 対応する「公開鍵」は、その秘密鍵から sodium_crypto_kx_publickey を使って導出します。 31 // デモンストレーションのため、アリスとボブで異なるシードを使用しています。 32 // 実運用では、各ユーザーはそれぞれ安全な乱数から独自の鍵ペアを生成します。 33 34 // アリスの鍵ペアを生成 35 $aliceSecretKey = sodium_crypto_kx_seed_keypair($initialSeed); 36 $alicePublicKey = sodium_crypto_kx_publickey($aliceSecretKey); 37 38 // ボブの鍵ペアを生成 (アリスとは異なるシードを使用) 39 $bobSecretKey = sodium_crypto_kx_seed_keypair($initialSeed . 'another_unique_string_for_bob_key'); 40 $bobPublicKey = sodium_crypto_kx_publickey($bobSecretKey); 41 42 echo "アリスの公開鍵 (一部): " . bin2hex(substr($alicePublicKey, 0, 8)) . "...\n"; 43 echo "ボブの公開鍵 (一部): " . bin2hex(substr($bobPublicKey, 0, 8)) . "...\n\n"; 44 45 // 2. 暗号化するメッセージとナンス(Nonce)を準備します。 46 $message = "これは非常に重要な機密メッセージです。システムエンジニアの皆さん、こんにちは!"; 47 // ナンスは「Number Used Once(一度だけ使われる数値)」を意味します。 48 // 各暗号化操作で必ず異なる、予測不可能な値である必要があります。 49 // 同じ鍵ペアで複数のメッセージを暗号化する場合でも、常に新しいナンスを生成してください。 50 // SODIUM_CRYPTO_BOX_NONCEBYTES は、sodium_crypto_box に必要なナンスの適切なバイト長を定義しています。 51 $nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES); 52 53 echo "元のメッセージ: " . $message . "\n"; 54 echo "使用したナンス (一部): " . bin2hex(substr($nonce, 0, 8)) . "...\n\n"; 55 56 // 3. アリスがボブ宛にメッセージを暗号化します。 57 // アリスは「自分の秘密鍵」と「ボブの公開鍵」を使ってメッセージを暗号化します。 58 // これにより、メッセージはボブだけが復号でき、かつアリスが送信元であることが保証されます。 59 try { 60 $encryptedMessage = sodium_crypto_box( 61 $message, 62 $nonce, 63 $bobPublicKey, // メッセージの受信者(ボブ)の公開鍵 64 $aliceSecretKey // メッセージの送信者(アリス)の秘密鍵 65 ); 66 echo "暗号化されたメッセージ (一部Hex): " . bin2hex(substr($encryptedMessage, 0, 8)) . "...\n\n"; 67 } catch (SodiumException $e) { 68 echo "エラー: メッセージの暗号化に失敗しました。詳細: " . $e->getMessage() . "\n"; 69 return; 70 } 71 72 // 4. ボブがアリスからのメッセージを復号化します。 73 // ボブは「自分の秘密鍵」と「アリスの公開鍵」を使ってメッセージを復号化します。 74 // 暗号化に使用されたのと同じナンスが、復号化にも必須です。 75 try { 76 $decryptedMessage = sodium_crypto_box_open( 77 $encryptedMessage, 78 $nonce, 79 $alicePublicKey, // メッセージの送信者(アリス)の公開鍵 80 $bobSecretKey // メッセージの受信者(ボブ)の秘密鍵 81 ); 82 83 echo "復号化されたメッセージ: " . $decryptedMessage . "\n\n"; 84 } catch (SodiumException $e) { 85 echo "エラー: メッセージの復号化に失敗しました。詳細: " . $e->getMessage() . "\n"; 86 echo "これは、不正なナンス、メッセージの改ざん、または誤った鍵ペアが原因である可能性があります。\n"; 87 return; 88 } 89 90 // 5. 復号化されたメッセージが元のメッセージと一致するか確認します。 91 if ($decryptedMessage === $message) { 92 echo "結果: メッセージは正しく暗号化され、復号化されました。\n"; 93 echo "通信の機密性(内容が漏れていない)と完全性(改ざんされていない)が保たれました。\n"; 94 } else { 95 echo "結果: メッセージの復号化に失敗したか、内容が改ざんされています。\n"; 96 } 97} 98 99// サンプルコードを実行します。 100// ここで生成するシードは、sodium_crypto_kx_seed_keypair が期待する適切なバイト長です。 101// random_bytes() はセキュリティのために強力な乱数を生成します。 102demonstrateSodiumCryptoBoxWithKxKeypair(random_bytes(SODIUM_CRYPTO_KX_SEEDBYTES)); 103 104?>
PHP 8のsodium_crypto_kx_seed_keypair関数は、Sodium拡張によって暗号通信用の秘密鍵を生成します。この関数は、string $seedという安全なバイト列を引数として受け取り、それに基づいた固定長の秘密鍵(string型)を生成して返します。このシードは鍵ペア生成の決定的な元となります。
サンプルコードでは、この関数を用いてユーザー(アリスとボブ)の秘密鍵を生成し、そこから対応する公開鍵を導出しています。これらの鍵ペアは、sodium_crypto_box関数と組み合わせてセキュアな通信を実現するために利用されます。sodium_crypto_boxは、送信者の秘密鍵と受信者の公開鍵、および一度きりのナンスを用いてメッセージを暗号化することで、メッセージが第三者に盗聴されず(機密性)、また改ざんもされていないこと(完全性)を保証する「認証付き暗号化」を提供します。このサンプルは、sodium_crypto_kx_seed_keypairによる鍵ペア生成から、sodium_crypto_boxを用いたメッセージの暗号化、そして復号化までの一連の流れを、システムエンジニアを目指す初心者にも分かりやすく実演しています。
このサンプルコードで鍵ペアを生成する際のシードは、実運用では予測不可能な安全な乱数として生成し、固定値や予測可能な値を使用しないでください。特に重要な注意点として、sodium_crypto_boxでメッセージを暗号化する際に使用するナンスは、各暗号化操作ごとに必ず異なる予測不可能な値である必要があります。同じナンスを複数回使用すると、重大なセキュリティ脆弱性につながるため、絶対に行わないでください。また、sodium_crypto_boxとsodium_crypto_box_open関数では、引数として渡す送信者と受信者の秘密鍵と公開鍵の組み合わせを正しく指定することが必須です。これらが誤っていると、暗号化や復号化はできません。復号化に失敗した場合は、メッセージが改ざんされた可能性も示しますので、適切なエラー処理を実装してください。
シードから鍵交換用鍵ペアを生成する
1<?php 2 3// Sodium 拡張がロードされていることを確認します。 4// この拡張は、暗号化処理を行うために必要です。 5if (!extension_loaded('sodium')) { 6 die('エラー: PHP Sodium 拡張がロードされていません。'); 7} 8 9/** 10 * 指定されたシード値から、決定論的にキー交換 (Key Exchange: KX) 用の鍵ペアを生成し、表示します。 11 * 12 * @return void 13 */ 14function generateKxKeypairFromSeedExample(): void 15{ 16 // sodium_crypto_kx_SEEDBYTES は、キー交換用のシードが持つべき正確なバイト数を示す定数です。 17 $seedBytes = SODIUM_CRYPTO_KX_SEEDBYTES; 18 19 // 鍵ペア生成に使用するシード値を準備します。 20 // シードは一意で予測不可能なデータであるべきですが、ここではデモンストレーションのため、 21 // 正しいバイト数のランダムなシードを生成します。 22 // 同じシードを常に使用すると、常に同じ鍵ペアが生成されます。 23 $seed = random_bytes($seedBytes); 24 25 echo "--- キー交換(KX)用の鍵ペア生成 ---" . PHP_EOL; 26 echo "使用するシード (16進数): " . bin2hex($seed) . PHP_EOL; 27 28 // sodium_crypto_kx_seed_keypair 関数は、与えられたシードから鍵ペアを生成します。 29 // 戻り値は、秘密鍵と公開鍵が結合された単一のバイナリ文字列です。 30 $keypair = sodium_crypto_kx_seed_keypair($seed); 31 32 echo "生成された鍵ペア (バイナリを16進数で表示): " . PHP_EOL; 33 // バイナリデータは直接表示すると文字化けすることがあるため、16進数に変換して表示します。 34 echo bin2hex($keypair) . PHP_EOL; 35 36 // 補足: キーワードにある sodium_crypto_sign_keypair 関数は、 37 // 署名 (Signature) 用の鍵ペアをランダムに生成する関数です。 38 // 本来の目的は異なりますが、どちらも暗号化における「鍵ペアの生成」という 39 // 重要な概念を扱います。この例では、特定のシードから鍵ペアを生成する方法を示しています。 40} 41 42// サンプル関数を実行して、鍵ペアの生成を確認します。 43generateKxKeypairFromSeedExample(); 44
このPHPコードは、PHPのSodium拡張にあるsodium_crypto_kx_seed_keypair関数を使用して、キー交換(Key Exchange: KX)用の鍵ペアを特定のシード値から生成する方法を示しています。
まず、コードはSodium拡張がシステムにロードされているかを確認します。これは暗号化機能を利用するために必須です。次に、SODIUM_CRYPTO_KX_SEEDBYTES定数を用いて、鍵ペア生成に必要なシードの正確なバイト数を取得します。サンプルでは、そのバイト数に合わせたランダムなシードを生成していますが、このシードが同じであれば、常に同じ鍵ペアが生成されます。
sodium_crypto_kx_seed_keypair関数は、引数として渡されたstring $seedから、秘密鍵と公開鍵が結合された単一のstring型バイナリ文字列として鍵ペアを返します。この戻り値は直接表示すると文字化けするため、bin2hex関数で16進数形式に変換して表示しています。
キーワードにあるsodium_crypto_sign_keypair関数は、署名(Signature)用の鍵ペアをランダムに生成するものであり、本コードで示されているキー交換とは目的が異なりますが、暗号化における「鍵ペアの生成」という共通の重要な概念を扱っています。
この関数は、指定されたシードから鍵交換用の鍵ペアを決定論的に生成します。初心者が注意すべき点は、まずPHP Sodium拡張が事前にロードされているかを確認することです。引数として渡すシードは、SODIUM_CRYPTO_KX_SEEDBYTESで定義される正確なバイト数である必要があります。同じシードからは常に同じ鍵ペアが生成されるため、本番環境では予測不可能な真にランダムなシードを使用することが、セキュリティ上極めて重要です。戻り値はバイナリ形式の鍵ペアですので、表示する際はbin2hexなどで16進数に変換して扱うと良いでしょう。また、この鍵ペアは鍵交換専用であり、署名用の鍵ペアとは用途が異なる点にもご留意ください。