【PHP8.x】sodium_crypto_secretstream_xchacha20poly1305_pull()関数の使い方
sodium_crypto_secretstream_xchacha20poly1305_pull関数の使い方について、初心者にもわかりやすく解説します。
基本的な使い方
sodium_crypto_secretstream_xchacha20poly1305_pull関数は、XChaCha20-Poly1305アルゴリズムを用いたシークレットストリームから、暗号化されたデータの断片(チャンク)を一つずつ復号するために実行する関数です。この関数は、sodium_crypto_secretstream_xchacha20poly1305_push関数によって暗号化された一連のメッセージを解読する際に使用されます。利用するには、まずsodium_crypto_secretstream_xchacha20poly1305_init_pull関数を呼び出して、復号処理の状態を初期化しておく必要があります。この関数は、初期化された状態と、復号したい暗号文チャンクを引数として受け取ります。処理が成功すると、復号された平文のチャンクと、そのチャンクがストリーム内でどのような位置づけにあるかを示すタグ情報の二つを格納した配列を返します。このタグ情報により、そのチャンクがストリームの最後の部分であるかなどを判断できます。もし暗号文が改ざんされている、あるいは処理の順序が間違っているなどの理由で復号に失敗した場合は、falseを返します。この仕組みにより、データの完全性を検証しながら、サイズの大きなファイルやストリーミングデータを安全に逐次処理することが可能になります。
構文(syntax)
1sodium_crypto_secretstream_xchacha20poly1305_pull( 2 string &$state, 3 string $ciphertext, 4 string $additional_data = "" 5): array|false
引数(parameters)
string &$state, string $ciphertext, string $additional_data = ""
- string &$state: 復号化処理の状態を保持する可変文字列。この引数は参照渡しされ、関数内で更新されます。
- string $ciphertext: 復号化する暗号化されたデータ(バイナリ文字列)。
- string $additional_data = "": 認証に使用される追加データ(バイナリ文字列)。省略可能です。
戻り値(return)
array|false
この関数は、暗号化されたストリームからデータを安全に復号化し、その結果を配列として返します。復号化に失敗した場合は false を返します。
サンプルコード
PHP Sodium: ストリーム暗号化/復号化デモ
1<?php 2 3// PHP Sodium 拡張が有効か確認 4if (!extension_loaded('sodium')) { 5 die('エラー: Sodium 拡張がロードされていません。php.ini で有効にしてください。'); 6} 7 8/** 9 * PHP Sodiumライブラリの `sodium_crypto_secretstream_xchacha20poly1305_pull` 関数を使用して、 10 * ストリーム暗号化・復号化の一連のプロセスをデモンストレーションします。 11 * 12 * この関数は、共有鍵ストリーム暗号を安全に利用する方法を示し、 13 * メッセージの暗号化、復号、および改ざん検知の機能を紹介します。 14 * システムエンジニアを目指す初心者向けに、各ステップをコメントで詳しく説明します。 15 */ 16function demonstrateSecretStreamDecryption(): void 17{ 18 echo "--- Sodium SecretStream XChaCha20-Poly1305 暗号化/復号化のデモンストレーション ---\n\n"; 19 20 // 1. 秘密鍵の生成: 送信側と受信側で共有される必要があります。 21 // この鍵はセキュアに管理される必要があります。 22 $key = sodium_crypto_secretstream_xchacha20poly1305_keygen(); 23 echo "生成された秘密鍵 (Base64エンコード): " . base64_encode($key) . "\n\n"; 24 25 // 暗号化・復号化するメッセージ群 26 $originalMessages = [ 27 "これは最初の秘密のメッセージです。", 28 "そして、これは2番目の秘密のメッセージです。", 29 "最後のメッセージも安全に送られます。", 30 ]; 31 32 // 各メッセージに対応する追加データ (認証のみに使用され、暗号化はされないが改ざんを検知できる) 33 $additionalData = [ 34 "メタデータ-1", 35 "メタデータ-2", 36 "メタデータ-3", 37 ]; 38 39 echo "--- 送信側の処理 (暗号化) ---\n"; 40 41 // 送信側: ストリームプッシュ操作のための初期状態を生成します。 42 // この `$state_push` は参照渡しされ、`sodium_crypto_secretstream_xchacha20poly1305_push` の呼び出しごとに更新されます。 43 $state_push = sodium_crypto_secretstream_xchacha20poly1305_init_push($key); 44 45 // `sodium_crypto_secretstream_xchacha20poly1305_init_push` の戻り値はストリームのヘッダーです。 46 // このヘッダーは、受信側がストリームを初期化するために必要です。 47 $header = $state_push; 48 echo "ストリームヘッダー (Base64エンコード): " . base64_encode($header) . "\n\n"; 49 50 $ciphertexts = []; 51 52 // メッセージを順次暗号化し、ストリームにプッシュします。 53 foreach ($originalMessages as $index => $message) { 54 // 最後のメッセージにはストリーム終了タグ `SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL` を使用します。 55 // それ以外のメッセージには通常のメッセージタグ `SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE` を使用します。 56 $tag = ($index === count($originalMessages) - 1) 57 ? SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL 58 : SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE; 59 60 $ciphertext = sodium_crypto_secretstream_xchacha20poly1305_push( 61 $state_push, // 現在のストリーム状態 (参照渡しで更新される) 62 $message, // 暗号化するメッセージ本体 63 $additionalData[$index], // 認証用に追加するデータ 64 $tag // メッセージの種類を示すタグ 65 ); 66 $ciphertexts[] = $ciphertext; 67 echo "暗号化されたメッセージ " . ($index + 1) . " (Base64エンコード): " . base64_encode($ciphertext) . "\n"; 68 } 69 echo "\n"; 70 71 echo "--- 受信側の処理 (復号化) ---\n"; 72 73 // 受信側: ストリームプル操作のための初期状態を生成します。 74 // 送信側から受け取った秘密鍵とヘッダーを使用します。 75 // この `$state_pull` も参照渡しされ、`sodium_crypto_secretstream_xchacha20poly1305_pull` の呼び出しごとに更新されます。 76 $state_pull = sodium_crypto_secretstream_xchacha20poly1305_init_pull($key, $header); 77 78 // 暗号文を順次プル(復号化)します。 79 foreach ($ciphertexts as $index => $ciphertext) { 80 // `sodium_crypto_secretstream_xchacha20poly1305_pull` は、 81 // 復号に成功した場合に `[復号されたメッセージ, タグ]` の配列を、 82 // 復号に失敗した場合 (例: データが改ざんされた場合) に `false` を返します。 83 $decrypted_result = sodium_crypto_secretstream_xchacha20poly1305_pull( 84 $state_pull, // 現在のストリーム状態 (参照渡しで更新される) 85 $ciphertext, // 復号する暗号文 86 $additionalData[$index] // 送信時と同じ追加データ (認証に使用) 87 ); 88 89 if ($decrypted_result === false) { 90 echo "エラー: メッセージ " . ($index + 1) . " の復号に失敗しました。このストリームは改ざんされた可能性があります。\n"; 91 continue; 92 } 93 94 [$decryptedMessage, $tag] = $decrypted_result; 95 echo "復号されたメッセージ " . ($index + 1) . ": " . $decryptedMessage . "\n"; 96 echo "受信タグ: "; 97 switch ($tag) { 98 case SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE: 99 echo "MESSAGE (通常のメッセージ)\n"; 100 break; 101 case SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL: 102 echo "FINAL (ストリームの終了)\n"; 103 break; 104 default: 105 echo "不明なタグ ($tag)\n"; 106 break; 107 } 108 109 // 復号されたメッセージが元のメッセージと一致するか検証します。 110 if ($decryptedMessage === $originalMessages[$index]) { 111 echo "検証成功: 復号されたメッセージはオリジナルと一致します。\n"; 112 } else { 113 echo "検証失敗: 復号されたメッセージはオリジナルと一致しません!\n"; 114 } 115 echo "\n"; 116 } 117 118 echo "--- データの改ざんテスト (暗号文の変更) ---\n"; 119 echo "最初の暗号文を故意に改ざんし、復号を試みます...\n"; 120 121 // テスト用に新しいストリーム状態を初期化します。 122 // 改ざんテストは、以前の復号状態に影響を与えないように独立して行うべきです。 123 $state_pull_for_tamper_test = sodium_crypto_secretstream_xchacha20poly1305_init_pull($key, $header); 124 125 // 最初の暗号文をコピーし、最初の1バイトを反転させて改ざんします。 126 $tamperedCiphertext = $ciphertexts[0]; 127 if (strlen($tamperedCiphertext) > 0) { 128 $tamperedCiphertext[0] = chr(ord($tamperedCiphertext[0]) ^ 1); 129 } else { 130 echo "エラー: 暗号文が短すぎて改ざんテストができません。\n"; 131 return; 132 } 133 134 $decrypted_result_tampered = sodium_crypto_secretstream_xchacha20poly1305_pull( 135 $state_pull_for_tamper_test, 136 $tamperedCiphertext, 137 $additionalData[0] 138 ); 139 140 if ($decrypted_result_tampered === false) { 141 echo "成功: 改ざんされた暗号文の復号に失敗しました。(期待される動作)\n"; 142 } else { 143 echo "警告: 改ざんされた暗号文が復号されてしまいました。(セキュリティ問題の可能性!)\n"; 144 [$decryptedMessageTampered, $tagTampered] = $decrypted_result_tampered; 145 echo "復号されたメッセージ (改ざん後): " . $decryptedMessageTampered . "\n"; 146 } 147 echo "\n"; 148 149 echo "--- データの改ざんテスト (追加データの変更) ---\n"; 150 echo "最初の暗号文は正しいまま、追加データを変更して復号を試みます...\n"; 151 152 // テスト用に新しいストリーム状態を初期化します。 153 $state_pull_for_ad_tamper_test = sodium_crypto_secretstream_xchacha20poly1305_init_pull($key, $header); 154 155 // 正しい暗号文を使用し、不正な追加データを設定します。 156 $originalCiphertextForAdTamper = $ciphertexts[0]; 157 $tamperedAdditionalData = "不正なメタデータ"; 158 159 $decrypted_result_ad_tampered = sodium_crypto_secretstream_xchacha20poly1305_pull( 160 $state_pull_for_ad_tamper_test, 161 $originalCiphertextForAdTamper, 162 $tamperedAdditionalData 163 ); 164 165 if ($decrypted_result_ad_tampered === false) { 166 echo "成功: 改ざんされた追加データでの復号に失敗しました。(期待される動作)\n"; 167 } else { 168 echo "警告: 改ざんされた追加データにもかかわらず復号されてしまいました。(セキュリティ問題の可能性!)\n"; 169 [$decryptedMessageAdTampered, $tagAdTampered] = $decrypted_result_ad_tampered; 170 echo "復号されたメッセージ (AD改ざん後): " . $decryptedMessageAdTampered . "\n"; 171 } 172 echo "\n"; 173} 174 175// 関数を実行してデモンストレーションを開始します。 176demonstrateSecretStreamDecryption(); 177 178?>
sodium_crypto_secretstream_xchacha20poly1305_pull関数は、共有鍵ストリーム暗号化されたデータのストリームから、次々に暗号文を復号するために使用されます。このサンプルコードは、まず共通の秘密鍵を生成し、複数のメッセージをsodium_crypto_secretstream_xchacha20poly1305_push関数で順次暗号化する送信側のプロセスを示しています。暗号化されたメッセージはストリームヘッダーと合わせて受信側に渡されます。
受信側では、sodium_crypto_secretstream_xchacha20poly1305_init_pull関数で初期状態を作成した後、sodium_crypto_secretstream_xchacha20poly1305_pull関数を用いて暗号文を一つずつ復号していきます。この関数は、最初の引数&$stateで渡される復号処理の状態を内部で更新し、連続する暗号文を正しく処理できるようにします。第二引数$ciphertextには復号したい暗号文、第三引数$additional_dataには暗号化時に指定された追加データを指定します。この追加データは暗号化されませんが、データの認証、つまり改ざん検知のために不可欠です。
復号が成功した場合、この関数は復号されたメッセージと、それがストリームの終了を示すかなどの情報を持つタグの配列を返します。もし暗号文や追加データが改ざんされていた場合、復号に失敗してfalseを返します。これにより、データが不正に変更されていないかを確実に検知でき、安全な通信を保証します。サンプルコードでは、意図的に暗号文や追加データを改ざんし、pull関数が正しく改ざんを検知してfalseを返す動作も確認しています。この一連のデモンストレーションは、秘匿性と改ざん検知を両立した安全なデータストリーム処理の基礎を理解するのに役立ちます。
この関数は、ストリーム暗号化されたデータの復号を行います。利用には、秘密鍵とストリームヘッダーの安全な共有・管理が不可欠です。秘密鍵が漏洩するとセキュリティが維持できません。引数の$stateは参照渡しで、呼び出すたびに内部状態が更新されるため、連続したストリーム処理にはその都度最新の$stateを使用してください。additional_dataは暗号化されませんが、改ざん検知に必要です。送信時と受信時で完全に一致させてください。復号が失敗するとfalseが返りますので、データの改ざんを検知できるよう、必ずエラー処理を組み込んでください。PHPのSodium拡張が有効かどうかも確認しましょう。
PHP Sodium ストリーム復号処理
1<?php 2 3/** 4 * PHPのsodium_crypto_secretstream_xchacha20poly1305_pull関数の使用例を示します。 5 * 6 * この関数は、Libsodiumライブラリのストリーム暗号化メカニズムの一部です。 7 * 大容量のデータや、連続して送られてくるデータを小さな「チャンク」に分割し、 8 * 順次安全に暗号化・復号するのに適しています。 9 * 10 * 復号側(pull)のプロセスを理解するには、まず暗号化側(push)でデータが 11 * どのように準備されるかを理解する必要があります。 12 */ 13function demonstrateSodiumSecretStreamPull(): void 14{ 15 // 1. ストリーム暗号化と復号の両方で使用する秘密鍵を生成します。 16 // この鍵は、データを暗号化する側と復号する側で安全に共有される必要があります。 17 $key = sodium_crypto_secretstream_xchacha20poly1305_keygen(); 18 echo "生成された秘密鍵 (Hex): " . bin2hex($key) . PHP_EOL . PHP_EOL; 19 20 // --- エンコード(暗号化)プロセス --- 21 // ここでは、復号に必要なデータ(暗号文とヘッダー)を生成します。 22 23 // 2. エンコード用のストリーム状態を初期化します。 24 // `init_push`は、ストリームの開始を示す「ヘッダー」と、 25 // 以降の暗号化に使用する「プッシュ状態」を返します。 26 // ヘッダーは復号側(pull)に渡される必要があります。 27 [$pushState, $header] = sodium_crypto_secretstream_xchacha20poly1305_init_push($key); 28 echo "生成されたストリームヘッダー (Hex): " . bin2hex($header) . PHP_EOL . PHP_EOL; 29 30 // 暗号化したい元のメッセージを複数のチャンクに分割したと仮定します。 31 $originalMessages = [ 32 "これは秘密のメッセージの最初の部分です。", 33 "これは次の部分で、さらに重要な情報を含むかもしれません。", 34 "これが最後の部分であり、メッセージ全体を締めくくります。", 35 ]; 36 // 追加データ(Additional Data)は、暗号文と一緒に認証されるデータです。 37 // このデータ自体は暗号化されませんが、復号時に同じものが提供されないと 38 // 認証エラーとなり、復号に失敗します。 39 $additionalData = "ユーザーID: 12345, 送信元: アプリケーションX"; 40 41 $encryptedChunks = []; 42 echo "--- メッセージの暗号化 ---" . PHP_EOL; 43 foreach ($originalMessages as $index => $message) { 44 // 最後のチャンクには特別なタグ `TAG_FINAL` を付けます。 45 // これにより、復号側でストリームの終了を認識できます。 46 $tag = ($index === count($originalMessages) - 1) ? 47 SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL : 48 SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE; 49 50 // 3. メッセージチャンクをエンコード(暗号化)します。 51 // `$pushState` は参照渡しされるため、関数が呼び出されるたびに内部状態が更新され、 52 // 次のチャンクの暗号化に利用されます。 53 $chunk = sodium_crypto_secretstream_xchacha20poly1305_push( 54 $pushState, 55 $message, 56 $additionalData, 57 $tag 58 ); 59 $encryptedChunks[] = $chunk; 60 echo "暗号化済みチャンク " . ($index + 1) . " (元の長さ: " . strlen($message) . "バイト): " . bin2hex($chunk) . PHP_EOL; 61 } 62 echo PHP_EOL; 63 64 // --- デコード(復号)プロセス --- 65 // ここからが `sodium_crypto_secretstream_xchacha20poly1305_pull` の主な使用例です。 66 67 echo "--- メッセージの復号 ---" . PHP_EOL; 68 // 4. デコード用のストリーム状態を初期化します。 69 // エンコード時に生成されたヘッダーと秘密鍵を使用します。 70 // ヘッダーが破損しているか、鍵が間違っている場合、初期化に失敗します。 71 $pullState = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key); 72 if ($pullState === false) { 73 echo "エラー: デコード状態の初期化に失敗しました。ヘッダーまたは鍵が不正な可能性があります。" . PHP_EOL; 74 return; 75 } 76 77 $decodedMessages = []; 78 foreach ($encryptedChunks as $index => $chunk) { 79 // 5. 暗号化されたチャンクをデコード(復号)します。 80 // `$pullState` は参照渡しされるため、関数が呼び出されるたびに内部状態が更新され、 81 // 次のチャンクの復号に利用されます。 82 // `$additionalData` は、エンコード時と同じものが提供される必要があります。 83 // 一致しない場合、または暗号文が改ざんされている場合、認証エラーとなり`false`が返されます。 84 $decryptedData = sodium_crypto_secretstream_xchacha20poly1305_pull( 85 $pullState, 86 $chunk, 87 $additionalData 88 ); 89 90 if ($decryptedData === false) { 91 echo "エラー: チャンク " . ($index + 1) . " の復号に失敗しました。データが改ざんされたか、追加データが一致しません。" . PHP_EOL; 92 break; // エラーが発生した場合は処理を中断 93 } 94 95 // 復号されたデータは、メッセージ本体とタグ(エンコード時に指定したもの)の配列で返されます。 96 [$message, $tag] = $decryptedData; 97 $decodedMessages[] = $message; 98 echo "復号済みチャンク " . ($index + 1) . " (タグ: " . $tag . "): " . $message . PHP_EOL; 99 100 if ($tag === SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL) { 101 echo "最終チャンクが正常に復号されました。" . PHP_EOL; 102 } 103 } 104 echo PHP_EOL; 105 106 // --- 検証 --- 107 108 echo "--- 復号結果の検証 ---" . PHP_EOL; 109 // 6. 復号されたデータが元のデータと一致するかを検証します。 110 if ($originalMessages === $decodedMessages) { 111 echo "成功: すべてのメッセージが正しく復号されました。" . PHP_EOL; 112 } else { 113 echo "エラー: 復号されたメッセージが元のメッセージと一致しません。" . PHP_EOL; 114 echo "元のメッセージ: " . implode(" | ", $originalMessages) . PHP_EOL; 115 echo "復号されたメッセージ: " . implode(" | ", $decodedMessages) . PHP_EOL; 116 } 117} 118 119// 関数を実行してデモンストレーションを開始します。 120demonstrateSodiumSecretStreamPull();
sodium_crypto_secretstream_xchacha20poly1305_pull関数は、PHPのLibsodium拡張機能の一部で、ストリーム暗号化されたデータを順次復号するために使用されます。この関数は、特に大容量のデータや連続して送られてくるデータを小さな「チャンク」に分割し、安全に処理する際に役立ちます。
復号処理を開始するには、まずsodium_crypto_secretstream_xchacha20poly1305_init_pull関数を使って、暗号化時に生成されたストリームヘッダーと秘密鍵をもとに復号状態を初期化する必要があります。
sodium_crypto_secretstream_xchacha20poly1305_pull関数は、初期化された復号状態を格納する&$state、復号したい暗号化されたデータチャンクを格納する$ciphertext、そして暗号化時に使用された任意の追加データ(認証用)を格納する$additional_dataを引数として取ります。&$stateは参照渡しされるため、関数が呼び出されるたびに内部状態が更新され、次のチャンクの復号に利用されます。$additional_dataはデータ認証のために重要で、暗号化時と完全に一致しない場合やデータが改ざんされている場合は、復号に失敗します。
成功した場合、この関数は復号されたメッセージ本体と、暗号化時に付与されたタグ(例えば、ストリームの終了を示すSODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINALなど)を含む配列を返します。復号に失敗した場合はfalseを返します。これにより、一連の暗号文チャンクを安全かつ確実に元のデータに戻すことができます。
sodium_crypto_secretstream_xchacha20poly1305_pull関数は、大容量データのストリーム復号に利用します。復号を開始するには、暗号化時に生成されたヘッダーと共通鍵を用いて、まずsodium_crypto_secretstream_xchacha20poly1305_init_pullで状態を初期化します。$state引数は参照渡しのため、各チャンクの復号時に内部状態が自動で更新されます。特に重要なのは$additional_dataで、これは暗号化時と全く同じ値を指定する必要があります。異なる値やデータが改ざんされている場合、復号に失敗しfalseが返されますので、必ず戻り値をチェックし、適切なエラー処理を実装してください。最終チャンクには特別なタグが含まれ、ストリームの終了を判断できます。