Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】sodium_crypto_secretstream_xchacha20poly1305_push()関数の使い方

sodium_crypto_secretstream_xchacha20poly1305_push関数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

sodium_crypto_secretstream_xchacha20poly1305_push関数は、XChaCha20-Poly1305アルゴリズムを用いた暗号化ストリームに、新しいメッセージの断片(チャンク)を追加して暗号化を実行する関数です。この関数は、事前にsodium_crypto_secretstream_xchacha20poly1305_init_push()関数で初期化されたストリームに対して使用します。第一引数で渡されるストリームの状態(state)は、この関数を呼び出すたびに内部で更新されるため、同じ状態を使い回す必要があります。第二引数に暗号化したい平文のメッセージチャンクを指定すると、関数はそれを暗号化し、認証タグを付与した暗号文を生成します。オプションの第三引数で追加の関連データを指定でき、これは暗号化されませんが、データの完全性を保証するための認証計算に含まれます。第四引数のタグは、そのチャンクが通常のメッセージか、あるいはストリームの最後のメッセージであるかを示すために重要です。ストリームの最後のチャンクを暗号化する際には、定数SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINALを指定する必要があります。関数は成功時に暗号化されたチャンクを文字列として返し、失敗した場合はfalseを返します。この関数を複数回呼び出すことで、大きなデータや連続したメッセージを、効率的かつ安全に暗号化して送信することが可能になります。

構文(syntax)

1sodium_crypto_secretstream_xchacha20poly1305_push(
2    string &$state,
3    string $message,
4    string $additional_data = "",
5    int $tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE
6): string

引数(parameters)

string &$state, string $message, string $additional_data = '', int $tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE

  • string &$state: 暗号化状態を保持する可変参照。初回呼び出し時は初期化された状態が必要です。
  • string $message: 暗号化するメッセージ本体の文字列。
  • string $additional_data = '': 認証に追加される追加データの文字列。オプション。
  • int $tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE: メッセージのタグ。メッセージの末尾を示すタグなどを指定可能。

戻り値(return)

string

この関数は、指定されたメッセージを暗号化し、認証タグを付与したバイナリ文字列を返します。

サンプルコード

PHP Sodium ストリーム暗号化・復号する

