ハッシュ関数がよくわからない
cryptはdesがどうのこうのでダメだという話がよくあるが、cryptとmd5やsha1やhashの違いがよくわからない。
<?php $str = 'foobarbaz'; echo md5($str) . "\n"; echo hash('md5', $str) . "\n"; echo crypt($str) . "\n"; echo sha1($str) . "\n"; echo hash('sha1', $str) . "\n";
php hash.php 6df23dc03f9b54cc38a0fc1483df6e21 6df23dc03f9b54cc38a0fc1483df6e21 $1$2vFnj56C$KGzeZFN3T4qTKvH8Wl5hE/ 5f5513f8822fdbe5145af33b64d8d970dcf95c6e 5f5513f8822fdbe5145af33b64d8d970dcf95c6e
うーん。どれを使えばいいのやら。
cryptだけ何らかの暗号化方式を使って更に加工しているみたい。
0x00 パスワードを pw, 塩を salt, "$1$"を magic と定義します。
0x01 [pw, salt, pw]という文字列を作ります。これを S1 とします。
0x02 S1 を MD5で暗号化します。出力結果を M1 とします。
0x03 [pw, magic, salt]という文字列を作ります。これを S2 とします。
0x04 S2 に M1 を、ある条件(仮に条件を F1 とする) F1 に従って追加します。
0x05 S2 に さらにある条件 F2 を使って、文字列を追加します。
0x06 S2 を MD5で暗号化します。出力結果を M2 とします。
0x07 pw, M2, salt をある条件 F3 を使用して組み合わせて文字列にし暗号化します。これを M_0001 とします。
0x08 0x07 を M_0001 〜 M_1000 まで 1000回くり返します。M2 はそのつど M_xxxx に変わります。
0x09 M_1000 を M3 とします。
0x0a M3 を ある条件 F4 を使用して 22bytes の文字列に変換します。これが暗号文です。仮に Z と定義します。
0x0b 最終的に[magic, salt, "$", Z]という文字列を出力します。
条件 F1 〜 F4 はソースコード見た方が良いと思います。
http://ruffnex.oc.to/kenji/xrea/md5crypt.txt
なかなか複雑な処理を行っています。
うーん。さっぱり。
Crypt::SaltedHash が生成する値は、LDAP のパスワードを扱う方法を定義した RFC-3112 に準拠した形式になるというメリットがあります (ただし SHA-1, MD5 を使用した場合のみ)。
ある日突然、ユーザアカウントの管理を LDAP に移行したい! ということになっても、パスワードカラムの値をそのまま使えるのです。素晴らしいですね。
パスワード保存のお供に Crypt::SaltedHash - JPerl Advent Calendar 2009
これが主な違い?
あとsqueezeや http://php53.dotdeb.org のPHPならcryptでもsha256とかが使えるらしい。
crypt() で $5$ や $6$ から始まる salt を指定することで、SHA-256 や SHA-512 が使用できるようになりました。
<?php echo 'SHA-256' . crypt( 'test', '$5$rounds=5000$salt$' ) . "\n"; echo 'SHA-512' . crypt( 'test', '$6$rounds=5000$salt$' ) . "\n";結果は以下のようになります。
SHA-256: $5$rounds=5000$salt$lNwM/2EW94.5e484ZZwetUClB7.Z/Z3buPmQvXdPEj4 SHA-512: $6$rounds=5000$salt$xdLuw21n.5WciQUUpHTTPfR6QwS..Z1Q/4xGfiyYa51WSQktzSXYXSk2zBp.Is5r9WiXrGqRmHpEG0iG0HaSk.PHP 5.3.2 での修正点や機能追加について - t_komuraの日記
で、結局パスワードやセッションIDを生成するのは何がいいんだろうね。
cryptでSHA-512を使いつつsaltを自動生成とかできないのかな。
こういうのもあった。
<?php function mkPasswd_SSHA($clearPass, $salt=null) { if(!isset($salt)){ mt_srand((double)microtime()*1000000); $salt = substr(md5(mt_rand()), 4, 8); } if(function_exists('sha1')) { $hash = pack("H*", sha1($clearPass . $salt)); }else if(function_exists('mHash')){ $hash = mHash(MHASH_SHA1, $clearPass . $salt); }else{ die("Error: Can not use Function:(SHA or SSHA). Use PHP Ver. 4.3.0 over."); } return base64_encode($hash . $salt); }http://www.developlus.jp/topics/password.html
うーむ。
saltを自動生成する部分だけ自作してcryptを使うのがいいのかな。どうなんだろ。
PHPのcryptをsha256変換方式で使う場合の情報って全然ないなーと思ったら本家にあった。
PHP: crypt - Manual
- CRYPT_SHA256 - SHA-256 hash with a sixteen character salt prefixed with $5$. If the salt string starts with 'rounds=
$', the numeric value of N is used to indicate how many times the hashing loop should be executed, much like the cost parameter on Blowfish. The default number of rounds is 5000, there is a minimum of 1000 and a maximum of 999,999,999. Any selection of N outside this range will be truncated to the nearest limit. - CRYPT_SHA512 - SHA-512 hash with a sixteen character salt prefixed with $6$. If the salt string starts with 'rounds=
$', the numeric value of N is used to indicate how many times the hashing loop should be executed, much like the cost parameter on Blowfish. The default number of rounds is 5000, there is a minimum of 1000 and a maximum of 999,999,999. Any selection of N outside this range will be truncated to the nearest limit.
日本語訳されてなかっただけだった…。
実装ネタ元のリンクもあった。
http://people.redhat.com/drepper/SHA-crypt.txt
長い…。
しかしさすがPHPのマニュアルだ。説明がないと思ったけどちゃんと書いてた。
続きはまた後でやろう。