| 159 | |
| 160 | |
| 161 | def generateChallengeResponseV2(password, user, server_challenge, server_info, domain = '', client_challenge = None): |
| 162 | client_timestamp = b'\0' * 8 |
| 163 | |
| 164 | if not client_challenge: |
| 165 | client_challenge = bytes([ random.getrandbits(8) for i in range(0, 8) ]) |
| 166 | |
| 167 | assert len(client_challenge) == 8 |
| 168 | |
| 169 | d = MD4() |
| 170 | d.update(password.encode('UTF-16LE')) |
| 171 | ntlm_hash = d.digest() # The NT password hash |
| 172 | response_key = hmac.new(ntlm_hash, (user.upper() + domain).encode('UTF-16LE'), 'md5').digest() # The NTLMv2 password hash. In [MS-NLMP], this is the result of NTOWFv2 and LMOWFv2 functions |
| 173 | temp = b'\x01\x01' + b'\0'*6 + client_timestamp + client_challenge + b'\0'*4 + server_info |
| 174 | ntproofstr = hmac.new(response_key, server_challenge + temp, 'md5').digest() |
| 175 | |
| 176 | nt_challenge_response = ntproofstr + temp |
| 177 | lm_challenge_response = hmac.new(response_key, server_challenge + client_challenge, 'md5').digest() + client_challenge |
| 178 | session_key = hmac.new(response_key, ntproofstr, 'md5').digest() |
| 179 | |
| 180 | return nt_challenge_response, lm_challenge_response, session_key |
| 181 | |
| 182 | |
| 183 | ################ |