Node.jsで文字列からハッシュ値を計算する方法

他の言語とかと比べてひとクセあるNode.jsでのハッシュ値計算ですが、たまにしか変換しなくて忘れがちなのでメモです。

お急ぎの人用

import { createHash } from 'crypto';

const str = 'hoge';

createHash('md5').update(str).digest('hex'); // ea703e7aa1efda0064eaa507d9e8ab7e

createHash('sha1').update(str).digest('hex'); // 31f30ddbcb1bf8446576f0e64aa4c88a9f055e3c

createHash('sha256').update(str).digest('hex'); // ecb666d778725ec97307044d642bf4d160aabb76f56c0069c71ea25b1e926825

詳細

cryptoモジュールを読み込みます。

import { createHash } from 'crypto';

createHash()を呼ぶとHashオブジェクトが返ります。
第一引数はハッシュアルゴリズムを指定します。
対応しているハッシュアルゴリズムはOpenSSLに依存しているらしくマイナーなアルゴリズム使いたい場合はOpenSSLを確認しましょう。

const hash = createHash('md5');

ハッシュ値を計算したい値を渡してハッシュオブジェクト内のデータを更新します。
文字列以外にもBufferなども指定できます。

hash.update('hoge');

最後にハッシュ値を計算します。
引数を指定しないとBufferで返りますが、指定すると文字列で返ります。
ドキュメント見ても詳しく書かれてませんがBuffertoString()をencoding指定で呼んだ場合と同じ文字列が返るっぽいです。

// 16進数の文字列で受け取る場合
hash.digest('hex'); // ea703e7aa1efda0064eaa507d9e8ab7e

// Base64で受け取る場合
hash.digest('base64'); // 6nA+eqHv2gBk6qUH2eirfg==

// Bufferで受け取る場合
hash.digest(); // <Buffer ea 70 3e 7a a1 ef da 00 64 ea a5 07 d9 e8 ab 7e>

注意事項

ハッシュオブジェクトは使い捨て

digest()を一度呼んだあとupdate()digest()を呼ぶとエラーになります。
使いまわし不可なのでcreateHash()を毎回呼ぶ必要があります。
16進数形式とBase64形式の両方が必要な場合などは気をつけましょう。

// 一回Bufferで受け取ってから
const buf = hash.digest();

const hex = buf.toString('hex');
const base64 = buf.toString('base64');

updateは上書きではなく追記

大きめのデータを分割して読み込めるようになっており、updateって名前だけど上書きではなく追記なので注意が必要です。
あまり無いかと思いますが本来複数回呼ぶ必要の無いのにうっかり複数回呼ぶような実装には注意しましょう。

const str = 'huga'

// デフォルト値
hash.update('hoge');

// パラメータの指定あったらそっち使いたいみたいな処理
if (str) {
  // hugaに上書きしたつもりが内部的には追記されてhogehuga
  hash.update(str);
}

// hogehugaのハッシュ値が計算される
return hash.digest('hex');