/** * Perform an NTLMv2 session key check * * @param md4hash String * @param challenge byte[] * @param type3Msg Type3NTLMMessage * @return boolean */ protected final boolean checkNTLMv2SessionKey( String md4hash, byte[] challenge, Type3NTLMMessage type3Msg) { if (getLogger().isDebugEnabled()) getLogger().debug(("Perform an NTLMv2 session key check.")); // Create the value to be encrypted by appending the server challenge and client challenge // and applying an MD5 digest byte[] nonce = new byte[16]; System.arraycopy(challenge, 0, nonce, 0, 8); System.arraycopy(type3Msg.getLMHash(), 0, nonce, 8, 8); MessageDigest md5 = null; byte[] v2challenge = new byte[8]; try { // Create the MD5 digest md5 = MessageDigest.getInstance("MD5"); // Apply the MD5 digest to the nonce md5.update(nonce); byte[] md5nonce = md5.digest(); // We only want the first 8 bytes System.arraycopy(md5nonce, 0, v2challenge, 0, 8); } catch (NoSuchAlgorithmException ex) { // Log the error getLogger().error(ex); } // Generate the local encrypted password using the MD5 generated challenge byte[] p21 = new byte[21]; byte[] md4byts = m_md4Encoder.decodeHash(md4hash); System.arraycopy(md4byts, 0, p21, 0, 16); // Generate the local hash of the password byte[] localHash = null; try { localHash = m_encryptor.doNTLM1Encryption(p21, v2challenge); } catch (NoSuchAlgorithmException ex) { // Log the error getLogger().error(ex); } // Validate the password byte[] clientHash = type3Msg.getNTLMHash(); if (clientHash != null && localHash != null && clientHash.length == localHash.length) { int i = 0; while (i < clientHash.length && clientHash[i] == localHash[i]) { i++; } if (i == clientHash.length) { if (getLogger().isDebugEnabled()) getLogger().debug(("Hashed password check successful.")); return true; } } if (getLogger().isDebugEnabled()) getLogger().debug(("Password check failed.")); return false; }
/** * Perform an NTLMv1 hashed password check * * @param md4hash String * @param challenge byte[] * @param type3Msg Type3NTLMMessage * @param checkLMHash boolean * @return boolean */ protected final boolean checkNTLMv1( String md4hash, byte[] challenge, Type3NTLMMessage type3Msg, boolean checkLMHash) { if (getLogger().isDebugEnabled()) getLogger().debug(("Perform an NTLMv1 hashed password check.")); // Generate the local encrypted password using the challenge that was sent to the client byte[] p21 = new byte[21]; byte[] md4byts = m_md4Encoder.decodeHash(md4hash); System.arraycopy(md4byts, 0, p21, 0, 16); // Generate the local hash of the password using the same challenge byte[] localHash = null; try { localHash = m_encryptor.doNTLM1Encryption(p21, challenge); } catch (NoSuchAlgorithmException ex) { } // Validate the password byte[] clientHash = checkLMHash ? type3Msg.getLMHash() : type3Msg.getNTLMHash(); if (clientHash != null && localHash != null && clientHash.length == localHash.length) { int i = 0; while (i < clientHash.length && clientHash[i] == localHash[i]) { i++; } if (i == clientHash.length) { if (getLogger().isDebugEnabled()) getLogger().debug(("Hashed passwords match.")); return true; } } if (getLogger().isDebugEnabled()) getLogger().debug(("Hashed passwords do not match.")); return false; }
/** * Perform an NTLMv2 check * * @param md4hash String * @param challenge byte[] * @param type3Msg Type3NTLMMessage * @return boolean */ protected final boolean checkNTLMv2(String md4hash, byte[] challenge, Type3NTLMMessage type3Msg) { if (getLogger().isDebugEnabled()) getLogger().debug(("Perform an NTLMv2 check.")); boolean ntlmv2OK = false; boolean lmv2OK = false; try { // Generate the v2 hash using the challenge that was sent to the client byte[] v2hash = m_encryptor.doNTLM2Encryption( m_md4Encoder.decodeHash(md4hash), type3Msg.getUserName(), type3Msg.getDomain()); // Get the NTLMv2 blob sent by the client and the challenge that was sent by the server NTLMv2Blob v2blob = new NTLMv2Blob(type3Msg.getNTLMHash()); // Calculate the HMAC of the received blob and compare byte[] srvHmac = v2blob.calculateHMAC(challenge, v2hash); byte[] clientHmac = v2blob.getHMAC(); if (clientHmac != null && srvHmac != null && clientHmac.length == srvHmac.length) { int i = 0; while (i < clientHmac.length && clientHmac[i] == srvHmac[i]) { i++; } if (i == clientHmac.length) { if (getLogger().isDebugEnabled()) getLogger().debug(("HMAC matches the client, user authenticated.")); ntlmv2OK = true; } } // NTLMv2 check failed, try the LMv2 value if (ntlmv2OK == false) { byte[] lmv2 = type3Msg.getLMHash(); byte[] clChallenge = v2blob.getClientChallenge(); if (lmv2 != null && lmv2.length == 24 && clChallenge != null && clChallenge.length == 8) { // Check that the LM hash contains the client challenge as the last 8 bytes int i = 0; while (i < clChallenge.length && lmv2[i + 16] == clChallenge[i]) i++; if (i == clChallenge.length) { // Calculate the LMv2 value byte[] lmv2Hmac = v2blob.calculateLMv2HMAC(v2hash, challenge, clChallenge); // Check if the LMv2 HMAC matches i = 0; while (i < lmv2Hmac.length && lmv2[i] == lmv2Hmac[i]) i++; if (i == lmv2Hmac.length) { if (getLogger().isDebugEnabled()) getLogger().debug(("LMv2 HMAC matches the client, user authenticated.")); // return true; lmv2OK = true; } } } } } catch (Exception ex) { if (getLogger().isDebugEnabled()) getLogger().debug(ex); } // Check if either of the NTLMv2 checks passed if (ntlmv2OK || lmv2OK) return true; return false; }