'''
/* Python Crypto Functions Source Code */

 Placed into Public Domain 
 2015, Karl-Uwe Frank
'''

from hashlib import md5, sha1

# -----------------------------------------
# HMAC MD5
#
# H(K XOR opad, H(K XOR ipad, text))
#
# ipad = 0x36, opad = 0x5c
#
def hmac_md5(key, message):
  blocksize = md5().block_size
  key_str   = str('')
  inner_pad = bytearray(blocksize)
  outer_pad = bytearray(blocksize)

  # Pass a possible keyarray into a String
  # because len(key) will always give 
  # size of the bytearray as result
  if (type(key) == bytearray):
    for i in range(0,len(key)):
      if (key[i] > 0): key_str += chr(key[i])
  else:
    key_str = key

  # If the Key is to long use it's Hash  
  if (len(key_str) > blocksize):
    key_str = md5(key_str).digest()
  
  # If the Key is to short fill it up with Zero
  if (len(key_str) < blocksize):
    for i in range(0,(blocksize - len(key_str))):
      key_str += chr(0x00) 
 
  # Generate the Pads
  for i in range(0,blocksize):
    inner_pad[i] = 0x36
    outer_pad[i] = 0x5c

  # XOR the Key against the Pads
  for i in range(0,len(key_str)):
    inner_pad[i] = (inner_pad[i] ^ ord(key_str[i]))
    outer_pad[i] = (outer_pad[i] ^ ord(key_str[i]))
  
  # Return the HMAC
  return md5(outer_pad + md5(inner_pad + message).digest())



#-----------------------------------------
# 
# Password based Key Derivation Function
#
def PBKDF2_md5(Password, salt, c, dkLen):
  hLen = 16 # Length of MD5 digest
  blockCount = int(math.ceil(dkLen / hLen))+2
  
  T_i = U_i = DK = str('')
  
  for i in range(1, blockCount):
    # Encoded "i" as 4 Bytes (Big Endian)
    i4Byte = bytearray(4)
    i4Byte[0] = ((i >> 24) & 0xff)
    i4Byte[1] = ((i >> 16) & 0xff)
    i4Byte[2] = ((i >>  8) & 0xff)
    i4Byte[3] = ( i        & 0xff)
    
    U_i = salt + i4Byte
        
    # Perform the first Iteration
    T_i = hmac_md5(Password, U_i).digest()
    U_i = T_i
   
    # Perform the remaining Iterations
    for j in range(1, c):
      U_i = hmac_md5(Password, U_i).digest()

      T = str('')      
      for k in range(0, hLen):
        T += chr(ord(T_i[k]) ^ ord(U_i[k]))
      
      # Pass over the temp Var  
      T_i = T

    # Concatenate the finaly derived Key        
    DK = DK + T_i
  
  return DK[0:dkLen]