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

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

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

作成日: 更新日:

基本的な使い方

sodium_crypto_pwhash_scryptsalsa208sha256関数は、ユーザーのパスワードを安全にハッシュ化するために使用される関数です。この関数は、パスワードをそのままの形でデータベースに保存するのではなく、セキュリティを高めた「ハッシュ値」と呼ばれるデータに変換して保存するために利用されます。これにより、万が一データベースが攻撃され、パスワード情報が漏洩したとしても、攻撃者がハッシュ値から元のパスワードを特定することを非常に困難にします。

この関数は「Scrypt(スクリプト)」と呼ばれる強力なパスワードハッシュアルゴリズムの一種(Scrypt-Salsa208-SHA256)を採用しています。Scryptは、計算に多くの時間とメモリを必要とするように設計されており、パスワードの推測や、様々なパスワードを試して解読しようとする総当たり攻撃(ブルートフォース攻撃)に対する耐性が非常に高いことが特徴です。これは、攻撃者が効率的にパスワードを解読することを困難にすることで、システム全体のセキュリティを向上させます。

具体的には、入力された生パスワードと、パスワードごとに異なるランダムな値である「ソルト」、そして計算の難易度を調整するための「コストパラメータ」を使用して、一方向性のハッシュ値を生成します。このハッシュ値は、元のパスワードを復元することが極めて難しいデータです。

新しいユーザーが登録される際や、既存ユーザーのパスワードが変更される際に、この関数を使ってパスワードのハッシュ値を生成し、データベースに保存します。ユーザーがログインする際には、入力されたパスワードと保存されているソルト、コストパラメータを用いて再度ハッシュ値を計算し、データベースに保存されたハッシュ値と比較することで、パスワードの正当性を検証します。

この関数は、ウェブアプリケーションなどにおいてユーザー認証のセキュリティを確保するための重要な要素であり、安全なシステム構築に不可欠な機能の一つです。

構文(syntax)

1<?php
2
3$password = 'YourSecretPassword123!';
4$salt = random_bytes(SODIUM_CRYPTO_PWHASH_SCRYPT_SALTBYTES);
5$opslimit = SODIUM_CRYPTO_PWHASH_SCRYPT_OPSLIMIT_MODERATE;
6$memlimit = SODIUM_CRYPTO_PWHASH_SCRYPT_MEMLIMIT_MODERATE;
7
8$hashed_password = sodium_crypto_pwhash_scryptsalsa208sha256($password, $salt, $opslimit, $memlimit);
9
10?>

引数(parameters)

int $length, string $password, string $salt, int $opslimit, int $memlimit

  • int $length: 生成するハッシュのバイト単位の長さ。
  • string $password: ハッシュ化するパスワード。
  • string $salt: パスワードハッシュ化に使用されるランダムなバイト列。
  • int $opslimit: 計算の反復回数の上限。CPU負荷を制御します。
  • int $memlimit: 使用できるメモリの最大量(バイト単位)。

戻り値(return)

string

この関数は、指定されたパスワードとソルトから生成された、暗号化されたハッシュ値を文字列として返します。

サンプルコード

PHP Sodiumでパスワードを安全にハッシュ化・検証する

