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
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
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ですかね)を推奨しているようです。
実装例