ある文字列を Java でハッシュ化しようとしてこんな処理を書きました。
今回の件には関係ないですが、アルゴリズムは「SHA-256」です。
String message = "メッセージ"; MessageDigest md; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } md.update(message.getBytes(Charset.forName("UTF-8"))); StringBuilder sb = new StringBuilder(); for (byte b : md.digest()) { sb.append(Integer.toHexString(b & 0xff)); } System.out.println(sb);
すると結果は・・・
「94d14c42c7f3639f698c5ecd65599432f84545bee72d82edda144b8c14a78c」
でした。
でもよく見るとSHA-256でハッシュ化しているのに62文字しかない・・・。
(本来は64文字あるはず)
そこで、オンラインのハッシュ計算サイトで同じ計算をしてみました。
結果は、
「94d14c42c7f3639f698c5ecd655994032f84545bee72d82edda1044b8c14a78c」
なるほど、「0」が出力されていなかったんですね。
理由を探ってみます。
for 文の中で出てくる「b & 0xff」には「0 ~ 255」の整数が入ります。
これを「Integer#toHexString」を用いて16進数の文字列に変換する処理です。
この「16進数の文字列に変換する処理」に問題がありました。
ここで、整数で「0 ~ 255」というのは16進数では「0 ~ ff」となります。
「00 ~ ff」ではありません。
もうお分かりでしょうか。
整数で「0 ~ 15」の時は、本来「00 ~ 0f」として変換してほしかった文字列が、
「0 ~ f」として変換されてしまっていたんですね。
「0 埋めとしての 0」が欠けた結果、「0」の個数分短くなってしまったというわけです。
0 埋めをしたい場合は「String#format」を利用するのが便利かと思います。
先ほどのコードを書き直しましょう。
String message = "メッセージ"; MessageDigest md; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } md.update(message.getBytes(Charset.forName("UTF-8"))); StringBuilder sb = new StringBuilder(); for (byte b : md.digest()) { sb.append(String.format("%02x", b & 0xff)); // String#format に修正 } System.out.println(sb);
これでめでたく64文字のハッシュ値が出力されるようになりました。
コメント