/** * {@inheritDoc} */ public function encode($username, $nt_domain, $client_hostname, CredentialInterface $credential, ServerChallenge $server_challenge) { $negotiate_flags = $server_challenge->getNegotiateFlags(); $server_challenge_nonce = $server_challenge->getNonce(); $target_name = $this->identifyTargetName($username, $nt_domain, $server_challenge); $client_challenge = null; // If extended session security is negotiated if ((NegotiateFlag::NEGOTIATE_EXTENDED_SESSION_SECURITY & $negotiate_flags) === NegotiateFlag::NEGOTIATE_EXTENDED_SESSION_SECURITY) { // Generate a client challenge $client_challenge = $this->random_byte_generator->generate(static::CLIENT_CHALLENGE_LENGTH); } $lm_hash = null; $nt_hash = null; $lm_challenge_response = null; $nt_challenge_response = null; $calculate_lm_response = true; $calculate_nt_response = true; if ($credential->isPlaintext()) { $lm_hash = $this->lm_hasher->hash($credential); $nt_hash = $this->nt_hasher->hash($credential); } elseif ($credential instanceof HashCredentialInterface) { switch ($credential->getType()) { case HashType::LM: $lm_hash = $credential; $calculate_nt_response = false; break; case HashType::NT_V1: $nt_hash = $credential; $calculate_lm_response = false; break; default: throw new InvalidArgumentException('Unsupported hash credential type'); } } if (null !== $nt_hash && $calculate_nt_response) { $nt_challenge_response = $this->calculateNtResponse($nt_hash, $client_challenge, $server_challenge_nonce); } // If we have a client challenge, extended session security must be negotiated if (null !== $client_challenge) { // Set the LM challenge response to the client challenge, null-padded to the expected length $lm_challenge_response = str_pad($client_challenge, static::LM_RESPONSE_LENGTH, static::NULL_PAD_CHARACTER); } elseif (null !== $lm_hash && $calculate_lm_response) { $lm_challenge_response = $this->calculateLmResponse($lm_hash, $client_challenge, $server_challenge_nonce); } else { // According to the spec, we're supposed to use the NT challenge response for the LM challenge response, // if an LM challenge response isn't calculated $lm_challenge_response = $nt_challenge_response; } // TODO: Generate an encrypted random session key $session_key = ''; return $this->encodeBinaryMessageString($negotiate_flags, $lm_challenge_response, $nt_challenge_response, $target_name, $username, $client_hostname, $session_key); }
/** * Identifies the "TargetName" of the intended authentication by inspecting * some of the authentication details. * * @param string $username The user's "username". * @param string $nt_domain The domain name of the NT user authenticating. * @param ServerChallenge $server_challenge The value of a decoded NTLM * server's "CHALLENGE_MESSAGE". * @return string The identified "TargetName" (domain/server name) of the * NT user authenticating. */ public function identifyTargetName($username, $nt_domain, ServerChallenge $server_challenge) { // If a domain name wasn't supplied, fall back to the server challenge's supplied value $target_name = $nt_domain ?: $server_challenge->getTargetName(); /** * If the username is in the "UPN" (Kerberos) format, the target name should be empty * * @link https://msdn.microsoft.com/en-us/library/windows/desktop/aa380525(v=vs.85).aspx * @link http://davenport.sourceforge.net/ntlm.html#nameVariations */ if (false !== strpos($username, static::USER_PRINCIPAL_NAME_SEPARATOR)) { $target_name = ''; } return $target_name; }
/** * {@inheritDoc} */ public function encode($username, $nt_domain, $client_hostname, CredentialInterface $credential, ServerChallenge $server_challenge) { $negotiate_flags = $server_challenge->getNegotiateFlags(); $server_challenge_nonce = $server_challenge->getNonce(); $target_info = $server_challenge->getTargetInfo(); $target_name = $this->identifyTargetName($username, $nt_domain, $server_challenge); // Generate a client challenge $client_challenge = $this->random_byte_generator->generate(static::CLIENT_CHALLENGE_LENGTH); // Encode the "blob" $binary_blob = $this->encodeBlob(new DateTime(), $client_challenge, $target_info); if ($credential->isPlaintext()) { $nt_hash = $this->nt_hasher->hash($credential, $username, $target_name); } elseif ($credential instanceof HashCredentialInterface && HashType::NT_V2 === $credential->getType()) { $nt_hash = $credential; } else { throw new InvalidArgumentException('Unsupported hash credential type'); } $lm_challenge_response = $this->calculateLmResponse($nt_hash, $client_challenge, $server_challenge_nonce); $nt_proof_string = $this->calculateNtProofString($nt_hash, $server_challenge_nonce, $binary_blob); $nt_challenge_response = $nt_proof_string . $binary_blob; // TODO: Generate an encrypted random session key $session_key = ''; return $this->encodeBinaryMessageString($negotiate_flags, $lm_challenge_response, $nt_challenge_response, $target_name, $username, $client_hostname, $session_key); }