2012-11-07 06:14:25 -07:00
|
|
|
# A simple implementation of pbkdf2 using stock python modules. See RFC2898
|
|
|
|
# for details. Basically, it derives a key from a password and salt.
|
2010-12-30 15:41:07 -07:00
|
|
|
|
2012-11-07 06:14:25 -07:00
|
|
|
# Copyright 2004 Matt Johnston <matt @ ucc asn au>
|
|
|
|
# Copyright 2009 Daniel Holth <dholth@fastmail.fm>
|
|
|
|
# This code may be freely used and modified for any purpose.
|
2010-12-30 15:41:07 -07:00
|
|
|
|
2012-11-07 06:14:25 -07:00
|
|
|
# Revision history
|
|
|
|
# v0.1 October 2004 - Initial release
|
|
|
|
# v0.2 8 March 2007 - Make usable with hashlib in Python 2.5 and use
|
|
|
|
# v0.3 "" the correct digest_size rather than always 20
|
|
|
|
# v0.4 Oct 2009 - Rescue from chandler svn, test and optimize.
|
2011-06-15 23:59:20 -06:00
|
|
|
|
2012-11-07 06:14:25 -07:00
|
|
|
import sys
|
|
|
|
import hmac
|
2012-05-16 10:15:43 -06:00
|
|
|
from struct import pack
|
2012-11-07 06:14:25 -07:00
|
|
|
try:
|
|
|
|
# only in python 2.5
|
|
|
|
import hashlib
|
|
|
|
sha = hashlib.sha1
|
|
|
|
md5 = hashlib.md5
|
|
|
|
sha256 = hashlib.sha256
|
|
|
|
except ImportError: # pragma: NO COVERAGE
|
|
|
|
# fallback
|
|
|
|
import sha
|
|
|
|
import md5
|
|
|
|
|
|
|
|
# this is what you want to call.
|
|
|
|
def pbkdf2( password, salt, itercount, keylen, hashfn = sha ):
|
2010-12-30 15:41:07 -07:00
|
|
|
try:
|
2012-11-07 06:14:25 -07:00
|
|
|
# depending whether the hashfn is from hashlib or sha/md5
|
|
|
|
digest_size = hashfn().digest_size
|
|
|
|
except TypeError: # pragma: NO COVERAGE
|
|
|
|
digest_size = hashfn.digest_size
|
|
|
|
# l - number of output blocks to produce
|
|
|
|
l = keylen / digest_size
|
|
|
|
if keylen % digest_size != 0:
|
|
|
|
l += 1
|
|
|
|
|
|
|
|
h = hmac.new( password, None, hashfn )
|
|
|
|
|
|
|
|
T = ""
|
|
|
|
for i in range(1, l+1):
|
|
|
|
T += pbkdf2_F( h, salt, itercount, i )
|
|
|
|
|
|
|
|
return T[0: keylen]
|
|
|
|
|
|
|
|
def xorstr( a, b ):
|
|
|
|
if len(a) != len(b):
|
|
|
|
raise ValueError("xorstr(): lengths differ")
|
|
|
|
return ''.join((chr(ord(x)^ord(y)) for x, y in zip(a, b)))
|
|
|
|
|
|
|
|
def prf( h, data ):
|
|
|
|
hm = h.copy()
|
|
|
|
hm.update( data )
|
|
|
|
return hm.digest()
|
|
|
|
|
|
|
|
# Helper as per the spec. h is a hmac which has been created seeded with the
|
|
|
|
# password, it will be copy()ed and not modified.
|
|
|
|
def pbkdf2_F( h, salt, itercount, blocknum ):
|
|
|
|
U = prf( h, salt + pack('>i',blocknum ) )
|
|
|
|
T = U
|
|
|
|
|
|
|
|
for i in range(2, itercount+1):
|
|
|
|
U = prf( h, U )
|
|
|
|
T = xorstr( T, U )
|
|
|
|
|
|
|
|
return T
|