Node.js/PHPでの様々な文字列ハッシュの生成

認証まわりで確実に必要になるハッシュの生成方法を調べてみました。
確認のためPHPを使っています。
調べたのは以下。

Node.jsで使いそうな文字列操作ライブラリ - ZeBeVogue別館も参考まで。

md5

安全面において使うべきではないですが、既存のシステムでも使われてるかも知れませんので。
cryptoを使います。

var crypto = require('crypto')
  , md5sum = crypto.createHash('md5')
  , arg = process.argv[2];

console.log(arg);
md5sum.update(arg);
console.log(md5sum.digest('hex'));

検証してみます。

$ node md5.js hoge
hoge
ea703e7aa1efda0064eaa507d9e8ab7e
$ php -r 'echo md5("hoge"), "\n";'
ea703e7aa1efda0064eaa507d9e8ab7e

同じですね。

sha1

sha1+saltももはや危険だと言われています。新規のものには使わない方が良いでしょう。
こちらもcryptoを使います。

var crypto = require('crypto')
  , sha1sum = crypto.createHash('sha1')
  , arg = process.argv[2];

console.log(arg);
sha1sum.update(arg);
console.log(sha1sum.digest('hex'));

検証します。

$ node sha1.js hoge
hoge
31f30ddbcb1bf8446576f0e64aa4c88a9f055e3c
$ php -r 'echo sha1("hoge"), "\n";'
31f30ddbcb1bf8446576f0e64aa4c88a9f055e3c

sha256

ここまでで気が付かれていると思いますが、

crypto.createHash('sha1')

アルゴリズムをsha256に指定すれば良いだけです。
http://nodejs.jp/nodejs.org_ja/api/crypto.html#crypto_crypto_createhash_algorithm」も参照ください。

$ node sha256.js hoge
hoge
ecb666d778725ec97307044d642bf4d160aabb76f56c0069c71ea25b1e926825
$ php -r 'echo hash("sha256", "hoge"), "\n";'
ecb666d778725ec97307044d642bf4d160aabb76f56c0069c71ea25b1e926825

参考)
PHP: hash - Manual

Bcrypt

これを使うべきとの事。
PHP: The Right Way
bcrypt - npm」を使います。

$ npm install bcrypt
var bcrypt = require('bcrypt')
  , arg = process.argv[2];

var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync(arg, salt);

console.log('salt -> ' + salt);
console.log('hash -> ' + hash);

var result = bcrypt.compareSync(arg, hash);
console.log(result);
$ node bcrypt_test.js hoge
salt -> $2a$10$fsZsWE2oYvwm5Zd.Q2ogB.
hash -> $2a$10$fsZsWE2oYvwm5Zd.Q2ogB.qZ93CC1/L.GR/d5ZCWS3baf0j6n9/Ra
true

検証します。

<?php
if (CRYPT_BLOWFISH == 1) {
	echo crypt('hoge', '$2a$10$fsZsWE2oYvwm5Zd.Q2ogB.') . "\n";
}
$ php bcrypt.php 
$2a$10$fsZsWE2oYvwm5Zd.Q2ogB.qZ93CC1/L.GR/d5ZCWS3baf0j6n9/Ra

参考)
PHP: crypt - Manual

salt の形式は、 "$2a$" か "$2x$" あるいは "$2y$"、2 桁のコストパラメータ、"$"、そして文字 "./0-9A-Za-z" からなる 22 桁となります。
(中略)
PHP 5.3.7 以降しか使わないのなら "$2a$" ではなく "$2y$" を使うべきだということです。

PHPでの生成と検証は以下で行けそう。

<?php
$iteration = 10;
$salt = '$2a$' . $iteration . '$' . substr(uniqid("", true), 0, 21);

if (CRYPT_BLOWFISH == 1) {
	$hash = crypt('hoge', $salt);
	echo 'hash  = ', $hash, "\n";

	$salt2 = substr($hash, 0, 28);
	$hash2 = crypt('hoge', $salt2);
	echo 'hash2 = ', ($hash2), "\n";

	var_dump($hash === $hash2);
}

PBKDF2

これについては、良く分かりませんでした。サンプルコードと参考URLだけ記載しておきます。ごめんなさい。

var crypto = require('crypto');

var iterations = 10;
var keylen = 32;
crypto.pbkdf2('password', 'salt', iterations, keylen, function(err, derivedKey) {
	console.log(err);
	console.log(new Buffer(derivedKey, 'binary').toString('hex'));
});
$ node pbkdf2.js 
undefined
ae3fe5f5707e07f3e7c117fb885cd052a6fcd77a4a7bcc3d30539407bd172fa4

PHPでは一応hash_pbkdf2という関数のマニュアルがありますが、手元の5.3.10では存在していません。CRYPT_BLOWFISHでのcrypt()(上記のBcryptですかね)を推奨しているようです。
実装例