1<?php
2
3/**
4 * プログラミング言語PHPのSodium拡張機能を利用した
5 * シークレットストリーム暗号化・復号のサンプルコードです。
6 *
7 * sodium_crypto_secretstream_xchacha20poly1305_push 関数は、
8 * ストリーム内のメッセージチャンクを暗号化するために使用されます。
9 * ストリーム暗号は、大量のデータや連続する複数のメッセージを安全に送受信する際に特に有用です。
10 *
11 * キーワード: sodium_crypto_box
12 * sodium_crypto_boxは公開鍵暗号による認証付き暗号化に用いられますが、
13 * 本サンプルで利用するストリームの共有鍵は、実運用ではsodium_crypto_boxのような
14 * 公開鍵暗号プリミティブを使って安全に交換されることが一般的です。
15 */
16function demonstrateSecretStreamCommunication(): void
17{
18    // Sodium拡張機能がロードされているか確認します。
19    // PHPで暗号化機能を使用するには、この拡張機能が必要です。
20    if (!extension_loaded('sodium')) {
21        echo "エラー: Sodium拡張機能がロードされていません。PHP設定を確認してください。" . PHP_EOL;
22        return;
23    }
24
25    // --- 送信者側 (メッセージストリームの暗号化) ---
26
27    // 1. ストリーム用のマスターシークレットキーを生成します。
28    // このキーは、送信者と受信者の間で安全に共有されている必要があります。
29    // 実際のアプリケーションでは、`sodium_crypto_box`などの公開鍵暗号を使って
30    // この共通鍵を安全に交換することが一般的なアプローチです。
31    $key = sodium_crypto_secretstream_xchacha20poly1305_keygen();
32    echo "生成されたストリームキー (hex): " . bin2hex($key) . PHP_EOL . PHP_EOL;
33
34    // 2. プッシュ操作のためのシークレットストリームを初期化します。
35    // これにより、ストリームのユニークなヘッダが生成され、暗号化の内部状態が初期化されます。
36    // このヘッダは、暗号化されたメッセージと一緒に受信者に送信する必要があります。
37    [$state_push, $header] = sodium_crypto_secretstream_xchacha20poly1305_init_push($key);
38    echo "ストリームヘッダ (hex): " . bin2hex($header) . PHP_EOL . PHP_EOL;
39
40    // 暗号化するメッセージと、それに関連付ける追加データ(認証のみされ、暗号化されないデータ)の配列。
41    $messages_to_send = [
42        ['message' => "最初の安全なメッセージです。", 'additional_data' => 'セッションID: ABC123'],
43        ['message' => "次に重要な情報です。", 'additional_data' => 'ユーザー: Alice'],
44        ['message' => "3番目のメッセージです。", 'additional_data' => ''], // 追加データなし
45    ];
46
47    $encrypted_chunks = [];      // 暗号化されたメッセージチャンクを格納する配列
48    $additional_data_sent = [];  // 各チャンクで使用された追加データを格納する配列(復号時の検証用)
49
50    echo "--- メッセージの暗号化 ---" . PHP_EOL;
51    foreach ($messages_to_send as $index => $item) {
52        $message_content = $item['message'];
53        $additional_data = $item['additional_data'];
54        // 通常のメッセージチャンクにはSODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGEタグを使用します。
55        $tag = SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;
56
57        // 3. sodium_crypto_secretstream_xchacha20poly1305_push を使用してメッセージチャンクを暗号化します。
58        // $state_push は参照渡しされ、呼び出しごとに内部的に更新されます。
59        // additional_dataは暗号化されませんが、認証されます。復号時には全く同じデータを提供する必要があります。
60        $cipher_text = sodium_crypto_secretstream_xchacha20poly1305_push(
61            $state_push,
62            $message_content,
63            $additional_data,
64            $tag
65        );
66        $encrypted_chunks[] = $cipher_text;
67        $additional_data_sent[] = $additional_data; // 復号時の検証のために保存
68
69        echo "  元メッセージ " . ($index + 1) . ": '" . $message_content . "'" . PHP_EOL;
70        if ($additional_data) {
71            echo "  追加データ " . ($index + 1) . ": '" . $additional_data . "'" . PHP_EOL;
72        }
73        echo "  暗号化チャンク " . ($index + 1) . " (hex): " . bin2hex($cipher_text) . PHP_EOL;
74    }
75
76    // ストリームの最後のメッセージチャンクを特別なタグで暗号化します。
77    // TAG_FINALタグはストリームの終了を示すのに役立ち、受信者はこれを使ってストリームの完了を検出できます。
78    $final_message = "これで送信終了です。";
79    $final_additional_data = '';
80    $cipher_text_final = sodium_crypto_secretstream_xchacha20poly1305_push(
81        $state_push,
82        $final_message,
83        $final_additional_data,
84        SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL
85    );
86    $encrypted_chunks[] = $cipher_text_final;
87    $additional_data_sent[] = $final_additional_data; // 復号時の検証のために保存
88
89    echo "  元最終メッセージ: '" . $final_message . "'" . PHP_EOL;
90    echo "  暗号化最終チャンク (hex): " . bin2hex($cipher_text_final) . PHP_EOL . PHP_EOL;
91
92
93    // --- 受信者側 (メッセージストリームの復号) ---
94
95    echo "--- メッセージの復号 ---" . PHP_EOL;
96
97    // 4. プル操作(復号)のためのシークレットストリームを初期化します。
98    // 受信者は、共有されたキーと送信者から受け取ったヘッダを使用して、
99    // 内部の復号状態を初期化します。
100    $state_pull = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key);
101
102    foreach ($encrypted_chunks as $index => $cipher_text_chunk) {
103        // 暗号化時に使用された追加データを取得します。
104        $expected_additional_data = $additional_data_sent[$index];
105
106        try {
107            // 5. sodium_crypto_secretstream_xchacha20poly1305_pull を使用してメッセージチャンクを復号します。
108            // $state_pull は参照渡しされ、呼び出しごとに内部的に更新されます。
109            // 重要な点として、ここで提供される `additional_data` は、暗号化時に
110            // そのチャンクに対して提供されたものと *完全に一致* しなければなりません。
111            // 一致しない場合、復号は失敗し、例外がスローされます。
112            [$decrypted_message, $received_tag] = sodium_crypto_secretstream_xchacha20poly1305_pull(
113                $state_pull,
114                $cipher_text_chunk,
115                $expected_additional_data
116            );
117
118            echo "  復号されたメッセージ " . ($index + 1) . ": '" . $decrypted_message . "'" . PHP_EOL;
119            echo "  受信タグ " . ($index + 1) . ": " . $received_tag . PHP_EOL;
120
121            if ($received_tag === SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL) {
122                echo "  (タグはこれが最終メッセージチャンクであることを示しています)" . PHP_EOL;
123            }
124        } catch (SodiumException $e) {
125            echo "  チャンク " . ($index + 1) . " の復号エラー: " . $e->getMessage() . PHP_EOL;
126            echo "  これは、メッセージの改ざん、キーの不一致、または追加データの不一致を示唆している可能性があります。" . PHP_EOL;
127        }
128    }
129    echo PHP_EOL;
130
131    // --- 追加データ不一致による復号失敗のデモンストレーション ---
132    echo "--- 追加データ不一致による復号失敗のデモンストレーション ---" . PHP_EOL;
133
134    // このデモンストレーションのために、復号状態を再初期化します。
135    // 実際のアプリケーションでは、追加データの不一致で復号が失敗した場合、
136    // そのストリーム全体が無効と見なされることが多いです。
137    $state_pull_bad_ad = sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key);
138
139    // 2番目のチャンク(インデックス1)を不正な追加データで復号しようとします。
140    $malicious_index = 1; // 2番目のメッセージ
141    $malicious_cipher_text = $encrypted_chunks[$malicious_index];
142    $incorrect_additional_data = '改ざんされた追加データ'; // 意図的に一致しないデータ
143
144    echo "  メッセージ " . ($malicious_index + 1) . " を誤った追加データで復号しようとします..." . PHP_EOL;
145
146    try {
147        // デモンストレーションのため、まず最初のチャンクを正しいデータで復号し、状態を進めます。
148        sodium_crypto_secretstream_xchacha20poly1305_pull($state_pull_bad_ad, $encrypted_chunks[0], $additional_data_sent[0]);
149
150        // 次に、2番目のチャンクを意図的に誤った追加データで復号しようとします。
151        // これにより、SodiumExceptionがスローされるはずです。
152        [$decrypted_msg, $tag] = sodium_crypto_secretstream_xchacha20poly1305_pull(
153            $state_pull_bad_ad,
154            $malicious_cipher_text,
155            $incorrect_additional_data // ここで意図的な不一致を引き起こす
156        );
157        echo "  エラー: 不正な追加データで復号が予期せず成功しました。" . PHP_EOL;
158    } catch (SodiumException $e) {
159        echo "  期待通り、メッセージ " . ($malicious_index + 1) . " の復号は追加データ不一致のため失敗しました: " . $e->getMessage() . PHP_EOL;
160    }
161}
162
163// デモンストレーション関数を実行します。
164demonstrateSecretStreamCommunication();
165

