You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by kw...@apache.org on 2017/03/17 10:43:16 UTC
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
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]);
- }
- }
-
}