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

作成日: 更新日:

sodium_crypto_secretbox関数は、共通の秘密鍵を使用してメッセージを暗号化し、そのデータの改ざんを検出するための認証タグを付加する機能を実行する関数です。この関数は、第三者によるデータの盗聴を防ぐ「機密性」と、データが途中で不正に変更されていないことを保証する「完全性」の両方を提供します。

主に、機密性の高い情報を安全に保存したり、ネットワークを介して安全にやり取りしたりする際に利用されます。例えば、ユーザーのパスワードハッシュやクレジットカード情報など、厳重な保護が必要なデータをデータベースに保存する前や、API通信で機密データを送受信する際にこの関数が役立ちます。

この関数を使用するには、暗号化したい元の「メッセージ」、暗号化と復号化の両方に使用する「秘密鍵」、そして「Nonce(ノンス)」と呼ばれる、各暗号化操作ごとに必ず異なるランダムな値の3つの主要な情報が必要です。Nonceはセキュリティ上非常に重要であり、同じ秘密鍵で異なるメッセージを暗号化するたびに、新しいNonceを生成して使用しなければなりません。

関数が正常に実行されると、暗号化されたメッセージと認証タグを含むバイナリ文字列が返されます。これにより、メッセージが安全に保護され、かつ信頼できるデータであることを確認できます。もし処理中にエラーが発生した場合は、falseが返されます。この関数は、PHPに組み込まれたLibsodium拡張機能の一部として提供されており、現代の暗号化技術に基づいた堅牢なセキュリティ機能を利用できます。

基本的な使い方

構文(syntax)

1sodium_crypto_secretbox(string $message, string $nonce, string $key): string

引数(parameters)

string $message, string $nonce, string $key

  • string $message: 暗号化したい平文データを表す文字列
  • string $nonce: 各メッセージで一意であるべきランダムなバイト列(nonce)を指定する文字列
  • string $key: 共有秘密鍵を表す文字列

戻り値(return)

string

secretbox形式で暗号化されたバイナリデータが文字列として返されます。

サンプルコード

PHP Sodiumでメッセージを暗号化・復号する

1<?php
2
3/**
4 * PHPのSodium拡張機能を使用して、共通鍵暗号(Symmetric-key encryption)の
5 * sodium_crypto_secretbox および sodium_crypto_secretbox_open 関数をデモンストレーションします。
6 *
7 * この関数は、指定されたメッセージを秘密鍵とノンスで暗号化し、
8 * その後、同じ鍵とノンスを使って復号化する一連の処理を示します。
9 *
10 * PHP 8 以降とSodium拡張機能が有効になっている環境で動作します。
11 */
12function demonstrateSodiumSecretBox(): void
13{
14    // 1. 秘密鍵の生成
15    // この鍵はメッセージの暗号化と復号化の両方に必要であり、外部に漏洩しないように厳重に管理する必要があります。
16    // SODIUM_CRYPTO_SECRETBOX_KEYBYTES は、このアルゴリズムで推奨される鍵のバイト数(長さ)です。
17    $key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
18
19    // 2. ノンス (Nonce) の生成
20    // ノンス(Number Used Once)は、各暗号化操作で一度だけ使用されるべきランダムな値です。
21    // 同じ鍵と同じノンスの組み合わせで異なるメッセージを暗号化すると、セキュリティ上の重大な脆弱性が生じます。
22    // 暗号文と一緒に安全に保存し、復号化時に同じノンスを再利用します。
23    // SODIUM_CRYPTO_SECRETBOX_NONCEBYTES は、このアルゴリズムで推奨されるノンスのバイト数です。
24    $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
25
26    // 3. 暗号化する元の平文メッセージ
27    $originalMessage = "これはシステムエンジニアの学習者向けの秘密のメッセージです。";
28    echo "元のメッセージ: " . $originalMessage . "\n";
29
30    // 4. メッセージの暗号化
31    // sodium_crypto_secretbox 関数は、平文メッセージ、ノンス、秘密鍵を引数に取り、
32    // 暗号文を生成して返します。
33    $ciphertext = sodium_crypto_secretbox($originalMessage, $nonce, $key);
34    echo "メッセージを暗号化しました。\n";
35
36    // 5. 暗号文の復号化
37    // キーワードである sodium_crypto_secretbox_open 関数を使用して、暗号文を復号します。
38    // 復号化には、元の暗号文、暗号化時に使用したノンス、そして同じ秘密鍵が必須です。
39    // 復号に成功すると元の平文を返しますが、失敗した場合(例: 鍵やノンスが不正、または暗号文が改ざんされている)は
40    // boolean の `false` を返します。
41    $decryptedMessage = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
42
43    // 6. 復号結果の検証
44    if ($decryptedMessage === false) {
45        echo "エラー: メッセージの復号に失敗しました。鍵、ノンス、または暗号文が間違っている可能性があります。\n";
46    } else {
47        echo "復号されたメッセージ: " . $decryptedMessage . "\n";
48
49        // 復号されたメッセージが元のメッセージと完全に一致するかを確認します。
50        if ($decryptedMessage === $originalMessage) {
51            echo "結果: 暗号化と復号化が成功し、元のメッセージと一致しました。\n";
52        } else {
53            echo "結果: 復号はされたものの、元のメッセージと一致しませんでした。何らかの異常が発生した可能性があります。\n";
54        }
55    }
56}
57
58// 上記のデモンストレーション関数を実行します。
59demonstrateSodiumSecretBox();
60
61?>

PHP 8のSodium拡張機能に属するsodium_crypto_secretbox関数は、共通鍵暗号方式を用いてメッセージを安全に暗号化します。この関数は、引数として暗号化したい元のメッセージ($message)、各暗号化に一度だけ使用するノンス($nonce)、そして暗号化と復号化で共通に使う秘密鍵($key)を受け取ります。ノンスは、暗号化ごとに異なる値を生成することが重要です。この関数の戻り値は、暗号化されたメッセージを表す文字列です。

サンプルコードは、sodium_crypto_secretboxによるメッセージの暗号化と、その対となるsodium_crypto_secretbox_open関数での復号化の一連の流れを示しています。sodium_crypto_secretbox_openは、暗号文、暗号化時に使用したノンス、秘密鍵を用いて復号を試みます。復号が成功した場合、元の平文メッセージを文字列で返しますが、鍵やノンスが不正な場合、または暗号文が改ざんされている場合は、戻り値としてfalseを返します。そのため、復号後の戻り値の確認は必須であり、これにより機密性の高いデータを安全に扱えるようになります。

このサンプルコードを利用する上で最も重要な点は、秘密鍵を厳重に管理し、決して外部に漏洩させないことです。また、ノンス(Nonce)は、各暗号化操作で一度だけ使用されるべき値であり、同じ秘密鍵とノンスの組み合わせで複数の異なるメッセージを暗号化すると、重大なセキュリティ上の問題が発生します。ノンスは暗号文と一緒に安全に保存し、復号時に同じものを利用する必要があります。sodium_crypto_secretbox_open関数は、復号に失敗するとfalseを返しますので、必ず厳密な比較(=== false)で復号結果を確認し、適切にエラー処理を行ってください。この機能はPHP 8以降でSodium拡張機能が有効な環境でのみ動作しますのでご注意ください。

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