1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.impl.auth;
28
29 import org.apache.http.Consts;
30 import org.junit.Assert;
31 import org.junit.Test;
32 import java.util.Random;
33
34 import java.io.ByteArrayInputStream;
35 import java.security.cert.CertificateFactory;
36 import java.security.cert.Certificate;
37
38 public class TestNTLMEngineImpl {
39
40 @Test
41 public void testMD4() throws Exception {
42 checkMD4("", "31d6cfe0d16ae931b73c59d7e0c089c0");
43 checkMD4("a", "bde52cb31de33e46245e05fbdbd6fb24");
44 checkMD4("abc", "a448017aaf21d8525fc10ae87aa6729d");
45 checkMD4("message digest", "d9130a8164549fe818874806e1c7014b");
46 checkMD4("abcdefghijklmnopqrstuvwxyz", "d79e1c308aa5bbcdeea8ed63df412da9");
47 checkMD4("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
48 "043f8582f241db351ce627e153e7f0e4");
49 checkMD4(
50 "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
51 "e33b4ddc9c38f2199c3e7b164fcc0536");
52 }
53
54
55 static byte toNibble(final char c) {
56 if (c >= 'a' && c <= 'f') {
57 return (byte) (c - 'a' + 0x0a);
58 }
59 if (c >= 'A' && c <= 'F') {
60 return (byte) (c - 'A' + 0x0a);
61 }
62 return (byte) (c - '0');
63 }
64
65
66 static byte[] toBytes(final String hex) {
67 final byte[] rval = new byte[hex.length() / 2];
68 int i = 0;
69 while (i < rval.length) {
70 rval[i] = (byte) ((toNibble(hex.charAt(i * 2)) << 4) | (toNibble(hex
71 .charAt(i * 2 + 1))));
72 i++;
73 }
74 return rval;
75 }
76
77
78 static void checkMD4(final String input, final String hexOutput) throws Exception {
79 final NTLMEngineImpl.MD4 md4;
80 md4 = new NTLMEngineImpl.MD4();
81 md4.update(input.getBytes(Consts.ASCII));
82 final byte[] answer = md4.getOutput();
83 final byte[] correctAnswer = toBytes(hexOutput);
84 if (answer.length != correctAnswer.length) {
85 throw new Exception("Answer length disagrees for MD4('" + input + "')");
86 }
87 int i = 0;
88 while (i < answer.length) {
89 if (answer[i] != correctAnswer[i]) {
90 throw new Exception("Answer value for MD4('" + input + "') disagrees at position "
91 + Integer.toString(i));
92 }
93 i++;
94 }
95 }
96
97 @Test
98 public void testLMResponse() throws Exception {
99 final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen(
100 new Random(1234),
101 1234L,
102 null,
103 null,
104 "SecREt01",
105 toBytes("0123456789abcdef"),
106 null,
107 null,
108 null,
109 null,
110 null,
111 null);
112
113 checkArraysMatch(toBytes("c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56"),
114 gen.getLMResponse());
115 }
116
117 @Test
118 public void testNTLMResponse() throws Exception {
119 final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen(
120 new Random(1234),
121 1234L,
122 null,
123 null,
124 "SecREt01",
125 toBytes("0123456789abcdef"),
126 null,
127 null,
128 null,
129 null,
130 null,
131 null);
132
133 checkArraysMatch(toBytes("25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6"),
134 gen.getNTLMResponse());
135 }
136
137 @Test
138 public void testLMv2Response() throws Exception {
139 final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen(
140 new Random(1234),
141 1234L,
142 "DOMAIN",
143 "user",
144 "SecREt01",
145 toBytes("0123456789abcdef"),
146 "DOMAIN",
147 null,
148 toBytes("ffffff0011223344"),
149 toBytes("ffffff0011223344"),
150 null,
151 null);
152
153 checkArraysMatch(toBytes("d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344"),
154 gen.getLMv2Response());
155 }
156
157 @Test
158 public void testNTLMv2Response() throws Exception {
159 final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen(
160 new Random(1234),
161 1234L,
162 "DOMAIN",
163 "user",
164 "SecREt01",
165 toBytes("0123456789abcdef"),
166 "DOMAIN",
167 toBytes("02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000"),
168 toBytes("ffffff0011223344"),
169 toBytes("ffffff0011223344"),
170 null,
171 toBytes("0090d336b734c301"));
172
173 checkArraysMatch(toBytes("01010000000000000090d336b734c301ffffff00112233440000000002000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d000000000000000000"),
174 gen.getNTLMv2Blob());
175 checkArraysMatch(toBytes("cbabbca713eb795d04c97abc01ee498301010000000000000090d336b734c301ffffff00112233440000000002000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d000000000000000000"),
176 gen.getNTLMv2Response());
177 }
178
179 @Test
180 public void testLM2SessionResponse() throws Exception {
181 final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen(
182 new Random(1234),
183 1234L,
184 "DOMAIN",
185 "user",
186 "SecREt01",
187 toBytes("0123456789abcdef"),
188 "DOMAIN",
189 toBytes("02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000"),
190 toBytes("ffffff0011223344"),
191 toBytes("ffffff0011223344"),
192 null,
193 toBytes("0090d336b734c301"));
194
195 checkArraysMatch(toBytes("ffffff001122334400000000000000000000000000000000"),
196 gen.getLM2SessionResponse());
197 }
198
199 @Test
200 public void testNTLM2SessionResponse() throws Exception {
201 final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen(
202 new Random(1234),
203 1234L,
204 "DOMAIN",
205 "user",
206 "SecREt01",
207 toBytes("0123456789abcdef"),
208 "DOMAIN",
209 toBytes("02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000"),
210 toBytes("ffffff0011223344"),
211 toBytes("ffffff0011223344"),
212 null,
213 toBytes("0090d336b734c301"));
214
215 checkArraysMatch(toBytes("10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455"),
216 gen.getNTLM2SessionResponse());
217 }
218
219 @Test
220 public void testNTLMUserSessionKey() throws Exception {
221 final NTLMEngineImpl.CipherGen gen = new NTLMEngineImpl.CipherGen(
222 new Random(1234),
223 1234L,
224 "DOMAIN",
225 "user",
226 "SecREt01",
227 toBytes("0123456789abcdef"),
228 "DOMAIN",
229 toBytes("02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000"),
230 toBytes("ffffff0011223344"),
231 toBytes("ffffff0011223344"),
232 null,
233 toBytes("0090d336b734c301"));
234
235 checkArraysMatch(toBytes("3f373ea8e4af954f14faa506f8eebdc4"),
236 gen.getNTLMUserSessionKey());
237 }
238
239 @Test
240 public void testType1Message() throws Exception {
241 final byte[] bytes = new NTLMEngineImpl.Type1Message("myhost", "mydomain").getBytes();
242 final byte[] bytes2 = toBytes("4E544C4D5353500001000000018208A20C000C003800000010001000280000000501280A0000000F6D00790064006F006D00610069006E004D00590048004F0053005400");
243 checkArraysMatch(bytes2, bytes);
244 }
245
246 @Test
247 public void testType3Message() throws Exception {
248 final byte[] bytes = new NTLMEngineImpl.Type3Message(
249 new Random(1234),
250 1234L,
251 "me", "mypassword", "myhost", "mydomain",
252 toBytes("0001020304050607"),
253 0xffffffff,
254 null,null).getBytes();
255 checkArraysMatch(toBytes("4E544C4D53535000030000001800180048000000180018006000000004000400780000000C000C007C0000001400140088000000100010009C000000FFFFFFFF0501280A0000000FA86886A5D297814200000000000000000000000000000000EEC7568E00798491244959B9C942F4F367C5CBABEEF546F74D0045006D00790068006F00730074006D007900700061007300730077006F007200640094DDAB1EBB82C9A1AB914CAE6F199644"),
256 bytes);
257 final byte[] bytes2 = new NTLMEngineImpl.Type3Message(
258 new Random(1234),
259 1234L,
260 "me", "mypassword", "myhost", "mydomain",
261 toBytes("0001020304050607"),
262 0xffffffff,
263 "mytarget",
264 toBytes("02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000")).getBytes();
265 checkArraysMatch(toBytes("4E544C4D53535000030000001800180048000000920092006000000004000400F20000000C000C00F600000014001400020100001000100016010000FFFFFFFF0501280A0000000F3695F1EA7B164788A437892FA7504320DA2D8CF378EBC83CE856A8FB985BF7783545828A91A13AE8010100000000000020CBFAD5DEB19D01A86886A5D29781420000000002000C0044004F004D00410049004E0001000C005300450052005600450052000400140064006F006D00610069006E002E0063006F006D00030022007300650072007600650072002E0064006F006D00610069006E002E0063006F006D0000000000000000004D0045006D00790068006F00730074006D007900700061007300730077006F0072006400BB1AAD36F11631CC7CBC8800CEEE1C99"),
266 bytes2);
267 }
268
269 private static String cannedCert =
270 "-----BEGIN CERTIFICATE-----\n"+
271 "MIIDIDCCAgigAwIBAgIEOqKaWTANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEQMA4GA1UEBxMH\n"+
272 "TXkgQ2l0eTEYMBYGA1UEChMPTXkgT3JnYW5pemF0aW9uMRcwFQYDVQQDEw5NeSBBcHBsaWNhdGlvbjAe\n"+
273 "Fw0xNzAzMTcxNDAyMzRaFw0yNzAzMTUxNDAyMzRaMFIxCzAJBgNVBAYTAlVTMRAwDgYDVQQHEwdNeSBD\n"+
274 "aXR5MRgwFgYDVQQKEw9NeSBPcmdhbml6YXRpb24xFzAVBgNVBAMTDk15IEFwcGxpY2F0aW9uMIIBIjAN\n"+
275 "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArc+mbViBaHeRSt82KrJ5IF+62b/Qob95Lca4DJIislTY\n"+
276 "vLPIo0R1faBV8BkEeUQwo01srkf3RaGLCHNZnFal4KEzbtiUy6W+n08G5E9w9YG+WSwW2dmjvEI7k2a2\n"+
277 "xqlaM4NdMKL4ONPXcxfZsMDqxDgpdkaNPKpZ10NDq6rmBTkQw/OSG0z1KLtwLkF1ZQ/3mXdjVzvP83V2\n"+
278 "g17AqBazb0Z1YHsVKmkGjPqnq3niJH/6Oke4N+5k/1cE5lSJcQNGP0nqeGdJfvqQZ+gk6gH/sOngZL9X\n"+
279 "hPVkpseAwHa+xuPneDSjibLgLmMt3XGDK6jGfjdp5FWqFvAD5E3LHbW9gwIDAQABMA0GCSqGSIb3DQEB\n"+
280 "CwUAA4IBAQCpUXUHhl5LyMSO5Q0OktEc9AaFjZtVfknpPde6Zeh35Pqd2354ErvJSBWgzFAphda0oh2s\n"+
281 "OIAFkM6LJQEnVDTbXDXN+YY8e3gb9ryfh85hkhC0XI9qp17WPSkmw8XgDfvRd6YQgKm1AnLxjOCwG2jg\n"+
282 "i09iZBIWkW3ZeRAMvWPHHjvq44iZB5ZrEl0apgumS6MxpUzKOr5Pcq0jxJDw2UCj5YloFMNl+UINv2vV\n"+
283 "aL/DR6ivc61dOfN1E/VNBGkkCk/AogNyucGiFMCq9hd25Y9EbkBBqObYTH1XMX+ufsJh+6hG7KDQ1e/F\n"+
284 "nRrlhKwM2uRe+aSH0D6/erjDBT7tXvwn\n"+
285 "-----END CERTIFICATE-----";
286
287 @Test
288 public void testType3MessageWithCert() throws Exception {
289 final ByteArrayInputStream fis = new ByteArrayInputStream(cannedCert.getBytes(Consts.ASCII));
290
291 final CertificateFactory cf = CertificateFactory.getInstance("X.509");
292
293 final Certificate cert = cf.generateCertificate(fis);
294
295 final byte[] bytes = new NTLMEngineImpl.Type3Message(
296 new Random(1234),
297 1234L,
298 "me", "mypassword", "myhost", "mydomain",
299 toBytes("0001020304050607"),
300 0xffffffff,
301 "mytarget",
302 toBytes("02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000"),
303 cert,
304 toBytes("4E544C4D5353500001000000018208A20C000C003800000010001000280000000501280A0000000F6D00790064006F006D00610069006E004D00590048004F0053005400"),
305 toBytes("4E544C4D5353500001000000018208A20C000C003800000010001000280000000501280A0000000F6D00790064006F006D00610069006E004D00590048004F0053005400FFFEFDFCFBFA")).getBytes();
306
307 checkArraysMatch(toBytes("4E544C4D53535000030000001800180058000000AE00AE0070000000040004001E0100000C000C0022010000140014002E0100001000100042010000FFFFFFFF0501280A0000000FEEFCCE4187D6CDF1F91C686C4E571D943695F1EA7B164788A437892FA7504320DA2D8CF378EBC83C59D7A3B2951929079B66621D7CF4326B010100000000000020CBFAD5DEB19D01A86886A5D29781420000000002000C0044004F004D00410049004E0001000C005300450052005600450052000400140064006F006D00610069006E002E0063006F006D00030022007300650072007600650072002E0064006F006D00610069006E002E0063006F006D0006000400020000000A00100038EDC0B7EF8D8FE9E1E6A83F6DFEB8FF00000000000000004D0045006D00790068006F00730074006D007900700061007300730077006F0072006400BB1AAD36F11631CC7CBC8800CEEE1C99"),
308 bytes);
309 }
310
311 @Test
312 public void testRC4() throws Exception {
313 checkArraysMatch(toBytes("e37f97f2544f4d7e"),
314 NTLMEngineImpl.RC4(toBytes("0a003602317a759a"),
315 toBytes("2785f595293f3e2813439d73a223810d")));
316 }
317
318
319 static void checkArraysMatch(final byte[] a1, final byte[] a2)
320 throws Exception {
321 Assert.assertEquals(a1.length,a2.length);
322 for (int i = 0; i < a1.length; i++) {
323 Assert.assertEquals(a1[i],a2[i]);
324 }
325 }
326
327 }