KotlinとPHPでHMAC方式(sha256)のハッシュ値を生成する
これまで、Kotlin や PHP、Python などでハッシュ値を取得する方法を紹介してきました。
(符号化)
昨今はハッシュアルゴリズムとして sha256 が一般的で、md5 や sha1 は安全性が低下しつつあり、セキュリティ的なリスクが増えてきています。
今回、「共有の秘密鍵」を使ってハッシュ値を取得する HMAC 方式を利用する機会があったので、Kotlin と PHP での利用方法をまとめたいと思います。
前提条件
HMAC 方式では複数のアルゴリズム(md5, sha256 など)が利用できますが、今回は Kotlin も PHP も「sha256」を採用します。
ハッシュするメッセージにはマルチバイトの文字列も含めますが、文字コードは「UTF-8」としておきましょう。
よくあるケースとして、外部のサイトから送られてきたハッシュ値を、自分の環境で生成したハッシュ値と比較するというパターンですね。
外部サイトのシステムが古く、文字コードが Shift_JIS(SJIS)や EUC-JP だったりすることもあるので、この場合は文字コードを意識した作りにする必要があります。
KotlinでHMAC-SHA256
Kotlin(Javaと一緒ですが)では以下のパッケージを利用するのが早そうです。
javax.crypto.Mac
javax.crypto.spec.SecretKeySpec
利用するアルゴリズムは「HmacSHA256」、共通鍵は「abcdefghijklmn」とします。
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec("abcdefghijklmn".toByteArray(), mac.algorithm))
val hash = mac.doFinal(
listOf("リラックマ", "コリラックマ", "キイロイトリ").joinToString("-").toByteArray()
).joinToString(separator = "") {
"%02x".format(it)
}
mac.doFinal() の戻り値がバイト配列になってわかりにくいので、16 進数の文字列で返すようにしてみました。
ハッシュ値は以下になります。
アルファベットを大文字にしたい場合は、最後に .toUpperCase() を追加すれば OK です。
2ddeba410bc46cc41a5f70ea9e4cfb7226bac35a195dda04cd3aa8b77e3fd5f1
PHPでHMAC-SHA256
PHP には hash_hmac() という関数が用意されていて、これを使えば一発でハッシュ値を生成することができます。
(やっぱり PHP は最高です)
利用するアルゴリズムは「sha256」、共通鍵は「abcdefghijklmn」とします。
戻り値として 16 進数の文字列が返却されますが、アルファベットは小文字になるので、必要に応じて strtoupper() などで大文字に変換するといいでしょう。
$message = sprintf('%s-%s-%s', 'リラックマ', 'コリラックマ', 'キイロイトリ');
$hash = hash_hmac('sha256', $message, 'abcdefghijklmn');
ハッシュ値は以下になります。
2ddeba410bc46cc41a5f70ea9e4cfb7226bac35a195dda04cd3aa8b77e3fd5f1
まとめ
Kotlin と PHP を使って、HMAC-SHA256 でハッシュ値を生成する方法を紹介しました。
単純な sha256 や md5 などのハッシュ値だと、ハッシュの元となるデータが推測できた場合に危険がありますが、HMAC 方式だと共通の秘密鍵を知られない限りは安全です。
双方が知らないデータの場合は、片方が暗号化して送り、もう片方が複合化する作業が必要になりますが、お互いが知っている情報ならハッシュの利用が楽ですね。
アルゴリズムの種類が多く、どれを使ったらいいのか悩むところですが、特に制限がない場合は基本的なものを採用しておくといいと思います。
数年後には使えないサンプルロジックになってしまう可能性もありますが、備忘録として残しておきます。