/**
  * {@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);
 }