以前、”国会にhash関数の話が出たwww”といって、そっちの界隈の人でちょっとした話題になっていました。
では、hashとはなんなのか?分からない人もいると思います。
それがわかっても、Pythonでの実装がわからない方もいらっしゃると思いますので、この記事を書いた次第です。
hashって?
wikipediaを参照すると
データから算出した小さな値。各データを区別・表現する目的に用いる。
となっています。
つまり、あるデータから、それ固有の値を取り出して(計算から導き出す)、データの区別に使うための値。です
この計算というのが大事で、たとえば、長さが400ページ以上もある本を文字に落とし込んで所得したhashと、
その文字列の句点と読点を一個だけ入れ替えた文字列のhashは異なります。
そこから、文書の改ざん対策などにも用いられるんですね。
また、その『元からhashを求めるのは用意である』が『hashから元を求めるのは非常に困難である』という性質を利用して、暗号・セキュリティにも用いられています。
Pythonで実装
Pythonにはhash関数が元からありますので、それを利用してみましょう。
>>> hash("1") # "ハッシュ不可能"(listやset, dictなど)は用いないでください
4940519975841726253
求められましたね。
しかし、これではだめです
このhashが信頼できるのは、このインタープリタを閉じるまでだからです。
一度閉じて、もう一度実行してみましょう。
>>> hash("1")
2261270426266027010
おなじ文字列のhashを取り出したにもかかわらず、違う値が出ていますよね。
このように、正当性を確かめるには、標準のhashは不向きであるとわかります。
そこで使うのが、hashlibです
>>> import hashlib
>>> hashlib.md5(b"1").digest() # bytesにしましょう
b'\xc4\xcaB8\xa0\xb9#\x82\r\xccP\x9aou\x84\x9b'
# 一度閉じます
>>> import hashlib
>>> hashlib.md5(b"1").digest()
b'\xc4\xcaB8\xa0\xb9#\x82\r\xccP\x9aou\x84\x9b' # 同じ値が返ってきます
みなさんが同じコードを打っても、同じ値が返ってくるはずです。
これが、一意性を保っているということです。
MD5(hash化の方法の種類です)のほかに、SHA1、SHA224、SHA256、SHA384、SHA512に対応しているようです。
ユーザーのパスワードをhash化して持っておき、ログインしようとしたときに、そのhashと入力された文字列のhashを比べる、なんてこともできますよね。
MD5に関しては、衝突(別のデータが同じhash値を持つこと)が他のものと比べて多いようなので、注意です
しかし、単にハッシュにしただけでは脆弱で、Brute-Force-Attack(総当たり攻撃)に対抗するだけの力がありません。
なので、Salt(パスワードと関係のない値)と反復を繰り返すのがhashlib.pbkdf2_hmac()です。
- より高度な使用
>>> import os, hashlib, binascii
>>> salt = os.urandom(64) # osの提供する64文字長の信頼できるrandomなbytes
>>> salt
b'\xc0<U\xdc5\xea\x8d+y\xe6W\x882U\xdaG\xbe\xd5\x19\xc0\xb2l\xf5\xd5/~W2\xa9\x92z\x8b\xff\xba\x8bs\x95t)I\xd1s\xfa.\x85R\xff\xd6\x89\x10n\xb7\xc3<\x84\x87\xea\xe6X\x8a\xdb,\xc3\x1c'
>>> dk= hashlib.pbkdf2_hmac("sha256", b"PaSsWoRd", salt, 100000) # sha256でb"PaSsWoRd"とsaltを使って100000回hmacの反復
>>> binascii.hexlify(dk) # 得られたhash
b'53ce88a1559e955b7b68794225365af09261f0a411629cef554de208e33e8da7'
といった感じです。
最低反復は 10,000回以上回すことが推奨されています。
それでは皆さん、よいPythonLifeを!!