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