SHA-1 (続・SHA-256)

ハッシュに MD5 を使っているアプリケーションをデータベースのテーブル定義等を変更せずに SHA-1 に移行するために 4bit × 40文字でなく、5bit × 32文字のハッシュを返す関数をつくってみた。

function sha1_32($str) {
    $hex = sha1($str);
    $hash = '';
    $c = array_map('strval', array_merge(range(0, 9), range('a', 'v')));
    //$c = array_map('chr', array_merge(range(48, 57), range(97, 118)));
    for ($i = 0; $i < 40; $i += 5) {
        $dec = hexdec(substr($hex, $i, 5));
        $o1 = floor($dec / 32768);
        $o2 = floor(($dec % 32768) / 1024);
        $o3 = floor(($dec % 1024) / 32);
        $o4 = $dec % 32;
        $hash .= $c[$o1] . $c[$o2] . $c[$o3] . $c[$o4];
    }
    return $hash;
}

セッションの場合は php.ini で

session.hash_function = 1
session.hash_bits_per_character = 5

とすれば SHA-1 で 5bit × 32文字のセッション ID が発行される。というかこっちが元ネタ。
しかしながら MD5 よりマシとはいえ SHA-1 にも欠陥が見つかっている し、公開鍵暗号、ハッシュ関数の強度に疑問を投げかける研究報告 によると SHA-256 も怪しいらしい。素人目には単純にブロックサイズが大きい分だけ強力そうに思えるのだけど、そのブロックサイズが大きいというのが ちょっと困ったこと なようで。
リンク先を踏まえると既存のアルゴリズムでは 160bit 以下なら Tiger (Tiger-160), それより大きいものなら Whirlpool が有力なのかな? とりあえず PHP では Mhash 関数で両方とも利用できる。
というわけで即席で tiger160_32 関数も作ってみた。 sha1_32 のはじめの2行を以下のように変えるだけ。

function tiger160_32($str) {
    $hex = bin2hex(mhash(MHASH_TIGER160, $str));

FreeBSD Ports の distfile では最近 MD5 と SHA-256 を併記するようになったようで、複数の異なるアルゴリズムで計算したものでチェックするというのは有効な手段の一つと思う。