1<?php
2
3// Sodium拡張がロードされていることを確認します。
4// これがない場合、Sodiumの関数は利用できません。
5if (!extension_loaded('sodium')) {
6    die('Sodium拡張がロードされていません。PHP設定で有効にしてください。');
7}
8
9/**
10 * Sodiumライブラリのscrypt実装を使用してパスワードのハッシュ化と検証を処理するクラス。
11 *
12 * このクラスは、システム内で安全なパスワード管理のために
13 * `sodium_crypto_pwhash_scryptsalsa208sha256`関数を使用する方法を示します。
14 */
15class PasswordManager
16{
17    /**
18     * 指定されたパスワードをscrypt-salsa208-sha256アルゴリズムでハッシュ化します。
19     *
20     * @param string $password ハッシュ化するプレーンテキストパスワード。
21     * @return array ハッシュ化されたパスワード(16進数)、ソルト(16進数)、
22     *               およびハッシュ化に使用されたパラメータを含む連想配列。
23     */
24    public function hashPassword(string $password): array
25    {
26        // 安全なランダムなソルトを生成します。
27        // `SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES` は推奨されるソルト長です。
28        $salt = random_bytes(SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES);
29
30        // ハッシュ化アルゴリズムの運用およびメモリ制限を定義します。
31        // これらの定数は、セキュリティとパフォーマンスのバランスを提供します。
32        // `MODERATE` は一般的なアプリケーションの良いデフォルト値です。
33        $opslimit = SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_MODERATE;
34        $memlimit = SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_MODERATE;
35
36        // 出力されるハッシュの希望する長さを指定します。
37        // `SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_BYTES` は推奨される出力長です。
38        $hashLength = SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_BYTES;
39
40        // scrypt (Salsa208/SHA256) を使用してパスワードをハッシュ化します。
41        // この関数はバイナリ形式の生ハッシュを返します。
42        $hashedPassword = sodium_crypto_pwhash_scryptsalsa208sha256(
43            $hashLength,  // 生成されるハッシュの長さ
44            $password,    // ハッシュ化するパスワード
45            $salt,        // ランダムに生成されたソルト
46            $opslimit,    // 演算量の上限
47            $memlimit     // メモリ使用量の上限
48        );
49
50        // 実際のアプリケーションでは、$hashedPasswordと$salt、そしてopsLimit、memLimit、hashLengthを
51        // ユーザー情報とともにデータベースに保存します。
52        // 検証時に必要となるため、ソルトを保存することが重要です。
53        return [
54            'hash' => bin2hex($hashedPassword), // バイナリハッシュを16進数に変換して保存/表示
55            'salt' => bin2hex($salt),           // バイナリソルトを16進数に変換して保存/表示
56            'opslimit' => $opslimit,
57            'memlimit' => $memlimit,
58            'hash_length' => $hashLength,
59        ];
60    }
61
62    /**
63     * 候補パスワードを、保存されたハッシュおよびそのパラメータと比較して検証します。
64     *
65     * @param string $candidatePassword 検証するプレーンテキストパスワード。
66     * @param array $storedData 保存されたハッシュ(16進数)、ソルト(16進数)、
67     *                          およびハッシュ化時に使用されたパラメータを含む連想配列。
68     * @return bool パスワードが一致すればtrue、そうでなければfalse。
69     */
70    public function verifyPassword(string $candidatePassword, array $storedData): bool
71    {
72        // 保存されたパラメータを取得し、16進数からバイナリに戻します。
73        $storedHash = hex2bin($storedData['hash']);
74        $storedSalt = hex2bin($storedData['salt']);
75        $storedOpslimit = $storedData['opslimit'];
76        $storedMemlimit = $storedData['memlimit'];
77        $storedHashLength = $storedData['hash_length'];
78
79        // 候補パスワードを、元のパスワードをハッシュ化したときと
80        // *全く同じ*ソルトとパラメータを使用して再ハッシュします。
81        $reHashedPassword = sodium_crypto_pwhash_scryptsalsa208sha256(
82            $storedHashLength,
83            $candidatePassword,
84            $storedSalt,
85            $storedOpslimit,
86            $storedMemlimit
87        );
88
89        // 新しく生成されたハッシュと保存されたハッシュを、定数時間比較関数を使用して比較します。
90        // これは、タイミング攻撃を防ぐために不可欠です。
91        return hash_equals(bin2hex($reHashedPassword), bin2hex($storedHash));
92    }
93}
94
95// --- 使用例 ---
96
97$passwordManager = new PasswordManager();
98$userPassword = 'mySuperSecurePassword123!';
99
100echo "--- パスワードのハッシュ化 ---" . PHP_EOL;
101$hashedResult = $passwordManager->hashPassword($userPassword);
102
103echo "元のパスワード: " . $userPassword . PHP_EOL;
104echo "保存されたハッシュ (hex): " . $hashedResult['hash'] . PHP_EOL;
105echo "保存されたソルト (hex): " . $hashedResult['salt'] . PHP_EOL;
106echo "OpsLimit: " . $hashedResult['opslimit'] . PHP_EOL;
107echo "MemLimit: " . $hashedResult['memlimit'] . PHP_EOL;
108echo "ハッシュ長: " . $hashedResult['hash_length'] . PHP_EOL . PHP_EOL;
109
110echo "--- パスワードの検証 ---" . PHP_EOL;
111
112// 正しいパスワードで検証を試みる
113$isCorrect = $passwordManager->verifyPassword($userPassword, $hashedResult);
114echo "正しいパスワード '" . $userPassword . "' での検証: " . ($isCorrect ? "成功" : "失敗") . PHP_EOL;
115
116// 間違ったパスワードで検証を試みる
117$incorrectPassword = 'wrongPassword';
118$isIncorrect = $passwordManager->verifyPassword($incorrectPassword, $hashedResult);
119echo "間違ったパスワード '" . $incorrectPassword . "' での検証: " . ($isIncorrect ? "成功" : "失敗") . PHP_EOL;
120

