def _get_exchange_key_ntlm_v1(negotiate_flags, session_base_key, server_challenge, lm_challenge_response, lm_hash): """ [MS-NLMP] v28.0 2016-07-14 4.3.5.1 KXKEY Calculates the Key Exchange Key for NTLMv1 authentication. Used for signing and sealing messages @param negotiate_flags: @param session_base_key: A session key calculated from the user password challenge @param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE @param lm_challenge_response: The LmChallengeResponse value computed in ComputeResponse @param lm_hash: The LMOWF computed in Compute Response @return key_exchange_key: The Key Exchange Key (KXKEY) used to sign and seal messages and compute the ExportedSessionKey """ if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: key_exchange_key = hmac.new( session_base_key, server_challenge + lm_challenge_response[:8]).digest() elif negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_LM_KEY: des_handler = des.DES(lm_hash[:7]) first_des = des_handler.encrypt(lm_challenge_response[:8]) des_handler = des.DES(lm_hash[7:8] + binascii.unhexlify('bdbdbdbdbdbdbd')) second_des = des_handler.encrypt(lm_challenge_response[:8]) key_exchange_key = first_des + second_des elif negotiate_flags & NegotiateFlags.NTLMSSP_REQUEST_NON_NT_SESSION_KEY: key_exchange_key = lm_hash[:8] + b'\0' * 8 else: key_exchange_key = session_base_key return key_exchange_key
def _lmowfv1(password): """ [MS-NLMP] v28.0 2016-07-14 3.3.1 NTLM v1 Authentication Same function as LMOWFv1 in document to create a one way hash of the password. Only used in NTLMv1 auth without session security :param password: The password of the user we are trying to authenticate with :return res: A Lan Manager hash of the password supplied """ # fix the password length to 14 bytes password = password.upper() lm_pw = password[0:14] # do hash magic_str = b"KGS!@#$%" # page 56 in [MS-NLMP v28.0] res = b'' dobj = des.DES(lm_pw[0:7]) res = res + dobj.encrypt(magic_str) dobj = des.DES(lm_pw[7:14]) res = res + dobj.encrypt(magic_str) return res
def _lmowfv1(password): """ [MS-NLMP] v28.0 2016-07-14 3.3.1 NTLM v1 Authentication Same function as LMOWFv1 in document to create a one way hash of the password. Only used in NTLMv1 auth without session security :param password: The password or hash of the user we are trying to authenticate with :return res: A Lan Manager hash of the password supplied """ # if the password is a hash, return the LM hash if re.match(r'^[a-fA-F\d]{32}:[a-fA-F\d]{32}$', password): lm_hash = binascii.unhexlify(password.split(':')[0]) return lm_hash # fix the password length to 14 bytes password = password.upper() lm_pw = password[0:14] # do hash magic_str = b"KGS!@#$%" # page 56 in [MS-NLMP v28.0] res = b'' dobj = des.DES(lm_pw[0:7]) res = res + dobj.encrypt(magic_str) dobj = des.DES(lm_pw[7:14]) res = res + dobj.encrypt(magic_str) return res
def _calc_resp(password_hash, server_challenge): """ Generate the LM response given a 16-byte password hash and the challenge from the CHALLENGE_MESSAGE :param password_hash: A 16-byte password hash :param server_challenge: A random 8-byte response generated by the server in the CHALLENGE_MESSAGE :return res: A 24-byte buffer to contain the LM response upon return """ # padding with zeros to make the hash 21 bytes long password_hash += b'\0' * (21 - len(password_hash)) res = b'' dobj = des.DES(password_hash[0:7]) res = res + dobj.encrypt(server_challenge[0:8]) dobj = des.DES(password_hash[7:14]) res = res + dobj.encrypt(server_challenge[0:8]) dobj = des.DES(password_hash[14:21]) res = res + dobj.encrypt(server_challenge[0:8]) return res