PBKDF1
PBKDF1¶
- Do not Use
- Using HMAC Key Derivation Functions (HKDF) is less secure than using PBKDF2, Bcrypt, Scrypt or Argon2.
Since the Input to the function is of fixed size and exactly equal to the output size there is a smaller amount of possible inputs and also it makes the 2 iteration have the same possible inputs as the 10th iteration.
Either there will be a larger possibility for collision of two arbitrary messages.
Or there will be a cycle where hashing a message creates the same output as hashing the same message N times.
Implementation¶
How it works:
import hashlib
def fixedlen_xor(input1, input2):
assert(len(input1) == len(input2))
return bytes([input1[i] ^ input2[i] for i in range(len(input1))])
def int_to_bytes_length(i_data, length, be=True):
if be:
return (i_data).to_bytes(length, byteorder='big')
else:
return (i_data).to_bytes(length, byteorder='little')
def hmac(key, message, hash_function):
#Get hash_function block_size
block_size = getattr(hash_function(), 'block_size')
# Check if key is longer than block size.
if len(key) > block_size:
# IF it is then hash the key. This makes the keysize the same as the output of the hashfunction
key = hash_function(key).digest()
# IF key is shorter
if len(key) < block_size:
# Pad the key to blocksize
key = key + b"\x00" * (block_size - len(key))
#print(key, len(key), block_size)
# Create Keys
o_key = fixedlen_xor(key, b"\x5c" * block_size)
i_key = fixedlen_xor(key, b"\x36" * block_size)
#Hash i_key and message
tmp = hash_function(i_key + message)
#Hash the o_key and the hashed output of above
return hash_function(o_key + tmp.digest()).digest()
def pbkdf1(password, salt, itterations=1000, keylength=24, hashobj=hashlib.sha1):
output_hash = hashobj(password + salt).digest()
#Check if keylength is too big for hash function
if len(output_hash) < keylength:
raise Exception("Invalid length {} for hash function".format(keylength))
#Do Loop for itterations
for idx in range(itterations):
output_hash = hashobj(output_hash).digest()
#Return the hash with the correct size
return output_hash[:keylength]
if __name__ == '__main__':
print(pbkdf1(b'password', b'salt', 1, 20, hashlib.sha1).hex())
#47e97e39e2b32b15eb9278e53f7bfca57f8e6b2c