この関数の基本を理解する必要があります。 php.netのドキュメントには、blowfishアルゴリズムについて次のように記載されています。
次のようにソルトを使用したBlowfishハッシュ:「$ 2a $」、2桁のコストパラメータ「$」、およびアルファベット「./0-9A-Za-z」からの22のbase64桁。ソルトでこの範囲外の文字を使用すると、crypt()は長さゼロの文字列を返します。
したがって、これは、定義上、機能しないはずです。
echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');
しかし、それは吐き出します:
$2a$07$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e
Crypt()がソルト自体を22の長さにカットしたように見えるところ。誰かがこれを説明してもらえますか?
この関数のもう1つの側面は、crypt()を使用してパスワードを比較する場合です。 http://php.net/manual/en/function.crypt.php (例1を参照)。これは、すべてのパスワードの暗号化に同じソルトを使用する場合、最初に暗号化する必要があることを意味しますか?すなわち:
$salt = "usesomadasdsadsadsadae";
$salt_crypt = crypt($salt);
if (crypt($user_input, $salt) == $password) {
// FAIL WONT WORK
}
if (crypt($user_input, $salt_crypt) == $password) {
// I HAVE TO DO THIS?
}
御時間ありがとうございます
次のコード例はあなたの質問に答えるかもしれません。
Blowfishを使用してハッシュされたパスワードを生成するには、最初にソルトを生成する必要があります。ソルトは$ 2a $で始まり、その後に反復回数と22文字のBase64文字列が続きます。
$salt = '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringfors';
$digest = crypt('rasmuslerdorf', $salt);
$ digest全体をデータベースに保存します。saltとdigestの両方が含まれています。
パスワードを比較するときは、これを行うだけです。
if (crypt($user_input, $digest) == $digest)
ダイジェストを塩として再利用しています。 cryptは、アルゴリズム識別子からソルトの長さを認識しています。
パスワードごとに新しいソルト
$password = 'p@ssw0rd';
$salt = uniqid('', true);
$algo = '6'; // CRYPT_SHA512
$rounds = '5042';
$cryptSalt = '$'.$algo.'$rounds='.$rounds.'$'.$salt;
$hashedPassword = crypt($password, $cryptSalt);
// Store complete $hashedPassword in DB
echo "<hr>$password<hr>$algo<hr>$rounds<hr>$cryptSalt<hr>$hashedPassword";
認証
if (crypt($passwordFromPost, $hashedPasswordInDb) == $hashedPasswordInDb) {
// Authenticated
マニュアルからの引用
CRYPT_BLOWFISH-次のようにソルトを使用したBlowfishハッシュ: "$ 2a $"、2桁のコストパラメータ "$"、およびアルファベットからの22のbase64桁
注:22 base64桁
BCryptはソルトに128ビットを使用するため、22バイトのBase64が使用され、最後のバイトの2ビットのみが使用されます。
ハッシュは、ソルトとパスワードを使用して計算されます。暗号化されたパスワードを渡すと、アルゴリズムは強度、ソルト(それ以外はすべて無視)、および指定したパスワードを読み取り、ハッシュを計算して追加します。 PostgreSQLとpg_cryptoが手元にある場合は、SELECT gen_salt( 'bf'); $ saltの何が読み取られているかが表示されます。
これが私の 。NET実装 のtest-vector-gen.phpからのソルト生成のコードサンプルです。
$salt = sprintf('$2a$%02d$%s', [strength goes here],
strtr(str_replace(
'=', '', base64_encode(openssl_random_pseudo_bytes(16))
),
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
'./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'));
すべてのパスワードに同じソルトを使用する理由はありません。とにかくsaltは出力の一部なので、便利なことは何も得られません...ただし、PHPには、組み込みのgen_salt関数が必要です。
最初の質問:
したがって、これは、定義上、機能しないはずです。
echo crypt('rasmuslerdorf', '$2a$07$usesomadasdsadsadsadasdasdasdsadesillystringforsalt$');
Crypt()がソルト自体を22の長さにカットしたように見えるところ。誰かがこれを説明してもらえますか?
文字が多すぎても問題はありません...フレーズソルトでこの範囲外の文字を使用すると、crypt()は長さゼロの文字列を返しますの範囲外を参照しますbase 64範囲外22文字。ソルト文字列に不正な文字を入力してみてください。空の出力が表示されるはずです(または、22文字未満を入力すると、不正な空のバイトが生成されます)。
2番目の質問:
ソルト文字列は常に暗号化された文字列に(設計上)表示されるため、暗号化された保存済みパスワードをソルトとして渡します。これにより、保存済みパスワードとユーザー入力パスワードの両方の暗号化に同じソルトを使用できるようになります。
この質問は、ZZCoderの回答に対する私の回答に関連しています。基本的に私の質問は、crypt()の結果をデータベースに保存することに関するものです。私のデータベースが次のようになるように、出力全体をデータベースに保存することになっていますか?
--------------------------------------------------------------------------------
| ID | Username | Password |
--------------------------------------------------------------------------------
| 32 | testuser | $2a$07$usesomadasdsadsadsadaeMTUHlZEItvtV00u0.kb7qhDlC0Kou9e |
--------------------------------------------------------------------------------
もしそうなら、そもそもこの種の塩を使うという目的に逆らうのではないでしょうか?誰かがデータベースにアクセスした場合、暗号化に使用されたソルトをはっきりと見ることができますか?
ボーナス質問:すべてのパスワードに同じソルトを使用するのは安全ですか?