パスワードのハッシュ化には、mitsuhiko の pbkdf2 の実装を使用します。
def pbkdf2_bin(data, salt, iterations=1000, keylen=24, hashfunc=None):
"""Returns a binary digest for the PBKDF2 hash algorithm of `data`
with the given `salt`. It iterates `iterations` time and produces a
key of `keylen` bytes. By default SHA-1 is used as hash function,
a different hashlib `hashfunc` can be provided.
"""
hashfunc = hashfunc or hashlib.sha1
mac = hmac.new(data, None, hashfunc)
def _pseudorandom(x, mac=mac):
h = mac.copy()
h.update(x)
return map(ord, h.digest())
buf = []
for block in xrange(1, -(-keylen // mac.digest_size) + 1):
rv = u = _pseudorandom(salt + _pack_int(block))
for i in xrange(iterations - 1):
u = _pseudorandom(''.join(map(chr, u)))
rv = starmap(xor, izip(rv, u))
buf.extend(rv)
return ''.join(map(chr, buf))[:keylen]
この関数は、base64 でエンコードされてデータベースに保存されるバイナリ ダイジェストを返します。また、ユーザーがログインすると、base64 文字列が Cookie として設定されます。
この関数は、パスワード ハッシュの比較に使用されます。
def comparePasswords(password1, password2):
if len(password1) != len(password2):
return False
diff = 0
for x, y in izip(password1, password2):
diff |= ord(x) ^ ord(y)
return diff == 0
バイナリ ハッシュと base64 文字列の比較で、セキュリティの点で違いがあるのだろうか? たとえば、ユーザーがログインすると、送信されたパスワードのバイナリ ダイジェストを計算し、データベースから base64 文字列をデコードしてから 2 つのバイナリ ハッシュを比較しますが、ユーザーが base64 文字列の Cookie を持っている場合は、それを a 文字列と直接比較しますデータベース。
2 番目の質問は塩についてです。
os.urandom はバイナリ文字列を返しますが、ハッシュ生成で使用する前に base64 でエンコードします。これを行ってソルトをバイナリ形式で使用してはならない理由はありますか?