27
27
// fork from Apache HttpComponents
28
28
package org .asynchttpclient .ntlm ;
29
29
30
+ import org .jetbrains .annotations .Contract ;
31
+ import org .jetbrains .annotations .Nullable ;
32
+
30
33
import javax .crypto .Cipher ;
31
34
import javax .crypto .spec .SecretKeySpec ;
32
35
import java .io .UnsupportedEncodingException ;
33
36
import java .nio .charset .Charset ;
34
- import java .nio .charset .UnsupportedCharsetException ;
37
+ import java .nio .charset .StandardCharsets ;
35
38
import java .security .Key ;
36
39
import java .security .MessageDigest ;
37
40
import java .security .SecureRandom ;
@@ -55,17 +58,7 @@ public final class NtlmEngine {
55
58
/**
56
59
* Unicode encoding
57
60
*/
58
- private static final Charset UNICODE_LITTLE_UNMARKED ;
59
-
60
- static {
61
- Charset c ;
62
- try {
63
- c = Charset .forName ("UnicodeLittleUnmarked" );
64
- } catch (UnsupportedCharsetException e ) {
65
- c = null ;
66
- }
67
- UNICODE_LITTLE_UNMARKED = c ;
68
- }
61
+ private static final Charset UNICODE_LITTLE_UNMARKED = StandardCharsets .UTF_16LE ;
69
62
70
63
private static final byte [] MAGIC_CONSTANT = "KGS!@#$%" .getBytes (US_ASCII );
71
64
@@ -92,7 +85,7 @@ public final class NtlmEngine {
92
85
/**
93
86
* Secure random generator
94
87
*/
95
- private static final SecureRandom RND_GEN ;
88
+ private static final @ Nullable SecureRandom RND_GEN ;
96
89
97
90
static {
98
91
SecureRandom rnd = null ;
@@ -132,17 +125,14 @@ public final class NtlmEngine {
132
125
* @throws NtlmEngineException If {@encrypt(byte[],byte[])} fails.
133
126
*/
134
127
private static String getType3Message (final String user , final String password , final String host , final String domain , final byte [] nonce ,
135
- final int type2Flags , final String target , final byte [] targetInformation ) {
128
+ final int type2Flags , final @ Nullable String target , final byte @ Nullable [] targetInformation ) {
136
129
return new Type3Message (domain , host , user , password , nonce , type2Flags , target , targetInformation ).getResponse ();
137
130
}
138
131
139
132
/**
140
133
* Strip dot suffix from a name
141
134
*/
142
135
private static String stripDotSuffix (final String value ) {
143
- if (value == null ) {
144
- return null ;
145
- }
146
136
final int index = value .indexOf ('.' );
147
137
if (index != -1 ) {
148
138
return value .substring (0 , index );
@@ -153,14 +143,16 @@ private static String stripDotSuffix(final String value) {
153
143
/**
154
144
* Convert host to standard form
155
145
*/
156
- private static String convertHost (final String host ) {
146
+ @ Contract (value = "!null -> !null" , pure = true )
147
+ private static @ Nullable String convertHost (final String host ) {
157
148
return host != null ? stripDotSuffix (host ).toUpperCase () : null ;
158
149
}
159
150
160
151
/**
161
152
* Convert domain to standard form
162
153
*/
163
- private static String convertDomain (final String domain ) {
154
+ @ Contract (value = "!null -> !null" , pure = true )
155
+ private static @ Nullable String convertDomain (final String domain ) {
164
156
return domain != null ? stripDotSuffix (domain ).toUpperCase () : null ;
165
157
}
166
158
@@ -223,36 +215,36 @@ private static class CipherGen {
223
215
protected final String user ;
224
216
protected final String password ;
225
217
protected final byte [] challenge ;
226
- protected final String target ;
227
- protected final byte [] targetInformation ;
218
+ protected final @ Nullable String target ;
219
+ protected final byte @ Nullable [] targetInformation ;
228
220
229
221
// Information we can generate but may be passed in (for testing)
230
- protected byte [] clientChallenge ;
231
- protected byte [] clientChallenge2 ;
232
- protected byte [] secondaryKey ;
233
- protected byte [] timestamp ;
222
+ protected byte @ Nullable [] clientChallenge ;
223
+ protected byte @ Nullable [] clientChallenge2 ;
224
+ protected byte @ Nullable [] secondaryKey ;
225
+ protected byte @ Nullable [] timestamp ;
234
226
235
227
// Stuff we always generate
236
- protected byte [] lmHash ;
237
- protected byte [] lmResponse ;
238
- protected byte [] ntlmHash ;
239
- protected byte [] ntlmResponse ;
240
- protected byte [] ntlmv2Hash ;
241
- protected byte [] lmv2Hash ;
242
- protected byte [] lmv2Response ;
243
- protected byte [] ntlmv2Blob ;
244
- protected byte [] ntlmv2Response ;
245
- protected byte [] ntlm2SessionResponse ;
246
- protected byte [] lm2SessionResponse ;
247
- protected byte [] lmUserSessionKey ;
248
- protected byte [] ntlmUserSessionKey ;
249
- protected byte [] ntlmv2UserSessionKey ;
250
- protected byte [] ntlm2SessionResponseUserSessionKey ;
251
- protected byte [] lanManagerSessionKey ;
252
-
253
- CipherGen (final String domain , final String user , final String password , final byte [] challenge , final String target ,
254
- final byte [] targetInformation , final byte [] clientChallenge , final byte [] clientChallenge2 , final byte [] secondaryKey ,
255
- final byte [] timestamp ) {
228
+ protected byte @ Nullable [] lmHash ;
229
+ protected byte @ Nullable [] lmResponse ;
230
+ protected byte @ Nullable [] ntlmHash ;
231
+ protected byte @ Nullable [] ntlmResponse ;
232
+ protected byte @ Nullable [] ntlmv2Hash ;
233
+ protected byte @ Nullable [] lmv2Hash ;
234
+ protected byte @ Nullable [] lmv2Response ;
235
+ protected byte @ Nullable [] ntlmv2Blob ;
236
+ protected byte @ Nullable [] ntlmv2Response ;
237
+ protected byte @ Nullable [] ntlm2SessionResponse ;
238
+ protected byte @ Nullable [] lm2SessionResponse ;
239
+ protected byte @ Nullable [] lmUserSessionKey ;
240
+ protected byte @ Nullable [] ntlmUserSessionKey ;
241
+ protected byte @ Nullable [] ntlmv2UserSessionKey ;
242
+ protected byte @ Nullable [] ntlm2SessionResponseUserSessionKey ;
243
+ protected byte @ Nullable [] lanManagerSessionKey ;
244
+
245
+ CipherGen (final String domain , final String user , final String password , final byte [] challenge , final @ Nullable String target ,
246
+ final byte @ Nullable [] targetInformation , final byte @ Nullable [] clientChallenge , final byte @ Nullable [] clientChallenge2 ,
247
+ final byte @ Nullable [] secondaryKey , final byte @ Nullable [] timestamp ) {
256
248
this .domain = domain ;
257
249
this .target = target ;
258
250
this .user = user ;
@@ -265,8 +257,8 @@ private static class CipherGen {
265
257
this .timestamp = timestamp ;
266
258
}
267
259
268
- CipherGen (final String domain , final String user , final String password , final byte [] challenge , final String target ,
269
- final byte [] targetInformation ) {
260
+ CipherGen (final String domain , final String user , final String password , final byte [] challenge , final @ Nullable String target ,
261
+ final byte @ Nullable [] targetInformation ) {
270
262
this (domain , user , password , challenge , target , targetInformation , null , null , null , null );
271
263
}
272
264
@@ -380,8 +372,11 @@ public byte[] getTimestamp() {
380
372
381
373
/**
382
374
* Calculate the NTLMv2Blob
375
+ *
376
+ * @param targetInformation this parameter is the same object as the field targetInformation,
377
+ * but guaranteed to be not null. This is done to satisfy NullAway requirements
383
378
*/
384
- public byte [] getNTLMv2Blob () {
379
+ public byte [] getNTLMv2Blob (byte [] targetInformation ) {
385
380
if (ntlmv2Blob == null ) {
386
381
ntlmv2Blob = createBlob (getClientChallenge2 (), targetInformation , getTimestamp ());
387
382
}
@@ -390,10 +385,13 @@ public byte[] getNTLMv2Blob() {
390
385
391
386
/**
392
387
* Calculate the NTLMv2Response
388
+ *
389
+ * @param targetInformation this parameter is the same object as the field targetInformation,
390
+ * but guaranteed to be not null. This is done to satisfy NullAway requirements
393
391
*/
394
- public byte [] getNTLMv2Response () {
392
+ public byte [] getNTLMv2Response (byte [] targetInformation ) {
395
393
if (ntlmv2Response == null ) {
396
- ntlmv2Response = lmv2Response (getNTLMv2Hash (), challenge , getNTLMv2Blob ());
394
+ ntlmv2Response = lmv2Response (getNTLMv2Hash (), challenge , getNTLMv2Blob (targetInformation ));
397
395
}
398
396
return ntlmv2Response ;
399
397
}
@@ -457,12 +455,15 @@ public byte[] getNTLMUserSessionKey() {
457
455
458
456
/**
459
457
* GetNTLMv2UserSessionKey
458
+ *
459
+ * @param targetInformation this parameter is the same object as the field targetInformation,
460
+ * but guaranteed to be not null. This is done to satisfy NullAway requirements
460
461
*/
461
- public byte [] getNTLMv2UserSessionKey () {
462
+ public byte [] getNTLMv2UserSessionKey (byte [] targetInformation ) {
462
463
if (ntlmv2UserSessionKey == null ) {
463
464
final byte [] ntlmv2hash = getNTLMv2Hash ();
464
465
final byte [] truncatedResponse = new byte [16 ];
465
- System .arraycopy (getNTLMv2Response (), 0 , truncatedResponse , 0 , 16 );
466
+ System .arraycopy (getNTLMv2Response (targetInformation ), 0 , truncatedResponse , 0 , 16 );
466
467
ntlmv2UserSessionKey = hmacMD5 (truncatedResponse , ntlmv2hash );
467
468
}
468
469
return ntlmv2UserSessionKey ;
@@ -597,9 +598,6 @@ private static byte[] lmHash(final String password) {
597
598
* the NTLM Response and the NTLMv2 and LMv2 Hashes.
598
599
*/
599
600
private static byte [] ntlmHash (final String password ) {
600
- if (UNICODE_LITTLE_UNMARKED == null ) {
601
- throw new NtlmEngineException ("Unicode not supported" );
602
- }
603
601
final byte [] unicodePassword = password .getBytes (UNICODE_LITTLE_UNMARKED );
604
602
final MD4 md4 = new MD4 ();
605
603
md4 .update (unicodePassword );
@@ -613,9 +611,6 @@ private static byte[] ntlmHash(final String password) {
613
611
* Responses.
614
612
*/
615
613
private static byte [] lmv2Hash (final String domain , final String user , final byte [] ntlmHash ) {
616
- if (UNICODE_LITTLE_UNMARKED == null ) {
617
- throw new NtlmEngineException ("Unicode not supported" );
618
- }
619
614
final HMACMD5 hmacMD5 = new HMACMD5 (ntlmHash );
620
615
// Upper case username, upper case domain!
621
616
hmacMD5 .update (user .toUpperCase (Locale .ROOT ).getBytes (UNICODE_LITTLE_UNMARKED ));
@@ -632,9 +627,6 @@ private static byte[] lmv2Hash(final String domain, final String user, final byt
632
627
* Responses.
633
628
*/
634
629
private static byte [] ntlmv2Hash (final String domain , final String user , final byte [] ntlmHash ) {
635
- if (UNICODE_LITTLE_UNMARKED == null ) {
636
- throw new NtlmEngineException ("Unicode not supported" );
637
- }
638
630
final HMACMD5 hmacMD5 = new HMACMD5 (ntlmHash );
639
631
// Upper case username, mixed case target!!
640
632
hmacMD5 .update (user .toUpperCase (Locale .ROOT ).getBytes (UNICODE_LITTLE_UNMARKED ));
@@ -774,10 +766,11 @@ private static void oddParity(final byte[] bytes) {
774
766
* NTLM message generation, base class
775
767
*/
776
768
private static class NTLMMessage {
769
+ private static final byte [] EMPTY_BYTE_ARRAY = new byte []{};
777
770
/**
778
771
* The current response
779
772
*/
780
- private byte [] messageContents ;
773
+ private byte [] messageContents = EMPTY_BYTE_ARRAY ;
781
774
782
775
/**
783
776
* The current output position
@@ -902,7 +895,7 @@ protected void addByte(final byte b) {
902
895
*
903
896
* @param bytes the bytes to add.
904
897
*/
905
- protected void addBytes (final byte [] bytes ) {
898
+ protected void addBytes (final byte @ Nullable [] bytes ) {
906
899
if (bytes == null ) {
907
900
return ;
908
901
}
@@ -1022,8 +1015,8 @@ String getResponse() {
1022
1015
*/
1023
1016
static class Type2Message extends NTLMMessage {
1024
1017
protected byte [] challenge ;
1025
- protected String target ;
1026
- protected byte [] targetInfo ;
1018
+ protected @ Nullable String target ;
1019
+ protected byte @ Nullable [] targetInfo ;
1027
1020
protected int flags ;
1028
1021
1029
1022
Type2Message (final String message ) {
@@ -1090,14 +1083,14 @@ byte[] getChallenge() {
1090
1083
/**
1091
1084
* Retrieve the target
1092
1085
*/
1093
- String getTarget () {
1086
+ @ Nullable String getTarget () {
1094
1087
return target ;
1095
1088
}
1096
1089
1097
1090
/**
1098
1091
* Retrieve the target info
1099
1092
*/
1100
- byte [] getTargetInfo () {
1093
+ byte @ Nullable [] getTargetInfo () {
1101
1094
return targetInfo ;
1102
1095
}
1103
1096
@@ -1117,19 +1110,19 @@ static class Type3Message extends NTLMMessage {
1117
1110
// Response flags from the type2 message
1118
1111
protected int type2Flags ;
1119
1112
1120
- protected byte [] domainBytes ;
1121
- protected byte [] hostBytes ;
1113
+ protected byte @ Nullable [] domainBytes ;
1114
+ protected byte @ Nullable [] hostBytes ;
1122
1115
protected byte [] userBytes ;
1123
1116
1124
1117
protected byte [] lmResp ;
1125
1118
protected byte [] ntResp ;
1126
- protected byte [] sessionKey ;
1119
+ protected byte @ Nullable [] sessionKey ;
1127
1120
1128
1121
/**
1129
1122
* Constructor. Pass the arguments we will need
1130
1123
*/
1131
1124
Type3Message (final String domain , final String host , final String user , final String password , final byte [] nonce ,
1132
- final int type2Flags , final String target , final byte [] targetInformation ) {
1125
+ final int type2Flags , final @ Nullable String target , final byte @ Nullable [] targetInformation ) {
1133
1126
// Save the flags
1134
1127
this .type2Flags = type2Flags ;
1135
1128
@@ -1149,12 +1142,12 @@ static class Type3Message extends NTLMMessage {
1149
1142
// been tested
1150
1143
if ((type2Flags & FLAG_TARGETINFO_PRESENT ) != 0 && targetInformation != null && target != null ) {
1151
1144
// NTLMv2
1152
- ntResp = gen .getNTLMv2Response ();
1145
+ ntResp = gen .getNTLMv2Response (targetInformation );
1153
1146
lmResp = gen .getLMv2Response ();
1154
1147
if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY ) != 0 ) {
1155
1148
userSessionKey = gen .getLanManagerSessionKey ();
1156
1149
} else {
1157
- userSessionKey = gen .getNTLMv2UserSessionKey ();
1150
+ userSessionKey = gen .getNTLMv2UserSessionKey (targetInformation );
1158
1151
}
1159
1152
} else {
1160
1153
// NTLMv1
@@ -1198,9 +1191,6 @@ static class Type3Message extends NTLMMessage {
1198
1191
} else {
1199
1192
sessionKey = null ;
1200
1193
}
1201
- if (UNICODE_LITTLE_UNMARKED == null ) {
1202
- throw new NtlmEngineException ("Unicode not supported" );
1203
- }
1204
1194
hostBytes = unqualifiedHost != null ? unqualifiedHost .getBytes (UNICODE_LITTLE_UNMARKED ) : null ;
1205
1195
domainBytes = unqualifiedDomain != null ? unqualifiedDomain .toUpperCase (Locale .ROOT ).getBytes (UNICODE_LITTLE_UNMARKED ) : null ;
1206
1196
userBytes = user .getBytes (UNICODE_LITTLE_UNMARKED );
0 commit comments