sodium_crypto_secretstream_xchacha20poly1305_push関数は、PHPのSodium拡張機能を利用したシークレットストリーム暗号化において、ストリーム内のメッセージの一部(チャンク)を安全に暗号化するために使用されます。この関数は、大量のデータや連続する複数のメッセージを効率的かつセキュアに送受信する際に特に有用です。

この関数は、ストリームの内部状態を管理する$state変数を参照渡しで受け取り、メッセージを暗号化するたびにその状態を更新します。これにより、ストリーム全体の連続性が保たれます。$message引数には暗号化したい実際のデータを指定し、$additional_data引数には、暗号化はされませんが認証の対象となる付随情報を指定できます。この$additional_dataは、復号時にまったく同じ値を提供することで、メッセージと付随情報の改ざんがないことを保証する役割を持ちます。$tag引数では、メッセージが通常のチャンクであるか、ストリームの終了を示す最終チャンクであるかなどを指定し、復号側でその意味を判断するために利用されます。

関数が正常に実行されると、暗号化されたメッセージチャンクが文字列として返されます。なお、ストリーム暗号で利用する共通鍵は、sodium_crypto_boxのような公開鍵暗号プリミティブを使って安全に交換することが一般的なプラクティスです。

この関数を使用するにはPHPのSodium拡張機能が必須です。ストリームの共通鍵は、sodium_crypto_boxなどの公開鍵暗号で安全に交換してください。sodium_crypto_secretstream_xchacha20poly1305_push$state引数は参照渡しで、呼び出しごとにストリーム内部の状態が更新されます。特にadditional_dataは暗号化されませんが、認証の対象となるため、送信時と復号時で完全に一致させる必要があります。不一致の場合、SodiumExceptionが発生し、データ改ざんや追加データの不整合を検知します。tag引数はメッセージの種類を示すために使用され、最終メッセージにはTAG_FINALを設定すると良いでしょう。復号時の例外処理も忘れずに行ってください。