PHPのSodium拡張は、安全な暗号化機能を提供するライブラリです。その主要な関数の一つであるsodium_crypto_pwhash_scryptsalsa208sha256は、Scryptと呼ばれる堅牢なアルゴリズムを使用し、パスワードを安全な形式でハッシュ化するために利用されます。これにより、データベースに平文のパスワードを保存するリスクを回避し、情報漏洩時でもパスワードが保護されます。

この関数は、ハッシュの長さを示す$length、ハッシュ化対象の$password、ランダムに生成された$salt、そして演算の計算量上限を定義する$opslimit、メモリ使用量の上限を設定する$memlimitの五つの引数を取ります。これらの制限値を高く設定することで、パスワードを破ろうとする攻撃(総当たり攻撃など)にかかる時間を大幅に増加させ、セキュリティを強化します。関数は、指定された長さのバイナリ形式でハッシュ化された文字列を戻り値として返します。

サンプルコードでは、hashPasswordメソッドでパスワードをハッシュ化し、生成されたハッシュ、ソルト、そして運用・メモリ制限を保存します。verifyPasswordメソッドでは、入力されたパスワードが保存されたハッシュと一致するかを検証します。この際、ハッシュ化時と同じソルトと制限値を使用して新しいハッシュを生成し、hash_equals関数で定数時間比較を行うことで、タイミング攻撃と呼ばれるセキュリティリスクからシステムを守ります。このようにして、安全なパスワード管理が実現されます。

PHPのSodium拡張は、パスワードの安全なハッシュ化など、高度な暗号機能を提供するライブラリです。この関数を利用するには、PHP設定でSodium拡張を有効にする必要があります。

パスワードをハッシュ化する際は、毎回異なるランダムなソルトを生成し、ハッシュ値、生成したソルト、およびopslimitmemlimitといった全てのパラメータをデータベースなどに保存してください。バイナリデータはbin2hexで16進数に変換してから保存し、検証時にhex2binで元に戻すのが一般的です。

パスワードの検証時には、ハッシュ化時と全く同じソルトとパラメータ(opslimitmemlimit、ハッシュ長)を使い、候補パスワードを再ハッシュ化します。生成されたハッシュと保存されたハッシュの比較には、タイミング攻撃を防ぐために必ずhash_equals関数を使用することが重要です。opslimitmemlimitはセキュリティ強度とサーバー負荷のバランスを取るもので、本番環境のスペックに合わせて調整が必要です。

PHP Sodium scryptでパスワードハッシュを生成する

