Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java
38924 views
1
/*
2
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.sun.security.ntlm;
27
28
import static com.sun.security.ntlm.Version.*;
29
import java.io.IOException;
30
import java.io.UnsupportedEncodingException;
31
import java.security.InvalidKeyException;
32
import java.security.MessageDigest;
33
import java.security.NoSuchAlgorithmException;
34
import java.security.spec.InvalidKeySpecException;
35
import java.util.Arrays;
36
import java.util.Locale;
37
import javax.crypto.BadPaddingException;
38
import javax.crypto.Cipher;
39
import javax.crypto.IllegalBlockSizeException;
40
import javax.crypto.Mac;
41
import javax.crypto.NoSuchPaddingException;
42
import javax.crypto.SecretKey;
43
import javax.crypto.SecretKeyFactory;
44
import javax.crypto.spec.DESKeySpec;
45
import javax.crypto.spec.SecretKeySpec;
46
47
/**
48
* NTLM authentication implemented according to MS-NLMP, version 12.1
49
* @since 1.7
50
*/
51
class NTLM {
52
53
private final SecretKeyFactory fac;
54
private final Cipher cipher;
55
private final MessageDigest md4;
56
private final Mac hmac;
57
private final MessageDigest md5;
58
private static final boolean DEBUG =
59
System.getProperty("ntlm.debug") != null;
60
61
final Version v;
62
63
final boolean writeLM;
64
final boolean writeNTLM;
65
66
protected NTLM(String version) throws NTLMException {
67
if (version == null) version = "LMv2/NTLMv2";
68
switch (version) {
69
case "LM": v = NTLM; writeLM = true; writeNTLM = false; break;
70
case "NTLM": v = NTLM; writeLM = false; writeNTLM = true; break;
71
case "LM/NTLM": v = NTLM; writeLM = writeNTLM = true; break;
72
case "NTLM2": v = NTLM2; writeLM = writeNTLM = true; break;
73
case "LMv2": v = NTLMv2; writeLM = true; writeNTLM = false; break;
74
case "NTLMv2": v = NTLMv2; writeLM = false; writeNTLM = true; break;
75
case "LMv2/NTLMv2": v = NTLMv2; writeLM = writeNTLM = true; break;
76
default: throw new NTLMException(NTLMException.BAD_VERSION,
77
"Unknown version " + version);
78
}
79
try {
80
fac = SecretKeyFactory.getInstance ("DES");
81
cipher = Cipher.getInstance ("DES/ECB/NoPadding");
82
md4 = sun.security.provider.MD4.getInstance();
83
hmac = Mac.getInstance("HmacMD5");
84
md5 = MessageDigest.getInstance("MD5");
85
} catch (NoSuchPaddingException e) {
86
throw new AssertionError();
87
} catch (NoSuchAlgorithmException e) {
88
throw new AssertionError();
89
}
90
}
91
92
/**
93
* Prints out a formatted string, called in various places inside then NTLM
94
* implementation for debugging/logging purposes. When the system property
95
* "ntlm.debug" is set, <code>System.out.printf(format, args)</code> is
96
* called. This method is designed to be overridden by child classes to
97
* match their own debugging/logging mechanisms.
98
* @param format a format string
99
* @param args the arguments referenced by <code>format</code>
100
* @see java.io.PrintStream#printf(java.lang.String, java.lang.Object[])
101
*/
102
public void debug(String format, Object... args) {
103
if (DEBUG) {
104
System.out.printf(format, args);
105
}
106
}
107
108
/**
109
* Prints out the content of a byte array, called in various places inside
110
* the NTLM implementation for debugging/logging purposes. When the system
111
* property "ntlm.debug" is set, the hexdump of the array is printed into
112
* System.out. This method is designed to be overridden by child classes to
113
* match their own debugging/logging mechanisms.
114
* @param bytes the byte array to print out
115
*/
116
public void debug(byte[] bytes) {
117
if (DEBUG) {
118
try {
119
new sun.misc.HexDumpEncoder().encodeBuffer(bytes, System.out);
120
} catch (IOException ioe) {
121
// Impossible
122
}
123
}
124
}
125
126
/**
127
* Reading an NTLM packet
128
*/
129
static class Reader {
130
131
private final byte[] internal;
132
133
Reader(byte[] data) {
134
internal = data;
135
}
136
137
int readInt(int offset) throws NTLMException {
138
try {
139
return (internal[offset] & 0xff) +
140
((internal[offset+1] & 0xff) << 8) +
141
((internal[offset+2] & 0xff) << 16) +
142
((internal[offset+3] & 0xff) << 24);
143
} catch (ArrayIndexOutOfBoundsException ex) {
144
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
145
"Input message incorrect size");
146
}
147
}
148
149
int readShort(int offset) throws NTLMException {
150
try {
151
return (internal[offset] & 0xff) +
152
((internal[offset+1] & 0xff << 8));
153
} catch (ArrayIndexOutOfBoundsException ex) {
154
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
155
"Input message incorrect size");
156
}
157
}
158
159
byte[] readBytes(int offset, int len) throws NTLMException {
160
try {
161
return Arrays.copyOfRange(internal, offset, offset + len);
162
} catch (ArrayIndexOutOfBoundsException ex) {
163
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
164
"Input message incorrect size");
165
}
166
}
167
168
byte[] readSecurityBuffer(int offset) throws NTLMException {
169
int pos = readInt(offset+4);
170
if (pos == 0) return new byte[0];
171
try {
172
return Arrays.copyOfRange(
173
internal, pos, pos + readShort(offset));
174
} catch (ArrayIndexOutOfBoundsException ex) {
175
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
176
"Input message incorrect size");
177
}
178
}
179
180
String readSecurityBuffer(int offset, boolean unicode)
181
throws NTLMException {
182
byte[] raw = readSecurityBuffer(offset);
183
try {
184
return raw == null ? null : new String(
185
raw, unicode ? "UnicodeLittleUnmarked" : "ISO8859_1");
186
} catch (UnsupportedEncodingException ex) {
187
throw new NTLMException(NTLMException.PACKET_READ_ERROR,
188
"Invalid input encoding");
189
}
190
}
191
}
192
193
/**
194
* Writing an NTLM packet
195
*/
196
static class Writer {
197
198
private byte[] internal; // buffer
199
private int current; // current written content interface buffer
200
201
/**
202
* Starts writing a NTLM packet
203
* @param type NEGOTIATE || CHALLENGE || AUTHENTICATE
204
* @param len the base length, without security buffers
205
*/
206
Writer(int type, int len) {
207
assert len < 256;
208
internal = new byte[256];
209
current = len;
210
System.arraycopy (
211
new byte[] {'N','T','L','M','S','S','P',0,(byte)type},
212
0, internal, 0, 9);
213
}
214
215
void writeShort(int offset, int number) {
216
internal[offset] = (byte)(number);
217
internal[offset+1] = (byte)(number >> 8);
218
}
219
220
void writeInt(int offset, int number) {
221
internal[offset] = (byte)(number);
222
internal[offset+1] = (byte)(number >> 8);
223
internal[offset+2] = (byte)(number >> 16);
224
internal[offset+3] = (byte)(number >> 24);
225
}
226
227
void writeBytes(int offset, byte[] data) {
228
System.arraycopy(data, 0, internal, offset, data.length);
229
}
230
231
void writeSecurityBuffer(int offset, byte[] data) {
232
if (data == null) {
233
writeShort(offset+4, current);
234
} else {
235
int len = data.length;
236
if (current + len > internal.length) {
237
internal = Arrays.copyOf(internal, current + len + 256);
238
}
239
writeShort(offset, len);
240
writeShort(offset+2, len);
241
writeShort(offset+4, current);
242
System.arraycopy(data, 0, internal, current, len);
243
current += len;
244
}
245
}
246
247
void writeSecurityBuffer(int offset, String str, boolean unicode) {
248
try {
249
writeSecurityBuffer(offset, str == null ? null : str.getBytes(
250
unicode ? "UnicodeLittleUnmarked" : "ISO8859_1"));
251
} catch (UnsupportedEncodingException ex) {
252
assert false;
253
}
254
}
255
256
byte[] getBytes() {
257
return Arrays.copyOf(internal, current);
258
}
259
}
260
261
// LM/NTLM
262
263
/* Convert a 7 byte array to an 8 byte array (for a des key with parity)
264
* input starts at offset off
265
*/
266
byte[] makeDesKey (byte[] input, int off) {
267
int[] in = new int [input.length];
268
for (int i=0; i<in.length; i++ ) {
269
in[i] = input[i]<0 ? input[i]+256: input[i];
270
}
271
byte[] out = new byte[8];
272
out[0] = (byte)in[off+0];
273
out[1] = (byte)(((in[off+0] << 7) & 0xFF) | (in[off+1] >> 1));
274
out[2] = (byte)(((in[off+1] << 6) & 0xFF) | (in[off+2] >> 2));
275
out[3] = (byte)(((in[off+2] << 5) & 0xFF) | (in[off+3] >> 3));
276
out[4] = (byte)(((in[off+3] << 4) & 0xFF) | (in[off+4] >> 4));
277
out[5] = (byte)(((in[off+4] << 3) & 0xFF) | (in[off+5] >> 5));
278
out[6] = (byte)(((in[off+5] << 2) & 0xFF) | (in[off+6] >> 6));
279
out[7] = (byte)((in[off+6] << 1) & 0xFF);
280
return out;
281
}
282
283
byte[] calcLMHash (byte[] pwb) {
284
byte[] magic = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
285
byte[] pwb1 = new byte [14];
286
int len = pwb.length;
287
if (len > 14)
288
len = 14;
289
System.arraycopy (pwb, 0, pwb1, 0, len); /* Zero padded */
290
291
try {
292
DESKeySpec dks1 = new DESKeySpec (makeDesKey (pwb1, 0));
293
DESKeySpec dks2 = new DESKeySpec (makeDesKey (pwb1, 7));
294
295
SecretKey key1 = fac.generateSecret (dks1);
296
SecretKey key2 = fac.generateSecret (dks2);
297
cipher.init (Cipher.ENCRYPT_MODE, key1);
298
byte[] out1 = cipher.doFinal (magic, 0, 8);
299
cipher.init (Cipher.ENCRYPT_MODE, key2);
300
byte[] out2 = cipher.doFinal (magic, 0, 8);
301
byte[] result = new byte [21];
302
System.arraycopy (out1, 0, result, 0, 8);
303
System.arraycopy (out2, 0, result, 8, 8);
304
return result;
305
} catch (InvalidKeyException ive) {
306
// Will not happen, all key material are 8 bytes
307
assert false;
308
} catch (InvalidKeySpecException ikse) {
309
// Will not happen, we only feed DESKeySpec to DES factory
310
assert false;
311
} catch (IllegalBlockSizeException ibse) {
312
// Will not happen, we encrypt 8 bytes
313
assert false;
314
} catch (BadPaddingException bpe) {
315
// Will not happen, this is encryption
316
assert false;
317
}
318
return null; // will not happen, we returned already
319
}
320
321
byte[] calcNTHash (byte[] pw) {
322
byte[] out = md4.digest (pw);
323
byte[] result = new byte [21];
324
System.arraycopy (out, 0, result, 0, 16);
325
return result;
326
}
327
328
/* key is a 21 byte array. Split it into 3 7 byte chunks,
329
* Convert each to 8 byte DES keys, encrypt the text arg with
330
* each key and return the three results in a sequential []
331
*/
332
byte[] calcResponse (byte[] key, byte[] text) {
333
try {
334
assert key.length == 21;
335
DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0));
336
DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7));
337
DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14));
338
SecretKey key1 = fac.generateSecret(dks1);
339
SecretKey key2 = fac.generateSecret(dks2);
340
SecretKey key3 = fac.generateSecret(dks3);
341
cipher.init(Cipher.ENCRYPT_MODE, key1);
342
byte[] out1 = cipher.doFinal(text, 0, 8);
343
cipher.init(Cipher.ENCRYPT_MODE, key2);
344
byte[] out2 = cipher.doFinal(text, 0, 8);
345
cipher.init(Cipher.ENCRYPT_MODE, key3);
346
byte[] out3 = cipher.doFinal(text, 0, 8);
347
byte[] result = new byte[24];
348
System.arraycopy(out1, 0, result, 0, 8);
349
System.arraycopy(out2, 0, result, 8, 8);
350
System.arraycopy(out3, 0, result, 16, 8);
351
return result;
352
} catch (IllegalBlockSizeException ex) { // None will happen
353
assert false;
354
} catch (BadPaddingException ex) {
355
assert false;
356
} catch (InvalidKeySpecException ex) {
357
assert false;
358
} catch (InvalidKeyException ex) {
359
assert false;
360
}
361
return null;
362
}
363
364
// LMv2/NTLMv2
365
366
byte[] hmacMD5(byte[] key, byte[] text) {
367
try {
368
SecretKeySpec skey =
369
new SecretKeySpec(Arrays.copyOf(key, 16), "HmacMD5");
370
hmac.init(skey);
371
return hmac.doFinal(text);
372
} catch (InvalidKeyException ex) {
373
assert false;
374
} catch (RuntimeException e) {
375
assert false;
376
}
377
return null;
378
}
379
380
byte[] calcV2(byte[] nthash, String text, byte[] blob, byte[] challenge) {
381
try {
382
byte[] ntlmv2hash = hmacMD5(nthash,
383
text.getBytes("UnicodeLittleUnmarked"));
384
byte[] cn = new byte[blob.length+8];
385
System.arraycopy(challenge, 0, cn, 0, 8);
386
System.arraycopy(blob, 0, cn, 8, blob.length);
387
byte[] result = new byte[16+blob.length];
388
System.arraycopy(hmacMD5(ntlmv2hash, cn), 0, result, 0, 16);
389
System.arraycopy(blob, 0, result, 16, blob.length);
390
return result;
391
} catch (UnsupportedEncodingException ex) {
392
assert false;
393
}
394
return null;
395
}
396
397
// NTLM2 LM/NTLM
398
399
static byte[] ntlm2LM(byte[] nonce) {
400
return Arrays.copyOf(nonce, 24);
401
}
402
403
byte[] ntlm2NTLM(byte[] ntlmHash, byte[] nonce, byte[] challenge) {
404
byte[] b = Arrays.copyOf(challenge, 16);
405
System.arraycopy(nonce, 0, b, 8, 8);
406
byte[] sesshash = Arrays.copyOf(md5.digest(b), 8);
407
return calcResponse(ntlmHash, sesshash);
408
}
409
410
// Password in ASCII and UNICODE
411
412
static byte[] getP1(char[] password) {
413
try {
414
return new String(password).toUpperCase(
415
Locale.ENGLISH).getBytes("ISO8859_1");
416
} catch (UnsupportedEncodingException ex) {
417
return null;
418
}
419
}
420
421
static byte[] getP2(char[] password) {
422
try {
423
return new String(password).getBytes("UnicodeLittleUnmarked");
424
} catch (UnsupportedEncodingException ex) {
425
return null;
426
}
427
}
428
}
429
430