• 2018-06-21
ウズマスター戦記
ウズマスター戦記 https://www.uzumax.org/2018/06/python-hmac.html

Pythonでハッシュ作成 HMAC版

以下の記事でPythonの標準ライブラリ「hashlib」で文字列からハッシュを出力する例があります。




しかしながら、上記ページに記載したhashlibの方式だとセキュリティ的にイマイチということで、一般には「hmac」を使用したやり方が推奨されているようです。

何故HMACでなければダメなのか?

暗号学的な話になってきて私も詳しい部分までは理解出来ていないのですが、要するにこういうことです。

基本的に暗号は総当たりで破る(ブルートフォース攻撃)というやり方に強いことが大前提です。
ブルートフォース攻撃は単純に処理効率と時間との闘いでして、最新のパソコンを総動員して解析に当たっても、宇宙が終わるまで解析が完了しないようになっているのが暗号というものです。

しかしながら、単純な総当たりではなく、暗号学を駆使した数学的手法でアタックを仕掛けると、案外短い時間で解析が完了してしまうケースがあるそうなのです。

これに対抗する為に編み出されたのがHMACです。

HMAC概要

IPAが公開しているHMACの説明はこちら。


これも難しいので簡単に解説しますと、HMACは暗号ハッシュ関数そのものではなく、暗号ハッシュ関数の使い方みたいなものです。

シンプルなハッシュ生成の進め方

普通に暗号ハッシュ関数を使う場合は以下のロジックです。

  • メッセージ本体と秘密鍵を文字列連結
  • ハッシュ関数でハッシュ化

しかし、この「秘密鍵をお尻にくっつけただけ」というやり方がヤバいそうなんですよ。
「衝突」と言って、違う値から作っているのにハッシュが同じになってしまうという事象を応用することで破れてしまうこともあるそうな。

HMAC方式のハッシュ生成の進め方

対して、HMAC方式はこんな感じ。

  • メッセージ本体と秘密鍵の前半を使って、ハッシュ化
  • さらに秘密鍵の後半を使って、ハッシュ化

秘密鍵をちょこっとズラして二回ハッシュ化する、と。

こうするとシンプルハッシュで通用した衝突探しの手法を使おうとしても、その衝突を探すのに何十万年も掛かってしまって、到底実現不可能だということになるそうです。

だから、ハッシュを作る時はHMACを使用する。

これが今や鉄則らしいですね。

サンプルソース

というわけで、PythonでHMACを使用したハッシュ出力のサンプルはこちら。

ソース

import hmac
import hashlib

# ハッシュ化する文字列(パスワード)など
password = 'heibon'
secret_key = 'uzu123'

print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.md5).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha1).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha224).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha256).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha384).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha512).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.blake2b).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.blake2s).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha3_224).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha3_256).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha3_384).hexdigest())
print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.sha3_512).hexdigest())

# 使用出来ない
# print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.shake_128).hexdigest())

# 使用できない
# print(hmac.new(password.encode("UTF-8"), secret_key.encode("UTF-8"), hashlib.shake_256).hexdigest())

結果

bc2dc0fd059ca240433e39dbdc537b15
af2e4f98d29092f224cba616b356dede1f8b6d1b
b6de8b5a8ba6a79a998f6d89edbb2c1355fa089cae5244e7961a0a25
4cf6ff82157dbd5f51459a7052b0812fe4cf376da616f695f6aff67f86ef9648
9f44c64f759f661913a8d31c66825f14745316eae220f02bbf7a8f0f3775a3b81cabe34f91c442aa36adea1521701476
7f8513e1a6abfdf27e23387a6cedd9e3f0b7e2949ae982fbfc51720be61d97e6d0a975b487edab229af404eb1ab77ed9982861db34c86f7b8000cb91d969d403
f32c21248684f59f2d9c472657df88c57f18c138223fba64cc375e79c6b1a0dd8931b62e94ce8927ea9c8c0ea67d1d7dfbe625c0a688dab1f0996140e1cbad2c
8d9dcec8227673486299dbd592a4a8fbbe0435b16cab02b77734cc338176f720
af6e67f05bef28c916d0d40dd51439d212007c09482c8d60c6732855
38958524e71459d0084d9662383ff4fe333585322cfbd8a55bc3d5f87a0b6b11
13c9feb0289d1380dd83fba778fda9653c085fcdad613f612bbec4ebbe27a44e86752c80277a70da941e8c5c18bcf9cf
5f201790622ac4fac0897366b52fa1b771e629768e0219ae53abdb1dd29ea83ffab8f4d7db905a099ce6c89f0ff73d3b0856a4baa85724a4cfb404d7aee7fe44

補足

HMACの中身はhashlibと同じなので、hashlibで使用出来た暗号ハッシュ関数は全部使えるはず……、と思ったら、shake128とshake256は使用できませんでした。



It's not a bug, but indented behavior. It does not make any sense to use SHAKE with the HMAC construct. In fact it does not make sense to combine Keccak sponge or Blake2 with HMAC at all. HMAC is only necessary for old, Merkle-Damgard hashing algorithms like MD5, SHA1 and SHA2, because they are subject to length extension attacks. The correct solution is 4. improve documentation

HMACというのは、MD5、SHA1、SHA2のようなlength-extension 攻撃に弱い暗号の為に存在するのであって、
SHAKEにはそういう問題は無いから不要だそうな。

むむ、色々と難しいものですね。

関連書籍


0 件のコメント:

コメントを投稿

お気軽にコメント下さい。