1<?php
2
3// このスクリプトを実行するには、PHPにSodium拡張がインストールされ、有効になっている必要があります。
4// php.iniで 'extension=sodium' を有効にするか、PHPをコンパイルする際に組み込む必要があります。
5
6/**
7 * PHPのSodium拡張を用いて、scryptアルゴリズム (sodium_crypto_pwhash_scryptsalsa208sha256) を使って
8 * 安全なパスワードハッシュを生成するサンプルコードです。
9 * システムエンジニアを目指す初心者の方にも理解しやすいよう、コメントで詳細を説明しています。
10 */
11
12// ユーザーから入力されたパスワードの例
13$password = 'mySuperSecretPassword123!';
14
15// ソルトの生成:
16// 各パスワードハッシュに対してユニークでランダムなソルトを使用することは、ブルートフォース攻撃や
17// レインボーテーブル攻撃からパスワードハッシュを保護するために極めて重要です。
18// SODIUM_CRYPTO_PWHASH_SALTBYTES は、scryptアルゴリズムが必要とするソルトの推奨バイト数です。
19try {
20    $salt = random_bytes(SODIUM_CRYPTO_PWHASH_SALTBYTES);
21} catch (Exception $e) {
22    // random_bytes() が失敗した場合の処理
23    die("ソルトの生成に失敗しました: " . $e->getMessage());
24}
25
26// scryptアルゴリズムの計算量とメモリ使用量の上限設定:
27// これらの定数は、Sodium拡張によって提供される推奨値であり、
28// セキュリティとパフォーマンスの適切なバランスを提供します。
29// SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE:
30//   対話型アプリケーション(例: Webサイトのログイン)向けに推奨される計算量の上限です。
31//   パスワード認証のたびに過度な遅延が発生しないように調整されています。
32// SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE:
33//   対話型アプリケーション向けに推奨されるメモリ使用量の上限です。
34//   これもサーバーリソースの消費を適切に保つための設定です。
35$opslimit = SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE;
36$memlimit = SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE;
37
38// 生成するパスワードハッシュの長さ:
39// SODIUM_CRYPTO_PWHASH_BYTES (32バイト) は、キー導出や認証トークンなどの用途で
40// 一般的に十分な長さとされています。この長さで、十分なエントロピーを持つハッシュが生成されます。
41$hashLength = SODIUM_CRYPTO_PWHASH_BYTES;
42
43echo "元のパスワード: " . $password . PHP_EOL;
44
45// sodium_crypto_pwhash_scryptsalsa208sha256 関数を使用してパスワードをハッシュ化します。
46// この関数は、指定された引数に基づいてパスワードを安全にハッシュ化し、バイナリ文字列として返します。
47$hashedPassword = sodium_crypto_pwhash_scryptsalsa208sha256(
48    $hashLength,   // 生成するハッシュの長さ
49    $password,     // ハッシュ化するパスワード
50    $salt,         // 生成したユニークなソルト
51    $opslimit,     // 計算量の上限
52    $memlimit      // メモリ使用量の上限
53);
54
55// 生成されたソルトとハッシュ化されたパスワードはバイナリデータです。
56// ターミナルでの表示や、データベースに文字列として保存する際には、
57// Base64やHexなどの形式でエンコードすることが一般的です。
58echo "生成されたソルト (Base64エンコード): " . base64_encode($salt) . PHP_EOL;
59echo "ハッシュ化されたパスワード (Base64エンコード): " . base64_encode($hashedPassword) . PHP_EOL;
60
61// 実際のアプリケーションでは、この $hashedPassword と $salt をデータベースに保存します。
62// ユーザー認証時には、ユーザーが入力したパスワードと保存された $salt を使って
63// 同じパラメータで再度ハッシュを生成し、$hashedPassword と比較して一致するかどうかを確認します。
64// 検証には、sodium_crypto_pwhash_scryptsalsa208sha256_str_verify のような関連関数もありますが、
65// このサンプルでは主要な関数の使用に焦点を当てています。
66
67?>

PHP 8のsodium_crypto_pwhash_scryptsalsa208sha256関数は、scryptアルゴリズムを用いて安全なパスワードハッシュを生成するために利用されます。この関数は、ユーザーが入力したパスワードを直接保存するのではなく、セキュリティを高めた形式に変換する役割を担います。

サンプルコードでは、まずユーザーパスワードと、セキュリティ上不可欠な「ソルト」を生成しています。ソルトは各パスワードハッシュに固有のランダムな値で、random_bytes関数と推奨されるバイト数であるSODIUM_CRYPTO_PWHASH_SALTBYTESを使用して生成されます。これにより、ブルートフォース攻撃などに対する耐性が向上します。

次に、ハッシュ計算の複雑さを調整する「計算量の上限(opslimit)」と「メモリ使用量の上限(memlimit)」を設定します。これらには対話型アプリケーション向けの推奨値であるSODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVESODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVEが使用され、セキュリティとシステムの応答性のバランスが取られています。生成されるハッシュの長さはSODIUM_CRYPTO_PWHASH_BYTESで指定され、十分なエントロピーを持つハッシュが得られます。

sodium_crypto_pwhash_scryptsalsa208sha256関数は、これら$length$password$salt$opslimit$memlimitの引数を受け取り、安全にハッシュ化されたパスワードをバイナリのstringとして返します。この戻り値は、そのままではデータベースに保存しにくいバイナリデータのため、Base64エンコードして表示・保存することが一般的です。生成されたハッシュとソルトはデータベースに保存し、認証時には同様の手順で生成したハッシュと比較することでユーザーを検証します。

この関数を利用するには、PHPのSodium拡張を有効にする必要があります。セキュリティ上、各パスワードに対してrandom_bytesで生成したユニークなソルトを使用することが極めて重要です。opslimitmemlimitのパラメータは、アプリケーションの要件(例:対話型Webアプリケーション)に合わせて、SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVEのような推奨定数を選び、セキュリティとパフォーマンスのバランスを取ってください。生成されるハッシュとソルトはバイナリデータのため、データベースへの保存や画面表示の際にはBase64などの形式でエンコードが必要です。認証時には、保存したソルトとユーザー入力パスワードを使って再度ハッシュを生成し、一致するかを比較して検証します。

関連コンテンツ

関連IT用語

関連プログラミング言語