PHP
password_hash
password_veryfy

PHPのPassword_hash関数をcrypt関数で再現する(メモ)


PHPのpassword_hashを詳しくみる

PHPのpassword_hash関数の暗号化アルゴリズムがblowfishというのはPHPerなら誰でも知っていると思います。

その詳細を調べたらパスワードごとにsaltを個別に持つことが可能でかつ、DB内に個別にsalt用カラムを保つ必要がないということをマニュアルを読んで知ったのメモ。


$hoge = "password";
$hash = password_hash($hoge, PASSWORD_BCRYPT);
// 暗号化されたパスワード:$2y$10$FCcP.mohAJhrvV0LeAgExutz.wPmInQ9R3Pme89QBVnJmujpZ4Ygi

if (password_verify($hoge, $hash)) {
echo("認証");
}

本来であれば、何も迷わずpassword_hashを使えばいいのでしょうけど、

crypt関数でも代用可能だと知ってちょっとためしてみました。


$hoge = "password";
$algo = '$2a$04$dummysalt/upto22characters';
$hash = crypt($hoge, $algo);
// $2a$04$dummysalt/upto22charaOlqk5u.LapVt7D9UokdVw2kezh9.edIq

// blowfishのsalt形式は3つ目の$を含めた以降の文字列のサイズが22byteであることが
// 仕様であるため、23文字目以降はむしされる模様。
// つまり、暗号化された文字列を第二引数に渡すことで同じhash値を計算することができる
// という仕様のようです。
if(crypt($hoge, $hash) === $hash) {
echo ("認証");
}

blowfishで暗号化するためには規定のSALT形式があるのでその仕様をみると


blowfish salt形式のフォーマット

CRYPT_BLOWFISH - Blowfish ハッシュ。salt の形式は、 "$2a$" か "$2x$" あるいは

"$2y$"、2 桁のコストパラメータ、"$"、そして文字 "./0-9A-Za-z" からなる 22 文字と
なります。
この範囲外の文字を salt に使うと、crypt() は長さゼロの文字列を返します。
2 桁のコストパラメータは反復回数の 2 を底とする対数で、 これは Blowfish
ベースのハッシュアルゴリズムで使います。 この値は 04 から 31 までの範囲でなければならず、
それ以外の値の場合は crypt() は失敗します。
5.3.7 までのバージョンの PHP では、salt のプレフィックスとして "$2a$" だけしか使えませんでした。
PHP 5.3.7 で新たなプレフィックスが導入され、 Blowfish の実装にあった
セキュリティ上の弱点に対応しました。
セキュリティ修正の対応の詳細については » この文書 を参照ください。
簡単にまとめると、PHP 5.3.7 以降しか使わないのなら "$2a$" ではなく "$2y$" を
使うべきだということです。

この仕様に則ってsaltをいろいろと変更してみましたが、

\$(2a)\$(04)\$とある(04)のコストパラメータをマックスの31にするとまったく計算が

完了せず使い物になりませんでした。

よっぽどの強固な暗号が必要で無い限りということでしょうけど、こんなに戻り値が

帰ってこないのに、使う場面あるの?とも思いましたが。

やはり、最小の04でやるとすんなり計算がおわるので、特に考えずに04を使っていこうと

思いました。

さて、このcrypt関数で作成したハッシュ値もpassword_verify関数に渡してやることで

パスワードの成否を検証することができるようです。

$hoge = "password";

$algo = '$2a$04$dummysalt/upto22characters';
$hash = crypt($hoge, $algo);

if(password_verify($hoge, $hash)) {
echo ("true");
}