private void ntlmChallenge(String authenticateHeader, HttpHeaders requestHeaders, Realm realm, NettyResponseFuture<?> future) { if (authenticateHeader.equals("NTLM")) { // server replied bare NTLM => we didn't preemptively sent Type1Msg String challengeHeader = NtlmEngine.INSTANCE.generateType1Msg(); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) requestHeaders.set(AUTHORIZATION, "NTLM " + challengeHeader); future.setInAuth(false); } else { String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim(); String challengeHeader = NtlmEngine.INSTANCE.generateType3Msg(realm.getPrincipal(), realm.getPassword(), realm.getNtlmDomain(), realm.getNtlmHost(), serverChallenge); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) requestHeaders.set(AUTHORIZATION, "NTLM " + challengeHeader); } }
byte[] getOutput() { // Feed pad/length data into engine. This must round out the input // to a multiple of 512 bits. final int bufferIndex = (int) (count & 63L); final int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex); final byte[] postBytes = new byte[padLen + 8]; // Leading 0x80, specified amount of zero padding, then length in // bits. postBytes[0] = (byte) 0x80; // Fill out the last 8 bytes with the length for (int i = 0; i < 8; i++) { postBytes[padLen + i] = (byte) ((count * 8) >>> (8 * i)); } // Update the engine update(postBytes); // Calculate final result final byte[] result = new byte[16]; writeULong(result, A, 0); writeULong(result, B, 4); writeULong(result, C, 8); writeULong(result, D, 12); return result; }
protected void round1(final int[] d) { A = rotintlft((A + F(B, C, D) + d[0]), 3); D = rotintlft((D + F(A, B, C) + d[1]), 7); C = rotintlft((C + F(D, A, B) + d[2]), 11); B = rotintlft((B + F(C, D, A) + d[3]), 19); A = rotintlft((A + F(B, C, D) + d[4]), 3); D = rotintlft((D + F(A, B, C) + d[5]), 7); C = rotintlft((C + F(D, A, B) + d[6]), 11); B = rotintlft((B + F(C, D, A) + d[7]), 19); A = rotintlft((A + F(B, C, D) + d[8]), 3); D = rotintlft((D + F(A, B, C) + d[9]), 7); C = rotintlft((C + F(D, A, B) + d[10]), 11); B = rotintlft((B + F(C, D, A) + d[11]), 19); A = rotintlft((A + F(B, C, D) + d[12]), 3); D = rotintlft((D + F(A, B, C) + d[13]), 7); C = rotintlft((C + F(D, A, B) + d[14]), 11); B = rotintlft((B + F(C, D, A) + d[15]), 19); }
protected void round2(final int[] d) { A = rotintlft((A + G(B, C, D) + d[0] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[4] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[8] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[12] + 0x5a827999), 13); A = rotintlft((A + G(B, C, D) + d[1] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[5] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[9] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[13] + 0x5a827999), 13); A = rotintlft((A + G(B, C, D) + d[2] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[6] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[10] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[14] + 0x5a827999), 13); A = rotintlft((A + G(B, C, D) + d[3] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[7] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[11] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[15] + 0x5a827999), 13); }
protected void round3(final int[] d) { A = rotintlft((A + H(B, C, D) + d[0] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[8] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[4] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[12] + 0x6ed9eba1), 15); A = rotintlft((A + H(B, C, D) + d[2] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[10] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[6] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[14] + 0x6ed9eba1), 15); A = rotintlft((A + H(B, C, D) + d[1] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[9] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[5] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[13] + 0x6ed9eba1), 15); A = rotintlft((A + H(B, C, D) + d[3] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[11] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[7] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[15] + 0x6ed9eba1), 15); } }
public static String perConnectionProxyAuthorizationHeader(Request request, Realm proxyRealm) { String proxyAuthorization = null; if (proxyRealm != null && proxyRealm.isUsePreemptiveAuth()) { switch (proxyRealm.getScheme()) { case NTLM: case KERBEROS: case SPNEGO: List<String> auth = request.getHeaders().getAll(PROXY_AUTHORIZATION); if (getHeaderWithPrefix(auth, "NTLM") == null) { String msg = NtlmEngine.INSTANCE.generateType1Msg(); proxyAuthorization = "NTLM " + msg; } break; default: } } return proxyAuthorization; }
@Test(expectedExceptions = NtlmEngineException.class) public void testGenerateType3MsgThrowsExceptionWhenChallengeDoesNotFollowCorrectFormat() { NtlmEngine engine = new NtlmEngine(); engine.generateType3Msg("username", "password", "localhost", "workstation", Base64.getEncoder().encodeToString("challenge".getBytes())); fail("An NtlmEngineException must have occurred as challenge format is not correct"); }
private void addType3NTLMAuthorizationHeader(String authenticateHeader, FluentCaseInsensitiveStringsMap headers, Realm realm, boolean proxyInd) throws NtlmEngineException { headers.remove(authorizationHeaderName(proxyInd)); if (authenticateHeader.startsWith("NTLM ")) { String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim(); String challengeHeader = NtlmEngine.INSTANCE.generateType3Msg(realm.getPrincipal(), realm.getPassword(), realm.getNtlmDomain(), realm.getNtlmHost(), serverChallenge); addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); } }
@Test public void testGenerateType1Msg() { NtlmEngine engine = new NtlmEngine(); String message = engine.generateType1Msg(); assertEquals(message, "TlRMTVNTUAABAAAAAYIIogAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==", "Incorrect type1 message generated"); }
final byte[] keyBytes = new byte[21]; System.arraycopy(hash, 0, keyBytes, 0, 16); final Key lowKey = createDESKey(keyBytes, 0); final Key middleKey = createDESKey(keyBytes, 7); final Key highKey = createDESKey(keyBytes, 14); final Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); des.init(Cipher.ENCRYPT_MODE, lowKey);
public String generateType3Msg(final String username, final String password, final String domain, final String workstation, final String challenge) throws NtlmEngineException { final Type2Message t2m = new Type2Message(challenge); return getType3Message(username, password, workstation, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(), t2m.getTargetInfo()); }
switch (realm.getScheme()) { case NTLM: String msg = NtlmEngine.INSTANCE.generateType1Msg(); authorizationHeader = "NTLM " + msg; break;
@Test(expectedExceptions = NtlmEngineException.class) public void testGenerateType3MsgThrowsExceptionWhenChallengeTooShort() { NtlmEngine engine = new NtlmEngine(); engine.generateType3Msg("username", "password", "localhost", "workstation", Base64.getEncoder().encodeToString("a".getBytes())); fail("An NtlmEngineException must have occurred as challenge length is too short"); }
private void addType3NTLMAuthorizationHeader(String authenticateHeader, FluentCaseInsensitiveStringsMap headers, Realm realm, boolean proxyInd) { headers.remove(authorizationHeaderName(proxyInd)); if (authenticateHeader.startsWith("NTLM ")) { String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim(); String challengeHeader = NtlmEngine.INSTANCE.generateType3Msg(realm.getPrincipal(), realm.getPassword(), realm.getNtlmDomain(), realm.getNtlmHost(), serverChallenge); addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); } }
protected void round2(final int[] d) { A = rotintlft((A + G(B, C, D) + d[0] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[4] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[8] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[12] + 0x5a827999), 13); A = rotintlft((A + G(B, C, D) + d[1] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[5] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[9] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[13] + 0x5a827999), 13); A = rotintlft((A + G(B, C, D) + d[2] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[6] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[10] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[14] + 0x5a827999), 13); A = rotintlft((A + G(B, C, D) + d[3] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[7] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[11] + 0x5a827999), 9); B = rotintlft((B + G(C, D, A) + d[15] + 0x5a827999), 13); }
protected void round3(final int[] d) { A = rotintlft((A + H(B, C, D) + d[0] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[8] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[4] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[12] + 0x6ed9eba1), 15); A = rotintlft((A + H(B, C, D) + d[2] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[10] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[6] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[14] + 0x6ed9eba1), 15); A = rotintlft((A + H(B, C, D) + d[1] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[9] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[5] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[13] + 0x6ed9eba1), 15); A = rotintlft((A + H(B, C, D) + d[3] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[11] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[7] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[15] + 0x6ed9eba1), 15); } }
/** * Creates the LM Hash of the user's password. * * @param password * The password. * * @return The LM Hash of the given password, used in the calculation of the * LM Response. */ private static byte[] lmHash(final String password) throws NtlmEngineException { try { final byte[] oemPassword = password.toUpperCase(Locale.ROOT).getBytes(US_ASCII); final int length = Math.min(oemPassword.length, 14); final byte[] keyBytes = new byte[14]; System.arraycopy(oemPassword, 0, keyBytes, 0, length); final Key lowKey = createDESKey(keyBytes, 0); final Key highKey = createDESKey(keyBytes, 7); final Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); des.init(Cipher.ENCRYPT_MODE, lowKey); final byte[] lowHash = des.doFinal(MAGIC_CONSTANT); des.init(Cipher.ENCRYPT_MODE, highKey); final byte[] highHash = des.doFinal(MAGIC_CONSTANT); final byte[] lmHash = new byte[16]; System.arraycopy(lowHash, 0, lmHash, 0, 8); System.arraycopy(highHash, 0, lmHash, 8, 8); return lmHash; } catch (final Exception e) { throw new NtlmEngineException(e.getMessage(), e); } }
public String generateType3Msg(final String username, final String password, final String domain, final String workstation, final String challenge) throws NtlmEngineException { final Type2Message t2m = new Type2Message(challenge); return getType3Message(username, password, workstation, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(), t2m.getTargetInfo()); }
public static String perConnectionProxyAuthorizationHeader(Request request, ProxyServer proxyServer, boolean connect) { String proxyAuthorization = null; if (connect) { List<String> auth = getProxyAuthorizationHeader(request); String ntlmHeader = getNTLM(auth); if (ntlmHeader != null) { proxyAuthorization = ntlmHeader; } } else if (proxyServer != null && proxyServer.getPrincipal() != null && proxyServer.getScheme().isLikeNtlm()) { List<String> auth = getProxyAuthorizationHeader(request); if (getNTLM(auth) == null) { String msg = NtlmEngine.INSTANCE.generateType1Msg(); proxyAuthorization = "NTLM " + msg; } } return proxyAuthorization; }
private void ntlmProxyChallenge(String authenticateHeader, HttpHeaders requestHeaders, Realm proxyRealm, NettyResponseFuture<?> future) { if (authenticateHeader.equals("NTLM")) { // server replied bare NTLM => we didn't preemptively sent Type1Msg String challengeHeader = NtlmEngine.INSTANCE.generateType1Msg(); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) requestHeaders.set(PROXY_AUTHORIZATION, "NTLM " + challengeHeader); future.setInProxyAuth(false); } else { String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim(); String challengeHeader = NtlmEngine.INSTANCE.generateType3Msg(proxyRealm.getPrincipal(), proxyRealm.getPassword(), proxyRealm.getNtlmDomain(), proxyRealm.getNtlmHost(), serverChallenge); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) requestHeaders.set(PROXY_AUTHORIZATION, "NTLM " + challengeHeader); } } }