PHP Sodium Secret Stream 暗号化/復号化

1<?php
2
3/**
4 * PHP Sodium Secret Stream Encryption/Decryption Demonstration
5 *
6 * This example demonstrates how to use `sodium_crypto_secretstream_xchacha20poly1305_push`
7 * to encrypt a stream of messages using a secret key, and then decrypt them.
8 * This is useful for encrypting large files or continuous data streams,
9 * where `sodium_crypto_secretbox` is more suited for single, smaller messages.
10 *
11 * For system engineers, understanding stream encryption is crucial for
12 * handling data larger than what fits in memory or for continuous data flows
13 * where re-keying and authentication are managed automatically by the stream API.
14 */
15function demonstrateSecretStreamEncryption(): bool
16{
17    // Ensure the Sodium extension is loaded
18    if (!extension_loaded('sodium')) {
19        echo "Error: Sodium extension is not loaded. Please enable it in your PHP configuration.\n";
20        return false;
21    }
22
23    echo "--- PHP Sodium Secret Stream Encryption/Decryption Demonstration ---\n\n";
24
25    // 1. Generate a master key for the stream. This key should be kept secret.
26    $key = sodium_crypto_secretstream_xchacha20poly1305_keygen();
27    echo "Generated Stream Key (Hex): " . bin2hex($key) . "\n\n";
28
29    // 2. Initialize the stream for encryption.
30    // This generates the stream header and the initial internal state for encryption.
31    // The state is passed by reference and updated automatically.
32    $encryptionState = null;
33    $header = sodium_crypto_secretstream_xchacha20poly1305_init($encryptionState, $key);
34    echo "Generated Stream Header (Hex): " . bin2hex($header) . "\n\n";
35
36    // Messages to be encrypted as a stream of chunks.
37    $messages = [
38        "This is the first secret message chunk, which could be part of a larger file.",
39        "Here's the second piece of data. The stream API handles internal re-keying automatically.",
40        "And finally, this is the last chunk of our data stream.",
41    ];
42
43    // Optional additional authenticated data (AAD). This data is not encrypted
44    // but its integrity is verified along with the ciphertext.
45    $additionalData = "Metadata for this entire stream";
46
47    $encryptedChunks = [];
48
49    echo "--- Encrypting Stream Chunks ---\n";
50    foreach ($messages as $index => $message) {
51        // Assign a tag to each message chunk.
52        // SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE: Standard message
53        // SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL: Marks the final message in the stream.
54        $tag = ($index === count($messages) - 1) ?
55            SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL :
56            SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;
57
58        // 3. Encrypt (push) a message chunk into the stream.
59        // The `$encryptionState` is updated by reference after each push operation,
60        // maintaining the stream's cryptographic context.
61        $ciphertext = sodium_crypto_secretstream_xchacha20poly1305_push(
62            $encryptionState,
63            $message,
64            $additionalData,
65            $tag
66        );
67        $encryptedChunks[] = $ciphertext;
68
69        echo "Chunk " . ($index + 1) . " encrypted (Tag: " . $tag . "). Ciphertext size: " . strlen($ciphertext) . " bytes\n";
70    }
71    echo "\nAll chunks encrypted successfully.\n\n";
72
73    // --- Decryption Phase ---
74
75    echo "--- Decrypting Stream Chunks ---\n";
76
77    // Initialize the stream for decryption using the same key and the header obtained during encryption.
78    // The `$decryptionState` is passed by reference and will be updated with each pull.
79    $decryptionState = null;
80    try {
81        sodium_crypto_secretstream_xchacha20poly1305_pull_init($decryptionState, $key, $header);
82    } catch (SodiumException $e) {
83        echo "Error initializing decryption: " . $e->getMessage() . "\n";
84        return false;
85    }
86
87    $decryptedMessages = [];
88    foreach ($encryptedChunks as $index => $ciphertext) {
89        // 4. Decrypt (pull) a message chunk from the stream.
90        // This function returns an array: [decrypted_message, received_tag].
91        // The `$decryptionState` is updated by reference after each pull.
92        try {
93            [$decryptedMessage, $receivedTag] = sodium_crypto_secretstream_xchacha20poly1305_pull(
94                $decryptionState,
95                $ciphertext,
96                $additionalData
97            );
98            $decryptedMessages[] = $decryptedMessage;
99
100            echo "Chunk " . ($index + 1) . " decrypted. Received Tag: " . $receivedTag . "\n";
101            echo "Original message:\n" . $messages[$index] . "\n";
102            echo "Decrypted message:\n" . $decryptedMessage . "\n";
103
104            // Verify if the decrypted message matches the original
105            if ($decryptedMessage === $messages[$index]) {
106                echo "Message content verification: SUCCESS\n";
107            } else {
108                echo "Message content verification: FAILED\n";
109                return false;
110            }
111
112            // Verify the tag as well, especially the FINAL tag for the last chunk
113            $expectedTag = ($index === count($messages) - 1) ?
114                SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL :
115                SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE;
116
117            if ($receivedTag === $expectedTag) {
118                echo "Tag verification: SUCCESS\n\n";
119            } else {
120                echo "Tag verification: FAILED (Expected: " . $expectedTag . ", Got: " . $receivedTag . ")\n\n";
121                return false;
122            }
123
124        } catch (SodiumException $e) {
125            echo "Error decrypting chunk " . ($index + 1) . ": " . $e->getMessage() . "\n";
126            return false;
127        }
128    }
129
130    echo "--- All messages processed ---\n";
131    return true;
132}
133
134// Execute the demonstration function
135if (demonstrateSecretStreamEncryption()) {
136    echo "\nSecret stream encryption and decryption demonstration completed successfully.\n";
137} else {
138    echo "\nSecret stream encryption and decryption demonstration failed.\n";
139}
140
141?>

