def pkcs12_kdf(hash_algorithm, password, salt, iterations, key_length, id_):
if not isinstance(password, byte_cls):<EOL><INDENT>raise TypeError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>type_name(password)<EOL>))<EOL><DEDENT>if not isinstance(salt, byte_cls):<EOL><INDENT>raise TypeError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>type_name(salt)<EOL>))<EOL><DEDENT>if not isinstance(iterations, int_types):<EOL><INDENT>raise TypeError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>type_name(iterations)<EOL>))<EOL><DEDENT>if iterations < <NUM_LIT:1>:<EOL><INDENT>raise ValueError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>repr(iterations)<EOL>))<EOL><DEDENT>if not isinstance(key_length, int_types):<EOL><INDENT>raise TypeError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>type_name(key_length)<EOL>))<EOL><DEDENT>if key_length < <NUM_LIT:1>:<EOL><INDENT>raise ValueError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>repr(key_length)<EOL>))<EOL><DEDENT>if hash_algorithm not in set(['<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>']):<EOL><INDENT>raise ValueError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>repr(hash_algorithm)<EOL>))<EOL><DEDENT>if id_ not in set([<NUM_LIT:1>, <NUM_LIT:2>, <NUM_LIT:3>]):<EOL><INDENT>raise ValueError(pretty_message(<EOL>'''<STR_LIT>''',<EOL>repr(id_)<EOL>))<EOL><DEDENT>utf16_password = password.decode('<STR_LIT:utf-8>').encode('<STR_LIT>') + b'<STR_LIT>'<EOL>algo = getattr(hashlib, hash_algorithm)<EOL>u = {<EOL>'<STR_LIT>': <NUM_LIT:16>,<EOL>'<STR_LIT>': <NUM_LIT:20>,<EOL>'<STR_LIT>': <NUM_LIT>,<EOL>'<STR_LIT>': <NUM_LIT:32>,<EOL>'<STR_LIT>': <NUM_LIT>,<EOL>'<STR_LIT>': <NUM_LIT:64><EOL>}[hash_algorithm]<EOL>if hash_algorithm in ['<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>v = <NUM_LIT><EOL><DEDENT>else:<EOL><INDENT>v = <NUM_LIT:64><EOL><DEDENT>d = chr_cls(id_) * v<EOL>s = b'<STR_LIT>'<EOL>if salt != b'<STR_LIT>':<EOL><INDENT>s_len = v * int(math.ceil(float(len(salt)) / v))<EOL>while len(s) < s_len:<EOL><INDENT>s += salt<EOL><DEDENT>s = s[<NUM_LIT:0>:s_len]<EOL><DEDENT>p = b'<STR_LIT>'<EOL>if utf16_password != b'<STR_LIT>':<EOL><INDENT>p_len = v * int(math.ceil(float(len(utf16_password)) / v))<EOL>while len(p) < p_len:<EOL><INDENT>p += utf16_password<EOL><DEDENT>p = p[<NUM_LIT:0>:p_len]<EOL><DEDENT>i = s + p<EOL>c = int(math.ceil(float(key_length) / u))<EOL>a = b'<STR_LIT:\x00>' * (c * u)<EOL>for num in range(<NUM_LIT:1>, c + <NUM_LIT:1>):<EOL><INDENT>a2 = algo(d + i).digest()<EOL>for _ in range(<NUM_LIT:2>, iterations + <NUM_LIT:1>):<EOL><INDENT>a2 = algo(a2).digest()<EOL><DEDENT>if num < c:<EOL><INDENT>b = b'<STR_LIT>'<EOL>while len(b) < v:<EOL><INDENT>b += a2<EOL><DEDENT>b = int_from_bytes(b[<NUM_LIT:0>:v]) + <NUM_LIT:1><EOL>for num2 in range(<NUM_LIT:0>, len(i) // v):<EOL><INDENT>start = num2 * v<EOL>end = (num2 + <NUM_LIT:1>) * v<EOL>i_num2 = i[start:end]<EOL>i_num2 = int_to_bytes(int_from_bytes(i_num2) + b)<EOL>i_num2_l = len(i_num2)<EOL>if i_num2_l > v:<EOL><INDENT>i_num2 = i_num2[i_num2_l - v:]<EOL><DEDENT>i = i[<NUM_LIT:0>:start] + i_num2 + i[end:]<EOL><DEDENT><DEDENT>begin = (num - <NUM_LIT:1>) * u<EOL>to_copy = min(key_length, u)<EOL>a = a[<NUM_LIT:0>:begin] + a2[<NUM_LIT:0>:to_copy] + a[begin + to_copy:]<EOL><DEDENT>return a[<NUM_LIT:0>:key_length]<EOL>
KDF from RFC7292 appendix b.2 - https://tools.ietf.org/html/rfc7292#page-19

:param hash_algorithm:
    The string name of the hash algorithm to use: "md5", "sha1", "sha224",
    "sha256", "sha384", "sha512"

:param password:
    A byte string of the password to use an input to the KDF

:param salt:
    A cryptographic random byte string

:param iterations:
    The numbers of iterations to use when deriving the key

:param key_length:
    The length of the desired key in bytes

:param id_:
    The ID of the usage - 1 for key, 2 for iv, 3 for mac

:return:
    The derived key as a byte string