gt:                 byte[] signingKey = new byte[40];
context: /* jcifs smb client library in Java
   * Copyright (C) 2002  "Michael B. Allen" <jcifs at samba dot org>
   *                  "Eric Glass" <jcifs at samba dot org>
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package jcifs.smb;
  
  import java.io.Serializable;
  import java.io.UnsupportedEncodingException;
  import java.security.GeneralSecurityException;
  import java.security.MessageDigest;
  import java.security.Principal;
  import java.util.Arrays;
  import java.util.Random;
  
  import jcifs.Config;
  import jcifs.util.DES;
  import jcifs.util.Encdec;
  import jcifs.util.HMACT64;
  import jcifs.util.MD4;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * This class stores and encrypts NTLM user credentials. The default
   * credentials are retrieved from the <tt>jcifs.smb.client.domain</tt>,
   * <tt>jcifs.smb.client.username</tt>, and <tt>jcifs.smb.client.password</tt>
   * properties.
   * <p>
   * Read <a href="../../../authhandler.html">jCIFS Exceptions and
   * NtlmAuthenticator</a> for related information.
   */
  
  public final class NtlmPasswordAuthentication implements Principal, Serializable {
  
      private static final long serialVersionUID = 7972905964105275479L;
  
      private static final int LM_COMPATIBILITY = Config.getInt("jcifs.smb.lmCompatibility", 3);
  
      private static final Random RANDOM = new Random();
  
      private static final Logger logger = LoggerFactory.getLogger(NtlmPasswordAuthentication.class);
  
      // KGS!@#$%
      private static final byte[] S8 = {
          (byte)0x4b, (byte)0x47, (byte)0x53, (byte)0x21,
          (byte)0x40, (byte)0x23, (byte)0x24, (byte)0x25
      };
      /* Accepts key multiple of 7
       * Returns enc multiple of 8
       * Multiple is the same like: 21 byte key gives 24 byte result
       */
      private static void E( byte[] key, byte[] data, byte[] e ) {
          byte[] key7 = new byte[7];
          byte[] e8 = new byte[8];
  
          for( int i = 0; i < key.length / 7; i++ ) {
              System.arraycopy( key, i * 7, key7, 0, 7 );
              DES des = new DES( key7 );
              des.encrypt( data, e8 );
              System.arraycopy( e8, 0, e, i * 8, 8 );
          }
      }
  
      static String DEFAULT_DOMAIN;
      static String DEFAULT_USERNAME;
      static String DEFAULT_PASSWORD;
      static final String BLANK = "";
  
      public static final NtlmPasswordAuthentication ANONYMOUS = new NtlmPasswordAuthentication("", "", "");
  
      static void initDefaults() {
          if (DEFAULT_DOMAIN != null) return;
          DEFAULT_DOMAIN = Config.getProperty("jcifs.smb.client.domain", "?");
          DEFAULT_USERNAME = Config.getProperty("jcifs.smb.client.username", "GUEST");
          DEFAULT_PASSWORD = Config.getProperty("jcifs.smb.client.password", BLANK);
      }
  
  /**
   * Generate the ANSI DES hash for the password associated with these credentials.
   */
      static public byte[] getPreNTLMResponse( String password, byte[] challenge ) {
      	return getPreNTLMResponse(passwordHash(password, 1), challenge);
      }
      
  	static public byte[] getPreNTLMResponse(byte[] hash, byte[] challenge) {
  		byte[] p24 = new byte[24];
  		E(hash, challenge, p24);
  		return p24;
  	}
  
  /**
   * Generate the Unicode MD4 hash for the password associated with these credentials.
   */
      static public byte[] getNTLMResponse( String password, byte[] challenge ) {
      	return getNTLMResponse(passwordHash(password, 3), challenge);
      }
      static public byte[] getNTLMResponse( byte[] passwordHash, byte[] challenge ) {
          byte[] p21 = new byte[21];
          byte[] p24 = new byte[24];
          System.arraycopy(passwordHash, 0, p21, 0, 16);        
          E( p21, challenge, p24 );
          return p24;
      }
  
      /**
       * Creates the LMv2 response for the supplied information.
       *
       * @param domain The domain in which the username exists.
       * @param user The username.
       * @param password The user's password.
       * @param challenge The server challenge.
       * @param clientChallenge The client challenge (nonce). 
       */ 
      public static byte[] getLMv2Response(String domain, String user,
              String password, byte[] challenge, byte[] clientChallenge) {
      	return getLMv2Response(domain, user, passwordHash(password, 5), challenge, clientChallenge);
      }
      public static byte[] getLMv2Response(String domain, String user,
              byte[] passwordHash, byte[] challenge, byte[] clientChallenge) {
          try {
              byte[] response = new byte[24];
  // The next 2-1/2 lines of this should be placed with nTOWFv1 in place of password
              HMACT64 hmac = new HMACT64(passwordHash);
              hmac.update(user.toUpperCase().getBytes(SmbConstants.UNI_ENCODING));
              hmac.update(domain.toUpperCase().getBytes(SmbConstants.UNI_ENCODING));
              hmac = new HMACT64(hmac.digest());
              hmac.update(challenge);
              hmac.update(clientChallenge);
              hmac.digest(response, 0, 16);
              System.arraycopy(clientChallenge, 0, response, 16, 8);
              return response;
          } catch (Exception ex) {
              logger.error(ex.getMessage(), ex);
              return null;
          }
      }
      public static byte[] getNTLM2Response(byte[] nTOWFv1,
                      byte[] serverChallenge,
                      byte[] clientChallenge)
      {
          byte[] sessionHash = new byte[8];
  
          try {
              MessageDigest md5;
              md5 = MessageDigest.getInstance("MD5");
              md5.update(serverChallenge);
              md5.update(clientChallenge, 0, 8);
              System.arraycopy(md5.digest(), 0, sessionHash, 0, 8);
          } catch (GeneralSecurityException gse) {
              logger.error(gse.getMessage(), gse);
              throw new RuntimeException("MD5", gse);
          }
  
          byte[] key = new byte[21];
          System.arraycopy(nTOWFv1, 0, key, 0, 16);
          byte[] ntResponse = new byte[24];
          E(key, sessionHash, ntResponse);
  
          return ntResponse;
      }
      public static byte[] nTOWFv1(String password)
      {
          if (password == null)
              throw new RuntimeException("Password parameter is required");
          return nTOWFv1(passwordHash(password, 5));
      }
      public static byte[] nTOWFv1(byte[] passwordHash)
      {
      	return passwordHash;
      }
      public static byte[] nTOWFv2(String domain, String username, String password)
      {
      	return nTOWFv2(domain, username, passwordHash(password, 5));
      }
      public static byte[] nTOWFv2(String domain, String username, byte[] passwordHash)
      {
          try {
              HMACT64 hmac = new HMACT64(passwordHash);
              hmac.update(username.toUpperCase().getBytes(SmbConstants.UNI_ENCODING));
              hmac.update(domain.getBytes(SmbConstants.UNI_ENCODING));
              return hmac.digest();
          } catch (UnsupportedEncodingException uee) {
              throw new RuntimeException(uee.getMessage());
          }
      }
      static byte[] computeResponse(byte[] responseKey,
                  byte[] serverChallenge,
                  byte[] clientData,
                  int offset,
                  int length)
      {
          HMACT64 hmac = new HMACT64(responseKey);
          hmac.update(serverChallenge);
          hmac.update(clientData, offset, length);
          byte[] mac = hmac.digest();
          byte[] ret = new byte[mac.length + clientData.length];
          System.arraycopy(mac, 0, ret, 0, mac.length);
          System.arraycopy(clientData, 0, ret, mac.length, clientData.length);
          return ret;
      }
      public static byte[] getLMv2Response(
              byte[] responseKeyLM,
              byte[] serverChallenge,
              byte[] clientChallenge)
      {
          return NtlmPasswordAuthentication.computeResponse(responseKeyLM,
                      serverChallenge,
                      clientChallenge,
                      0,
                      clientChallenge.length);
      }
      public static byte[] getNTLMv2Response(
              byte[] responseKeyNT,
              byte[] serverChallenge,
              byte[] clientChallenge,
              long nanos1601,
              byte[] targetInfo)
      {
          int targetInfoLength = targetInfo != null ? targetInfo.length : 0;
          byte[] temp = new byte[28 + targetInfoLength + 4];
  
          Encdec.enc_uint32le(0x00000101, temp, 0); // Header
          Encdec.enc_uint32le(0x00000000, temp, 4); // Reserved
          Encdec.enc_uint64le(nanos1601, temp, 8);
          System.arraycopy(clientChallenge, 0, temp, 16, 8);
          Encdec.enc_uint32le(0x00000000, temp, 24); // Unknown
          if (targetInfo != null)
              System.arraycopy(targetInfo, 0, temp, 28, targetInfoLength);
          Encdec.enc_uint32le(0x00000000, temp, 28 + targetInfoLength); // mystery bytes!
  
          return NtlmPasswordAuthentication.computeResponse(responseKeyNT,
                          serverChallenge,
                          temp,
                          0,
                          temp.length);
      }
  
      static final NtlmPasswordAuthentication NULL =
                  new NtlmPasswordAuthentication( "", "", "" );
      static final NtlmPasswordAuthentication GUEST =
                  new NtlmPasswordAuthentication( "?", "GUEST", "" );
      static final NtlmPasswordAuthentication DEFAULT =
                  new NtlmPasswordAuthentication( null );
  
      String domain;
      String username;
      byte[] passwordHash;
      byte[] ansiHash;
      byte[] unicodeHash;
      boolean hashesExternal = false;
      byte[] clientChallenge = null;
      byte[] challenge = null;
  
  /**
   * Create an <tt>NtlmPasswordAuthentication</tt> object from the userinfo
   * component of an SMB URL like "<tt>domain;user:pass</tt>". This constructor
   * is used internally be jCIFS when parsing SMB URLs.
   */
  
      public NtlmPasswordAuthentication( String userInfo ) {
          domain = username = null;
  
          String password = null;
          
          if( userInfo != null ) {
              try {
                  userInfo = unescape( userInfo );
              } catch( UnsupportedEncodingException uee ) {
              }
              int i, u, end;
              char c;
  
              end = userInfo.length();
              for( i = 0, u = 0; i < end; i++ ) {
                  c = userInfo.charAt( i );
                  if( c == ';' ) {
                      domain = userInfo.substring( 0, i );
                      u = i + 1;
                  } else if( c == ':' ) {
                      password = userInfo.substring( i + 1 );
                      break;
                  }
              }
              username = userInfo.substring( u, i );
          }
  
          initDefaults();
  
          if( domain == null ) this.domain = DEFAULT_DOMAIN;
          if( username == null ) this.username = DEFAULT_USERNAME;
          if( password == null ) password = DEFAULT_PASSWORD;
  		this.passwordHash = passwordHash(password);
      }
  /**
   * Create an <tt>NtlmPasswordAuthentication</tt> object from a
   * domain, username, and password. Parameters that are <tt>null</tt>
   * will be substituted with <tt>jcifs.smb.client.domain</tt>,
   * <tt>jcifs.smb.client.username</tt>, <tt>jcifs.smb.client.password</tt>
   * property values.
   */
      public NtlmPasswordAuthentication( String domain, String username, String password ) {
          this(domain, username, passwordHash(password, LM_COMPATIBILITY));
      }
      
      public NtlmPasswordAuthentication( String domain, String username, byte[] passwordHash ) {
          int ci;
  
          if (username != null) {
              ci = username.indexOf('@');
              if (ci > 0) {
                  domain = username.substring(ci + 1);
                  username = username.substring(0, ci);
              } else {
                  ci = username.indexOf('\\');
                  if (ci > 0) {
                      domain = username.substring(0, ci);
                      username = username.substring(ci + 1);
                  }
              }
          }
  
          this.domain = domain;
          this.username = username;
  
          initDefaults();
  
          if( domain == null ) this.domain = DEFAULT_DOMAIN;
          if( username == null ) this.username = DEFAULT_USERNAME;
          this.passwordHash = passwordHash;
      }
  /**
   * Create an <tt>NtlmPasswordAuthentication</tt> object with raw password
   * hashes. This is used exclusively by the <tt>jcifs.http.NtlmSsp</tt>
   * class which is in turn used by NTLM HTTP authentication functionality.
   */
      public NtlmPasswordAuthentication( String domain, String username,
                      byte[] challenge, byte[] ansiHash, byte[] unicodeHash ) {
          if( domain == null || username == null ||
                                      ansiHash == null || unicodeHash == null ) {
              throw new IllegalArgumentException( "External credentials cannot be null" );
          }
          this.domain = domain;
          this.username = username;
          this.challenge = challenge;
          this.ansiHash = ansiHash;
          this.unicodeHash = unicodeHash;
          hashesExternal = true;
      }
  
  /**
   * Returns the domain.
   */
      public String getDomain() {
          return domain;
      }
  
  /**
   * Returns the username.
   */
      public String getUsername() {
          return username;
      }
  /**
   * Returns the password in plain text or <tt>null</tt> if the raw password
   * hashes were used to construct this <tt>NtlmPasswordAuthentication</tt>
   * object which will be the case when NTLM HTTP Authentication is
   * used. There is no way to retrieve a users password in plain text unless
   * it is supplied by the user at runtime.
   */
      public byte[] getPasswordHash() {
          return passwordHash;
      }
  /**
   * Return the domain and username in the format:
   * <tt>domain\\username</tt>. This is equivalent to <tt>toString()</tt>.
   */
      public String getName() {
          boolean d = domain.length() > 0 && domain.equals( "?" ) == false;
          return d ? domain + "\\" + username : username;
      }
  
  /**
   * Computes the 24 byte ANSI password hash given the 8 byte server challenge.
   */
      public byte[] getAnsiHash( byte[] challenge ) {
          if( hashesExternal ) {
              return ansiHash;
          }
          switch (LM_COMPATIBILITY) {
          case 0:
          case 1:
              return getPreNTLMResponse( passwordHash, challenge );
          case 2:
              return getNTLMResponse( passwordHash, challenge );
          case 3:
          case 4:
          case 5:
              if( clientChallenge == null ) {
                  clientChallenge = new byte[8];
                  RANDOM.nextBytes( clientChallenge );
              }
              return getLMv2Response(domain, username, passwordHash, challenge,
                      clientChallenge);
          default:
              return getPreNTLMResponse( passwordHash, challenge );
          }
      }
  /**
   * Computes the 24 byte Unicode password hash given the 8 byte server challenge.
   */
      public byte[] getUnicodeHash( byte[] challenge ) {
          if( hashesExternal ) {
              return unicodeHash;
          }
          switch (LM_COMPATIBILITY) {
          case 0:
          case 1:
          case 2:
              return getNTLMResponse( passwordHash, challenge );
          case 3:
          case 4:
          case 5:
              /*
              if( clientChallenge == null ) {
                  clientChallenge = new byte[8];
                  RANDOM.nextBytes( clientChallenge );
              }
              return getNTLMv2Response(domain, username, password, null,
                      challenge, clientChallenge);
              */
              return new byte[0];
          default:
              return getNTLMResponse( passwordHash, challenge );
          }
      }
  
      public byte[] getSigningKey(byte[] challenge) throws SmbException
      {
          switch (LM_COMPATIBILITY) {
              case 0:
              case 1:
              case 2:
  