Node.jsでハッシュ値を算出する
これは、私が業務でとあるAPIのリクエストを作成していた時のことです。
そのAPIは、ある文字列からハッシュ値を算出して、
そのハッシュ値が一致するかどうかで認証を行っていたんです。
だから以下のようなコードからハッシュ値を算出して、リクエストを投げて、
レスポンスを取得できていました。
const crypto = require('crypto');
const data = 'abcdefg';
// ハッシュ値を算出(md5)
const hash = crypto.createHash('md5').update(data).digest('hex');
console.log(hash); // 7ac66c0f148de9519b8bd264312c4d64
ビルトインモジュールのcrypto
を使うだけでハッシュ値を算出できるなんて、手軽でいいなあと思っていました。
何も問題は無かったんです。
ハッシュ値を算出する文字列に、マルチバイト文字が含まれるまでは...。
hash.update()
cryptoモジュールのhashクラスのupdateメソッドは、引数を2つ取ることができます。
update(data [, inputEncoding])
公式ドキュメントでは、
data
がstringであり、かつinputEncoding
が省略された場合は、
utf8
でのエンコードが適用される(原文を意訳)、とあります。
そのAPIでは文字コードをWindows-31J
に指定して、
ハッシュ値を算出する必要がある仕様でした。
しかし、ハッシュ値算出の際に文字コードを指定しないと、
デフォルトのUTF-8
で算出されるため、「ハッシュ値が一致しない」という事態が起きたのです。
では、update()
の第2引数をWindows-31J
にすればいいかと言えば、サポート対象外なのでそうではなく...。1
特定の文字コードでハッシュ値を算出する
// UTF-8でハッシュ値が算出されるコード
const crypto = require('crypto');
const data = 'あいうえお';
// ハッシュ値を算出(md5)
const hash = crypto.createHash('md5').update(data).digest('hex');
console.log(hash); // 86deb27a32903da70a7b2348fcf36bc3
このままだと、UTF-8としてハッシュ値を算出されてしまいます。
今回はWindows-31J
という文字コードの文字列としてハッシュ値を算出したいので、
iconv-lite
という文字コード変換パッケージを使います!
iconv-lite
のencode()
を用いることで、
第一引数に指定した文字列を、第二引数に指定した文字コードへの変換ができます。
const iconv = require('iconv-lite');
const data = iconv.encode('あいうえお', 'Windows-31j');
encode()の返り値はBufferになります。
先述のハッシュのupdate()
は引数にBufferもとれるので、
encode()
の返り値をそのまま渡すだけで、そこからハッシュ値を算出してくれます。
つまり、指定の文字コードでエンコードされたデータから、
ハッシュ値を算出することができる!
const crypto = require('crypto');
const iconv = require('iconv-lite');
// Windows-31Jでハッシュ値を算出する
const data = iconv.encode('あいうえお', 'Windows-31j');
const hash = crypto.createHash('md5').update(data).digest('hex');
console.log(hash); // ad7cf5ce5313f8b3fc59d626b9aad653
ヨシ!
パッケージを使うことで、簡単にできました。
ありがたや...。
まとめ
- ハッシュ値を算出するにはビルトインモジュールの
crypto
を使う - 特定の文字コードでハッシュ値を算出を行うには、
iconv-lite
のencode()
でBufferにしたデータを渡すことで可能
これまでハッシュ値算出の時に、文字コードを意識したことはなかったので、
新たなことを知る良い経験になりました