sodium_crypto_secretstream_xchacha20poly1305_push関数は、PHPで大規模なデータや連続するデータストリームを安全に暗号化するために使用されます。単一の小さなメッセージを暗号化するsodium_crypto_secretboxとは異なり、この関数はデータを小さな断片(チャンク)に分割して順次暗号化するストリーム暗号化の過程で利用されます。

第一引数の&$stateは、暗号化処理の現在の内部状態を管理する重要な要素で、関数が呼び出されるたびに参照渡しで自動的に更新されます。これにより、ストリーム全体の連続性とセキュリティが維持されます。第二引数の$messageには、暗号化したいメッセージの断片を指定します。第三引数の$additional_dataは、暗号化はされませんが、データの改ざんを検出するために使用される追加の認証データです。第四引数の$tagは、メッセージチャンクの種類を示す整数値で、例えばストリームの最後のメッセージであることを示すタグ(SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL)を設定することで、復号時にストリームの終端を識別できます。

この関数は暗号化されたメッセージの断片を文字列として返します。sodium_crypto_secretstream_xchacha20poly1305_init関数で初期化された状態を基に繰り返し呼び出すことで、一連のデータを安全にストリーム暗号化し、効率的に処理することが可能です。

sodium_crypto_secretstream_xchacha20poly1305_push関数は、大きなデータや連続したメッセージを安全に暗号化する際に利用します。単一のメッセージ暗号化にはsodium_crypto_secretboxを用いるため、用途に応じた使い分けが重要です。

この関数は$stateという内部状態を参照渡しで更新します。暗号化処理の開始から終了まで、この$stateを正しく維持し続けることが不可欠です。途中で$stateが失われたり、間違った状態が渡されたりすると、復号できなくなるため注意してください。暗号化のマスターキーは厳重に管理し、絶対に漏洩させてはいけません。また、復号時には暗号化時と同じストリームヘッダと追加データ(AAD)が必要となります。最後のメッセージには特別なタグを付与し、ストリームの終端を明示的に示すようにしてください。利用前にはSodium拡張が有効か確認し、エラー発生時のための適切な例外処理を実装しましょう。

関連コンテンツ

関連IT用語

関連プログラミング言語