パスワードハッシュにBlowfishをPHP crypt()で使用していますが、奇妙なことに気づきました。PHPドキュメント:
CRYPT_BLOWFISH-次のソルトを使用したBlowfishハッシュ:「$ 2a $」、「$ 2x $」または「$ 2y $」、2桁のコストパラメータ「$」、およびアルファベット「./0-9Aからの22桁」 -Za-z」。
最終ハッシュに含まれるソルトは、ソルトが長すぎるかのように1文字短い(最後のものが切り取られる)ことに気付きましたが、そうではありません。
スクリプト出力の例:
塩:長さ22の97504ebb48c4619f820f83
ブローフィッシュ:$ 2a $ 13 $ 97504ebb48c4619f820f8u4QTtlV5MoqHt9l7hmK4jEohUXrI.0PK
ハッシュマッチ。
ご覧のとおり、ランダムソルトは正確に22桁ですが、最終ハッシュには「3」がありません。 21文字だけをソルトにすると、ハッシュが破損し、機能しません。では、なぜ最後の文字を切り捨てるのでしょうか?
PHPマニュアル の例でも、ランダムなソルトに最後の$を追加します。理由のためにそこに$あるのか、それともBlowfish、SHA-256、SHA-512にランダムに追加して、みんなを混乱させたのですか?
そして最後に、これは私のコードです:
if (CRYPT_BLOWFISH == 1) {
$salt = md5(uniqid(Rand(), TRUE));
$salt = substr($salt, 0, 22);
echo "Salt: " . $salt . " with length " . strlen($salt) . "<br />";
$pass = "rasmuslerdorf";
$bsalt = "$2a$13$".$salt;
$blowfish=crypt($pass, $bsalt);
echo 'Blowfish: ' . $blowfish . "<br />";
if (crypt($pass, $blowfish) == $blowfish) {
echo "Hash match.<br />";
}
else echo "no<br />";
}
else {
exit("You need php 5.3 or newer");
}
実際には「3」がありますが、「u」と呼ばれています。
説明:bcryptには128ビットのソルトが必要です。指定するソルトは「変更されたbase64」である必要があります。つまり、文字、数字、「/」または「。」で構成されている必要があります。記号(true Base64 では「。」の代わりに「+」記号が使用され、順序が異なるため、これは「変更」されます)。これは64要素のアルファベットなので、各文字は6ビットの価値があり、22文字は132ビットをエンコードします。
Bcryptは132ビットの最初の128ビットのみを使用するため、最後の4ビットは完全に無視されます。最後の4ビットは、最後のソルト文字の最後の4ビットです。変更されたbase64では、「u」の値はバイナリで48、110000であり、「3」の値はバイナリで57、111001です。ご覧のとおり、2つの値は最後の(右端の)4ビットのみが異なり、無視されます。
何が起こるかというと、最初に使用するbcrypt実装は、ソルト(22文字)を128ビットバッファー(16バイト)に変換し、そこでドロップが発生します。次に、コードはそれをbackを変更されたbase64に変換しますが、今回は「欠落している4ビット」にゼロを使用するため、「3」が「u」に変わります。 「97504ebb48c4619f820f83」の代わりに「97504ebb48c4619f820f8u」をソルトとして使用すると、これらの2つのソルトは最後の4ビットのみが異なるため無視されるため、まったく同じbcrypt出力が得られます。