1 19 20 package jcifs.smb; 21 22 import java.io.UnsupportedEncodingException ; 23 import java.io.Serializable ; 24 import java.security.Principal ; 25 import java.util.Random ; 26 import java.util.Arrays ; 27 import jcifs.Config; 28 import jcifs.util.*; 29 30 39 40 public final class NtlmPasswordAuthentication implements Principal , Serializable { 41 42 private static final int LM_COMPATIBILITY = 43 Config.getInt("jcifs.smb.lmCompatibility", 0); 44 45 private static final Random RANDOM = new Random (); 46 47 private static LogStream log = LogStream.getInstance(); 48 49 private static final byte[] S8 = { 51 (byte)0x4b, (byte)0x47, (byte)0x53, (byte)0x21, 52 (byte)0x40, (byte)0x23, (byte)0x24, (byte)0x25 53 }; 54 private static void E( byte[] key, byte[] data, byte[] e ) { 55 byte[] key7 = new byte[7]; 56 byte[] e8 = new byte[8]; 57 58 for( int i = 0; i < key.length / 7; i++ ) { 59 System.arraycopy( key, i * 7, key7, 0, 7 ); 60 DES des = new DES( key7 ); 61 des.encrypt( data, e8 ); 62 System.arraycopy( e8, 0, e, i * 8, 8 ); 63 } 64 } 65 66 static String DEFAULT_DOMAIN; 67 static String DEFAULT_USERNAME; 68 static String DEFAULT_PASSWORD; 69 static final String BLANK = ""; 70 71 static void initDefaults() { 72 if (DEFAULT_DOMAIN != null) return; 73 DEFAULT_DOMAIN = Config.getProperty("jcifs.smb.client.domain", "?"); 74 DEFAULT_USERNAME = Config.getProperty("jcifs.smb.client.username", "GUEST"); 75 DEFAULT_PASSWORD = Config.getProperty("jcifs.smb.client.password", BLANK); 76 } 77 78 81 static public byte[] getPreNTLMResponse( String password, byte[] challenge ) { 82 byte[] p14 = new byte[14]; 83 byte[] p21 = new byte[21]; 84 byte[] p24 = new byte[24]; 85 byte[] passwordBytes; 86 try { 87 passwordBytes = password.toUpperCase().getBytes( ServerMessageBlock.OEM_ENCODING ); 88 } catch( UnsupportedEncodingException uee ) { 89 throw new RuntimeException ("Try setting jcifs.encoding=US-ASCII", uee); 90 } 91 int passwordLength = passwordBytes.length; 92 93 if( passwordLength > 14) { 95 passwordLength = 14; 96 } 97 System.arraycopy( passwordBytes, 0, p14, 0, passwordLength ); 98 E( p14, S8, p21); 99 E( p21, challenge, p24); 100 return p24; 101 } 102 105 static public byte[] getNTLMResponse( String password, byte[] challenge ) { 106 byte[] uni = null; 107 byte[] p21 = new byte[21]; 108 byte[] p24 = new byte[24]; 109 110 try { 111 uni = password.getBytes( "UnicodeLittleUnmarked" ); 112 } catch( UnsupportedEncodingException uee ) { 113 if( log.level > 0 ) 114 uee.printStackTrace( log ); 115 } 116 MD4 md4 = new MD4(); 117 md4.update( uni ); 118 try { 119 md4.digest(p21, 0, 16); 120 } catch (Exception ex) { 121 if( log.level > 0 ) 122 ex.printStackTrace( log ); 123 } 124 E( p21, challenge, p24 ); 125 return p24; 126 } 127 128 137 public static byte[] getLMv2Response(String domain, String user, 138 String password, byte[] challenge, byte[] clientChallenge) { 139 try { 140 byte[] hash = new byte[16]; 141 byte[] response = new byte[24]; 142 MD4 md4 = new MD4(); 143 md4.update(password.getBytes("UnicodeLittleUnmarked")); 144 HMACT64 hmac = new HMACT64(md4.digest()); 145 hmac.update(user.toUpperCase().getBytes("UnicodeLittleUnmarked")); 146 hmac.update(domain.toUpperCase().getBytes("UnicodeLittleUnmarked")); 147 hmac = new HMACT64(hmac.digest()); 148 hmac.update(challenge); 149 hmac.update(clientChallenge); 150 hmac.digest(response, 0, 16); 151 System.arraycopy(clientChallenge, 0, response, 16, 8); 152 return response; 153 } catch (Exception ex) { 154 if( log.level > 0 ) 155 ex.printStackTrace( log ); 156 return null; 157 } 158 } 159 160 static final NtlmPasswordAuthentication NULL = 161 new NtlmPasswordAuthentication( "", "", "" ); 162 static final NtlmPasswordAuthentication GUEST = 163 new NtlmPasswordAuthentication( "?", "GUEST", "" ); 164 static final NtlmPasswordAuthentication DEFAULT = 165 new NtlmPasswordAuthentication( null ); 166 167 String domain; 168 String username; 169 String password; 170 byte[] ansiHash; 171 byte[] unicodeHash; 172 boolean hashesExternal = false; 173 byte[] clientChallenge = null; 174 byte[] challenge = null; 175 176 181 182 public NtlmPasswordAuthentication( String userInfo ) { 183 domain = username = password = null; 184 185 if( userInfo != null ) { 186 int i, u, end; 187 char c; 188 189 end = userInfo.length(); 190 for( i = 0, u = 0; i < end; i++ ) { 191 c = userInfo.charAt( i ); 192 if( c == ';' ) { 193 domain = userInfo.substring( 0, i ); 194 u = i + 1; 195 } else if( c == ':' ) { 196 password = userInfo.substring( i + 1 ); 197 break; 198 } 199 } 200 username = userInfo.substring( u, i ); 201 } 202 203 initDefaults(); 204 205 if( domain == null ) this.domain = DEFAULT_DOMAIN; 206 if( username == null ) this.username = DEFAULT_USERNAME; 207 if( password == null ) this.password = DEFAULT_PASSWORD; 208 } 209 216 public NtlmPasswordAuthentication( String domain, String username, String password ) { 217 this.domain = domain; 218 this.username = username; 219 this.password = password; 220 221 initDefaults(); 222 223 if( domain == null ) this.domain = DEFAULT_DOMAIN; 224 if( username == null ) this.username = DEFAULT_USERNAME; 225 if( password == null ) this.password = DEFAULT_PASSWORD; 226 } 227 232 public NtlmPasswordAuthentication( String domain, String username, 233 byte[] challenge, byte[] ansiHash, byte[] unicodeHash ) { 234 if( domain == null || username == null || 235 ansiHash == null || unicodeHash == null ) { 236 throw new IllegalArgumentException ( "External credentials cannot be null" ); 237 } 238 this.domain = domain; 239 this.username = username; 240 this.password = null; 241 this.challenge = challenge; 242 this.ansiHash = ansiHash; 243 this.unicodeHash = unicodeHash; 244 hashesExternal = true; 245 } 246 247 250 public String getDomain() { 251 return domain; 252 } 253 256 public String getUsername() { 257 return username; 258 } 259 266 public String getPassword() { 267 return password; 268 } 269 273 public String getName() { 274 boolean d = domain.length() > 0 && domain.equals( "?" ) == false; 275 return d ? domain + "\\" + username : username; 276 } 277 278 281 public byte[] getAnsiHash( byte[] challenge ) { 282 if( hashesExternal ) { 283 return ansiHash; 284 } 285 switch (LM_COMPATIBILITY) { 286 case 0: 287 case 1: 288 return getPreNTLMResponse( password, challenge ); 289 case 2: 290 return getNTLMResponse( password, challenge ); 291 case 3: 292 case 4: 293 case 5: 294 if( clientChallenge == null ) { 295 clientChallenge = new byte[8]; 296 RANDOM.nextBytes( clientChallenge ); 297 } 298 return getLMv2Response(domain, username, password, challenge, 299 clientChallenge); 300 default: 301 return getPreNTLMResponse( password, challenge ); 302 } 303 } 304 307 public byte[] getUnicodeHash( byte[] challenge ) { 308 if( hashesExternal ) { 309 return unicodeHash; 310 } 311 switch (LM_COMPATIBILITY) { 312 case 0: 313 case 1: 314 case 2: 315 return getNTLMResponse( password, challenge ); 316 case 3: 317 case 4: 318 case 5: 319 327 return new byte[0]; 328 default: 329 return getNTLMResponse( password, challenge ); 330 } 331 } 332 333 340 public byte[] getUserSessionKey(byte[] challenge) { 341 if (hashesExternal) return null; 342 byte[] key = new byte[16]; 343 try { 344 getUserSessionKey(challenge, key, 0); 345 } catch (Exception ex) { 346 if( log.level > 0 ) 347 ex.printStackTrace( log ); 348 } 349 return key; 350 } 351 352 361 void getUserSessionKey(byte[] challenge, byte[] dest, int offset) 362 throws Exception { 363 if (hashesExternal) return; 364 MD4 md4 = new MD4(); 365 md4.update(password.getBytes("UnicodeLittleUnmarked")); 366 switch (LM_COMPATIBILITY) { 367 case 0: 368 case 1: 369 case 2: 370 md4.update(md4.digest()); 371 md4.digest(dest, offset, 16); 372 break; 373 case 3: 374 case 4: 375 case 5: 376 if( clientChallenge == null ) { 377 clientChallenge = new byte[8]; 378 RANDOM.nextBytes( clientChallenge ); 379 } 380 381 HMACT64 hmac = new HMACT64(md4.digest()); 382 hmac.update(username.toUpperCase().getBytes( 383 "UnicodeLittleUnmarked")); 384 hmac.update(domain.toUpperCase().getBytes( 385 "UnicodeLittleUnmarked")); 386 byte[] ntlmv2Hash = hmac.digest(); 387 hmac = new HMACT64(ntlmv2Hash); 388 hmac.update(challenge); 389 hmac.update(clientChallenge); 390 HMACT64 userKey = new HMACT64(ntlmv2Hash); 391 userKey.update(hmac.digest()); 392 userKey.digest(dest, offset, 16); 393 break; 394 default: 395 md4.update(md4.digest()); 396 md4.digest(dest, offset, 16); 397 break; 398 } 399 } 400 401 406 public boolean equals( Object obj ) { 407 if( obj instanceof NtlmPasswordAuthentication ) { 408 NtlmPasswordAuthentication ntlm = (NtlmPasswordAuthentication)obj; 409 if( ntlm.domain.toUpperCase().equals( domain.toUpperCase() ) && 410 ntlm.username.toUpperCase().equals( username.toUpperCase() )) { 411 if( hashesExternal && ntlm.hashesExternal ) { 412 return Arrays.equals( ansiHash, ntlm.ansiHash ) && 413 Arrays.equals( unicodeHash, ntlm.unicodeHash ); 414 418 } else if( !hashesExternal && password.equals( ntlm.password )) { 419 return true; 420 } 421 } 422 } 423 return false; 424 } 425 426 427 430 public int hashCode() { 431 return getName().toUpperCase().hashCode(); 432 } 433 437 public String toString() { 438 return getName(); 439 } 440 } 441 442 | Popular Tags |