SHA256でパスワードをハッシュ化する(Java編)

データベースにパスワードを生のままで保存するのは危険すぎるのでハッシュ関数を使って文字列をハッシュ化する。ハッシュ関数には色々あるけど今回はSHA-256を使用。SHA256は、どんな文字数の文字列でも必ず、64文字のハッシュ化された文字列にしてくれる大変便利なものだ。ハッシュ化についてはWikipediaの解説を読むと面白いのでオススメ。

さて、ここまでは今開発しているアプリのログイン処理に既に用いた方法であるが、これとは別にサンプルデータとしてのパスワードが必要になった。CSVファイルにそのままコピペできる様にループ処理を用いてパスワードをハッシュ化してみる。

先ずは手始めに一件だけ変換↓

import javax.xml.bind.DatatypeConverter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class EncryptEg {
    public static void main(String[] args) throws NoSuchAlgorithmException {

        String pepper = "4Aq1wpmS"; // ペッパー文字列(鍵)
        String userPass = "2"; // パスワード
        String ret; // 暗号

        byte[] bytes;
        String password = userPass + pepper;

        System.out.println("ペッパー文字列 + パスワード -> " + password);

        bytes = MessageDigest.getInstance("SHA-256").digest(password.getBytes());
        ret = DatatypeConverter.printHexBinary(bytes);

        System.out.println("ハッシュ化したバイト配列 -> " + bytes);
        System.out.println("バイト配列を16進数表記の文字列に -> " + ret);
    }
}
ペッパー文字列 + パスワード -> 24Aq1wpmS
ハッシュ化したバイト配列 -> [B@5acf9800
バイト配列を16進数表記の文字列に -> 9E6D76AB168F9272491A2AA3C05FEA87884415BA593B8F3A5C3CA8F08AC0C325

ハッシュ化された文字列は不可逆なので復元することはできない。しかし、安全を考えてパスワードに鍵として文字列を連結させておく。ペッパー文字列とも呼ぶらしい(本番ではバレない様に)。それを元に次はMessageDigestクラスを利用してダイジェスト値を求める。MessageDigestを使った場合、戻り値が byte[]になることに注意。別途、16進数文字列にしてあげる為にDatatypeConverterクラスを使う。

16進数文字列に変換する手間が面倒であればApache Commons CodecDigestUtilsクラスを利用するという手もある。一応やってみた。

import org.apache.commons.codec.digest.DigestUtils;
import java.security.NoSuchAlgorithmException;

public class EncryptEg {
    public static void main(String[] args) throws NoSuchAlgorithmException {

        String pepper = "4Aq1wpmS"; // ペッパー文字列(鍵)
        String userPass = "2"; // パスワード
        String ret; // 暗号

        byte[] bytes;
        String password = userPass + pepper;

        System.out.println("ペッパー文字列 + パスワード -> " + password);

        String hexString = DigestUtils.sha256Hex(password);

        System.out.println("ハッシュ化したバイト配列 -> " + bytes);
        System.out.println("バイト配列を16進数表記の文字列に -> " + hexString);
    }
}

結果はもちろん変わらない。しかし、Apache Commons Codecをダウンロードするか、Apache Mavenを利用している場合は、pom.xmlに依存関係を記述(↓)しないといけないのでどっちを取るかは考えないといけない。

<dependencies>
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
    </dependency>
</dependencies>

ここまで来れば後はfor文で回してあげるだけなので簡単。

import javax.xml.bind.DatatypeConverter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class EncryptEg {
    public static void main(String[] args) throws NoSuchAlgorithmException {

        String pepper = "4Aq1wpmS";
        String ret;

        byte[] bytes;

        for (int i = 1; i <= 100; i++) {
            int userPass = i;
            String userPassStr = String.valueOf(userPass);

            String password = userPassStr + pepper;

            bytes = MessageDigest.getInstance("SHA-256").digest(password.getBytes());
            ret = DatatypeConverter.printHexBinary(bytes);

            if (String.valueOf(i).length() == 1) {
                System.out.println(i + "   => " + ret);
            } else if (String.valueOf(i).length() == 2) {
                System.out.println(i + "  => " + ret);
            } else {
                System.out.println(i + " => " + ret);
            }
        }
    }
}

SQLでデータベースを参照してみるとちゃんとパスワードが一致してたので終了(id = 1のパスワードがハッシュ化されてないのは最初にログインした時の名残)。

MySQL [tipswatch]> select id, password from members;
+----+------------------------------------------------------------------+
| id | password                                                         |
+----+------------------------------------------------------------------+
|  1 | 1                                                                |
|  2 | 9E6D76AB168F9272491A2AA3C05FEA87884415BA593B8F3A5C3CA8F08AC0C325 |
|  3 | 682CF1DBC2BE9754CC47FDCCB1B5DA51282DE5CAA12FCE613942E396E28E75F3 |
|  5 | 20DCA2B7D2B7820FC8671B036C63E9C70246655BA0DD48B511CCF07E75C619DD |
|  4 | C1C998EBA318A7CA6A8B05E1002DFDDE867CB41A58199DA80AE064F9702A685E |
|  6 | F37B53DCAC13A3CC4FBB15BB600BFF04C0CEED6F450AD72B051453A91ADD6016 |
|  7 | FC7C61541A688E8261B947B5C4E22BB7B91DAD3388B726D2190DEDFB9B3FB4C1 |
|  8 | 7DB84286C4B197C677DE247DE73F89E65D4B873CE12C34FA683E00A1C351DADB |
|  9 | C5DD9173A589EE432C1C9197B1553F3CE854F25186334378A483D2E86B3FCDC3 |
+----+------------------------------------------------------------------+

To comment

@TOC
閉じる