Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 13C2A200C49 for ; Fri, 17 Mar 2017 11:43:20 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 12491160B80; Fri, 17 Mar 2017 10:43:20 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id DE003160B6D for ; Fri, 17 Mar 2017 11:43:18 +0100 (CET) Received: (qmail 92264 invoked by uid 500); 17 Mar 2017 10:43:18 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 92255 invoked by uid 99); 17 Mar 2017 10:43:17 -0000 Received: from Unknown (HELO svn01-us-west.apache.org) (209.188.14.144) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 17 Mar 2017 10:43:17 +0000 Received: from svn01-us-west.apache.org (localhost [127.0.0.1]) by svn01-us-west.apache.org (ASF Mail Server at svn01-us-west.apache.org) with ESMTP id 5B9D43A05CD for ; Fri, 17 Mar 2017 10:43:17 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1787322 - in /httpcomponents/httpclient/branches/pull-66/httpclient/src: main/java/org/apache/http/impl/auth/NTLMEngineImpl.java test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java Date: Fri, 17 Mar 2017 10:43:16 -0000 To: commits@hc.apache.org From: kwright@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20170317104317.5B9D43A05CD@svn01-us-west.apache.org> archived-at: Fri, 17 Mar 2017 10:43:20 -0000 Author: kwright Date: Fri Mar 17 10:43:16 2017 New Revision: 1787322 URL: http://svn.apache.org/viewvc?rev=1787322&view=rev Log: Pass in random number generator and current time to CipherGen, so we can build repeatable Type3 responses Modified: httpcomponents/httpclient/branches/pull-66/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java httpcomponents/httpclient/branches/pull-66/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java Modified: httpcomponents/httpclient/branches/pull-66/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/pull-66/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java?rev=1787322&r1=1787321&r2=1787322&view=diff ============================================================================== --- httpcomponents/httpclient/branches/pull-66/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java (original) +++ httpcomponents/httpclient/branches/pull-66/httpclient/src/main/java/org/apache/http/impl/auth/NTLMEngineImpl.java Fri Mar 17 10:43:16 2017 @@ -32,6 +32,7 @@ import java.security.Key; import java.security.MessageDigest; import java.util.Arrays; import java.util.Locale; +import java.util.Random; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; @@ -300,31 +301,28 @@ final class NTLMEngineImpl implements NT } /** Calculate a challenge block */ - private static byte[] makeRandomChallenge() throws NTLMEngineException { - if (RND_GEN == null) { - throw new NTLMEngineException("Random generator not available"); - } + private static byte[] makeRandomChallenge(final Random random) throws NTLMEngineException { final byte[] rval = new byte[8]; - synchronized (RND_GEN) { - RND_GEN.nextBytes(rval); + synchronized (random) { + random.nextBytes(rval); } return rval; } /** Calculate a 16-byte secondary key */ - private static byte[] makeSecondaryKey() throws NTLMEngineException { - if (RND_GEN == null) { - throw new NTLMEngineException("Random generator not available"); - } + private static byte[] makeSecondaryKey(final Random random) throws NTLMEngineException { final byte[] rval = new byte[16]; - synchronized (RND_GEN) { - RND_GEN.nextBytes(rval); + synchronized (random) { + random.nextBytes(rval); } return rval; } protected static class CipherGen { + protected final Random random; + protected final long currentTime; + protected final String domain; protected final String user; protected final String password; @@ -356,10 +354,14 @@ final class NTLMEngineImpl implements NT protected byte[] ntlm2SessionResponseUserSessionKey = null; protected byte[] lanManagerSessionKey = null; - public CipherGen(final String domain, final String user, final String password, + public CipherGen(final Random random, final long currentTime, + final String domain, final String user, final String password, final byte[] challenge, final String target, final byte[] targetInformation, final byte[] clientChallenge, final byte[] clientChallenge2, final byte[] secondaryKey, final byte[] timestamp) { + this.random = random; + this.currentTime = currentTime; + this.domain = domain; this.target = target; this.user = user; @@ -372,16 +374,21 @@ final class NTLMEngineImpl implements NT this.timestamp = timestamp; } - public CipherGen(final String domain, final String user, final String password, - final byte[] challenge, final String target, final byte[] targetInformation) { - this(domain, user, password, challenge, target, targetInformation, null, null, null, null); + public CipherGen(final Random random, final long currentTime, + final String domain, + final String user, + final String password, + final byte[] challenge, + final String target, + final byte[] targetInformation) { + this(random, currentTime, domain, user, password, challenge, target, targetInformation, null, null, null, null); } /** Calculate and return client challenge */ public byte[] getClientChallenge() throws NTLMEngineException { if (clientChallenge == null) { - clientChallenge = makeRandomChallenge(); + clientChallenge = makeRandomChallenge(random); } return clientChallenge; } @@ -390,7 +397,7 @@ final class NTLMEngineImpl implements NT public byte[] getClientChallenge2() throws NTLMEngineException { if (clientChallenge2 == null) { - clientChallenge2 = makeRandomChallenge(); + clientChallenge2 = makeRandomChallenge(random); } return clientChallenge2; } @@ -399,7 +406,7 @@ final class NTLMEngineImpl implements NT public byte[] getSecondaryKey() throws NTLMEngineException { if (secondaryKey == null) { - secondaryKey = makeSecondaryKey(); + secondaryKey = makeSecondaryKey(random); } return secondaryKey; } @@ -461,7 +468,7 @@ final class NTLMEngineImpl implements NT /** Calculate a timestamp */ public byte[] getTimestamp() { if (timestamp == null) { - long time = System.currentTimeMillis(); + long time = this.currentTime; time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch. time *= 10000; // tenths of a microsecond. // convert to little-endian byte array. @@ -1230,11 +1237,14 @@ final class NTLMEngineImpl implements NT * * @return The response as above. */ - String getResponse() { + public String getResponse() { return new String(Base64.encodeBase64(getBytes()), StandardCharsets.US_ASCII); } public byte[] getBytes() { + if (messageContents == null) { + buildMessage(); + } final byte[] resp; if ( messageContents.length > currentOutputPosition ) { final byte[] tmp = new byte[currentOutputPosition]; @@ -1242,8 +1252,11 @@ final class NTLMEngineImpl implements NT messageContents = tmp; } return messageContents; - } + } + protected void buildMessage() { + throw new RuntimeException("Message builder not implemented for "+getClass().getName()); + } } /** Type 1 message assembly class */ @@ -1310,7 +1323,7 @@ final class NTLMEngineImpl implements NT * it */ @Override - String getResponse() { + protected void buildMessage() { int domainBytesLength = 0; if ( domainBytes != null ) { domainBytesLength = domainBytes.length; @@ -1360,8 +1373,6 @@ final class NTLMEngineImpl implements NT if (domainBytes != null) { addBytes(domainBytes); } - - return super.getResponse(); } } @@ -1478,6 +1489,21 @@ final class NTLMEngineImpl implements NT this(domain, host, user, password, nonce, type2Flags, target, targetInformation, null, null, null); } + /** More primitive constructor: don't include cert or previous messages. + */ + Type3Message(final Random random, final long currentTime, + final String domain, + final String host, + final String user, + final String password, + final byte[] nonce, + final int type2Flags, + final String target, + final byte[] targetInformation) + throws NTLMEngineException { + this(random, currentTime, domain, host, user, password, nonce, type2Flags, target, targetInformation, null, null, null); + } + /** Constructor. Pass the arguments we will need */ Type3Message(final String domain, final String host, @@ -1491,6 +1517,28 @@ final class NTLMEngineImpl implements NT final byte[] type1Message, final byte[] type2Message) throws NTLMEngineException { + this(RND_GEN, System.currentTimeMillis(), domain, host, user, password, nonce, type2Flags, target, targetInformation, peerServerCertificate, type1Message, type2Message); + } + + /** Constructor. Pass the arguments we will need */ + Type3Message(final Random random, final long currentTime, + final String domain, + final String host, + final String user, + final String password, + final byte[] nonce, + final int type2Flags, + final String target, + final byte[] targetInformation, + final X509Certificate peerServerCertificate, + final byte[] type1Message, + final byte[] type2Message) + throws NTLMEngineException { + + if (random == null) { + throw new NTLMEngineException("Random generator not available"); + } + // Save the flags this.type2Flags = type2Flags; this.type1Message = type1Message; @@ -1511,7 +1559,8 @@ final class NTLMEngineImpl implements NT } // Create a cipher generator class. Use domain BEFORE it gets modified! - final CipherGen gen = new CipherGen(unqualifiedDomain, + final CipherGen gen = new CipherGen(random, currentTime, + unqualifiedDomain, user, password, nonce, @@ -1599,7 +1648,7 @@ final class NTLMEngineImpl implements NT /** Assemble the response */ @Override - String getResponse() { + protected void buildMessage() { final int ntRespLen = ntResp.length; final int lmRespLen = lmResp.length; @@ -1733,7 +1782,6 @@ final class NTLMEngineImpl implements NT final byte[] mic = hmacMD5.getOutput(); System.arraycopy( mic, 0, messageContents, micPosition, mic.length ); } - return super.getResponse(); } /** Modified: httpcomponents/httpclient/branches/pull-66/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/branches/pull-66/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java?rev=1787322&r1=1787321&r2=1787322&view=diff ============================================================================== --- httpcomponents/httpclient/branches/pull-66/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java (original) +++ httpcomponents/httpclient/branches/pull-66/httpclient/src/test/java/org/apache/http/impl/auth/TestNTLMEngineImpl.java Fri Mar 17 10:43:16 2017 @@ -29,6 +29,7 @@ package org.apache.http.impl.auth; import org.apache.http.Consts; import org.junit.Assert; import org.junit.Test; +import java.util.Random; public class TestNTLMEngineImpl { @@ -92,6 +93,8 @@ public class TestNTLMEngineImpl { @Test public void testLMResponse() throws Exception { final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen( + new Random(1234), + 1234L, null, null, "SecREt01", @@ -110,6 +113,8 @@ public class TestNTLMEngineImpl { @Test public void testNTLMResponse() throws Exception { final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen( + new Random(1234), + 1234L, null, null, "SecREt01", @@ -128,6 +133,8 @@ public class TestNTLMEngineImpl { @Test public void testLMv2Response() throws Exception { final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen( + new Random(1234), + 1234L, "DOMAIN", "user", "SecREt01", @@ -146,6 +153,8 @@ public class TestNTLMEngineImpl { @Test public void testNTLMv2Response() throws Exception { final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen( + new Random(1234), + 1234L, "DOMAIN", "user", "SecREt01", @@ -166,6 +175,8 @@ public class TestNTLMEngineImpl { @Test public void testLM2SessionResponse() throws Exception { final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen( + new Random(1234), + 1234L, "DOMAIN", "user", "SecREt01", @@ -184,6 +195,8 @@ public class TestNTLMEngineImpl { @Test public void testNTLM2SessionResponse() throws Exception { final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen( + new Random(1234), + 1234L, "DOMAIN", "user", "SecREt01", @@ -202,6 +215,8 @@ public class TestNTLMEngineImpl { @Test public void testNTLMUserSessionKey() throws Exception { final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen( + new Random(1234), + 1234L, "DOMAIN", "user", "SecREt01", @@ -219,35 +234,32 @@ public class TestNTLMEngineImpl { @Test public void testType1Message() throws Exception { - final byte[] bytes = new NTLMEngineImpl().getType1Message("myhost", "mydomain").getBytes(); - final byte[] bytes2 = toBytes("546C524D54564E545541414241414141415949496F6741414141416F414141414141414141436741414141464153674B4141414144773D3D"); + final byte[] bytes = new NTLMEngineImpl.Type1Message("myhost", "mydomain").getBytes(); + final byte[] bytes2 = toBytes("4E544C4D5353500001000000018208A2000000002800000000000000280000000501280A0000000F6D00790064006F006D00610069006E004D00590048004F0053005400"); checkArraysMatch(bytes2, bytes); } @Test public void testType3Message() throws Exception { - final byte[] bytes = new NTLMEngineImpl().getType3Message("me", "mypassword", "myhost", "mydomain", + final byte[] bytes = new NTLMEngineImpl.Type3Message( + new Random(1234), + 1234L, + "me", "mypassword", "myhost", "mydomain", toBytes("0001020304050607"), 0xffffffff, null,null).getBytes(); - // Verify the parts that have no random or timestamp component - checkArraysMatch(toBytes("546C524D54564E545541414441414141474141594145674141414159414267415941414141424141454142344141414142414145414967414141414D414177416A4141414142414145414359414141412F2F2F2F2F7755424B416F4141414150"), - 0, bytes); - checkArraysMatch(toBytes("414141414141414141414141414141414141414141"), - 107, bytes); - checkArraysMatch(toBytes("5451425A414551415477424E414545415351424F414730415A51427441486B416141427641484D416441"), - 160, bytes); - final byte[] bytes2 = new NTLMEngineImpl().getType3Message("me", "mypassword", "myhost", "mydomain", + checkArraysMatch(toBytes("4E544C4D53535000030000001800180048000000180018006000000004000400780000000C000C007C0000001400140088000000100010009C000000FFFFFFFF0501280A0000000FA86886A5D297814200000000000000000000000000000000EEC7568E00798491244959B9C942F4F367C5CBABEEF546F74D0045006D00790068006F00730074006D007900700061007300730077006F007200640094DDAB1EBB82C9A1AB914CAE6F199644"), + bytes); + final byte[] bytes2 = new NTLMEngineImpl.Type3Message( + new Random(1234), + 1234L, + "me", "mypassword", "myhost", "mydomain", toBytes("0001020304050607"), 0xffffffff, "mytarget", toBytes("02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000")).getBytes(); - checkArraysMatch(toBytes("546C524D54564E545541414441414141474141594145674141414353414A49415941414141424141454144794141414142414145414149424141414D41417741426745414142414145414153415141412F2F2F2F2F7755424B416F4141414150"), - 0, bytes2); - checkArraysMatch(toBytes("45424141414141414141"), - 150, bytes2); - checkArraysMatch(toBytes("4141414141434141774152414250414530415151424A414534414151414D41464D41525142534146594152514253414151414641426B414738416251426841476B416267417541474D416277427441414D414967427A414755416367423241475541636741754147514162774274414745416151427541433441597742764147304141414141414141414141424E41466B4152414250414530415151424A414534416251426C414730416551426F414738416377423041"), - 182, bytes2); + checkArraysMatch(toBytes("4E544C4D53535000030000001800180048000000920092006000000004000400F20000000C000C00F600000014001400020100001000100016010000FFFFFFFF0501280A0000000F3695F1EA7B164788A437892FA7504320DA2D8CF378EBC83CE856A8FB985BF7783545828A91A13AE8010100000000000020CBFAD5DEB19D01A86886A5D29781420000000002000C0044004F004D00410049004E0001000C005300450052005600450052000400140064006F006D00610069006E002E0063006F006D00030022007300650072007600650072002E0064006F006D00610069006E002E0063006F006D0000000000000000004D0045006D00790068006F00730074006D007900700061007300730077006F0072006400BB1AAD36F11631CC7CBC8800CEEE1C99"), + bytes2); } @Test @@ -266,14 +278,4 @@ public class TestNTLMEngineImpl { } } - /* Byte array check helper */ - static void checkArraysMatch(final byte[] a1, - final int a2StartIndex, final byte[] a2) - throws Exception { - Assert.assertTrue(a2.length - a2StartIndex >= a1.length); - for (int i = 0; i < a1.length; i++) { - Assert.assertEquals(a1[i],a2[i + a2StartIndex]); - } - } - }