1 19 20 package com.knowgate.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 28 import com.knowgate.jcifs.util.DES; 29 import com.knowgate.jcifs.util.MD4; 30 import com.knowgate.jcifs.util.HMACT64; 31 32 import com.knowgate.debug.*; 33 import com.knowgate.jcifs.Config; 34 35 44 45 public final class NtlmPasswordAuthentication implements Principal , Serializable { 46 47 private static final int LM_COMPATIBILITY = 48 Config.getInt("jcifs.smb.lmCompatibility", 0); 49 50 private static final String DEFAULT_DOMAIN = 51 Config.getProperty("jcifs.smb.client.domain", "?"); 52 53 private static final String DEFAULT_USERNAME = 54 Config.getProperty("jcifs.smb.client.username", "GUEST"); 55 56 static final String DEFAULT_PASSWORD = 57 Config.getProperty("jcifs.smb.client.password", ""); 58 59 private static final Random RANDOM = new Random (); 60 61 private static final byte[] S8 = { 63 (byte)0x4b, (byte)0x47, (byte)0x53, (byte)0x21, 64 (byte)0x40, (byte)0x23, (byte)0x24, (byte)0x25 65 }; 66 private static void E( byte[] key, byte[] data, byte[] e ) { 67 byte[] key7 = new byte[7]; 68 byte[] e8 = new byte[8]; 69 70 for( int i = 0; i < key.length / 7; i++ ) { 71 System.arraycopy( key, i * 7, key7, 0, 7 ); 72 DES des = new DES( key7 ); 73 des.encrypt( data, e8 ); 74 System.arraycopy( e8, 0, e, i * 8, 8 ); 75 } 76 } 77 80 static public byte[] getPreNTLMResponse( String password, byte[] challenge ) { 81 byte[] p14 = new byte[14]; 82 byte[] p21 = new byte[21]; 83 byte[] p24 = new byte[24]; 84 byte[] passwordBytes; 85 try { 86 passwordBytes = password.toUpperCase().getBytes( ServerMessageBlock.OEM_ENCODING ); 87 } catch( UnsupportedEncodingException uee ) { 88 return null; 89 } 90 int passwordLength = passwordBytes.length; 91 92 if( passwordLength > 14) { 94 passwordLength = 14; 95 } 96 System.arraycopy( passwordBytes, 0, p14, 0, passwordLength ); 97 E( p14, S8, p21); 98 E( p21, challenge, p24); 99 return p24; 100 } 101 104 static public byte[] getNTLMResponse( String password, byte[] challenge ) { 105 byte[] uni = null; 106 byte[] p21 = new byte[21]; 107 byte[] p24 = new byte[24]; 108 109 try { 110 uni = password.getBytes( "UnicodeLittleUnmarked" ); 111 } catch( UnsupportedEncodingException uee ) { 112 if( DebugFile.trace ) 113 new ErrorHandler(uee); 114 } 115 MD4 md4 = new MD4(); 116 md4.update( uni ); 117 try { 118 md4.digest(p21, 0, 16); 119 } catch (Exception ex) { 120 if( DebugFile.trace ) 121 new ErrorHandler(ex); 122 } 123 E( p21, challenge, p24 ); 124 return p24; 125 } 126 127 136 public static byte[] getLMv2Response(String domain, String user, 137 String password, byte[] challenge, byte[] clientChallenge) { 138 try { 139 byte[] hash = new byte[16]; 140 byte[] response = new byte[24]; 141 MD4 md4 = new MD4(); 142 md4.update(password.getBytes("UnicodeLittleUnmarked")); 143 HMACT64 hmac = new HMACT64(md4.digest()); 144 hmac.update(user.toUpperCase().getBytes("UnicodeLittleUnmarked")); 145 hmac.update(domain.toUpperCase().getBytes("UnicodeLittleUnmarked")); 146 hmac = new HMACT64(hmac.digest()); 147 hmac.update(challenge); 148 hmac.update(clientChallenge); 149 hmac.digest(response, 0, 16); 150 System.arraycopy(clientChallenge, 0, response, 16, 8); 151 return response; 152 } catch (Exception ex) { 153 if( DebugFile.trace ) 154 new ErrorHandler(ex); 155 return null; 156 } 157 } 158 159 static final NtlmPasswordAuthentication NULL = 160 new NtlmPasswordAuthentication( "", "", "" ); 161 static final NtlmPasswordAuthentication GUEST = 162 new NtlmPasswordAuthentication( "?", "GUEST", "" ); 163 static final NtlmPasswordAuthentication DEFAULT = 164 new NtlmPasswordAuthentication( null ); 165 166 String domain; 167 String username; 168 String password; 169 byte[] ansiHash; 170 byte[] unicodeHash; 171 boolean hashesExternal = false; 172 byte[] clientChallenge = null; 173 byte[] challenge = null; 174 175 180 181 public NtlmPasswordAuthentication( String userInfo ) { 182 domain = username = password = null; 183 184 if( userInfo != null ) { 185 int i, u, end; 186 char c; 187 188 end = userInfo.length(); 189 for( i = 0, u = 0; i < end; i++ ) { 190 c = userInfo.charAt( i ); 191 if( c == ';' ) { 192 domain = userInfo.substring( 0, i ); 193 u = i + 1; 194 } else if( c == ':' ) { 195 password = userInfo.substring( i + 1 ); 196 break; 197 } 198 } 199 username = userInfo.substring( u, i ); 200 } 201 202 if( domain == null ) this.domain = DEFAULT_DOMAIN; 203 if( username == null ) this.username = DEFAULT_USERNAME; 204 if( password == null ) this.password = DEFAULT_PASSWORD; 205 } 206 213 public NtlmPasswordAuthentication( String domain, String username, String password ) { 214 this.domain = domain; 215 this.username = username; 216 this.password = password; 217 if( domain == null ) this.domain = DEFAULT_DOMAIN; 218 if( username == null ) this.username = DEFAULT_USERNAME; 219 if( password == null ) this.password = DEFAULT_PASSWORD; 220 } 221 226 public NtlmPasswordAuthentication( String domain, String username, 227 byte[] challenge, byte[] ansiHash, byte[] unicodeHash ) { 228 if( domain == null || username == null || 229 ansiHash == null || unicodeHash == null ) { 230 throw new IllegalArgumentException ( "External credentials cannot be null" ); 231 } 232 this.domain = domain; 233 this.username = username; 234 this.password = null; 235 this.challenge = challenge; 236 this.ansiHash = ansiHash; 237 this.unicodeHash = unicodeHash; 238 hashesExternal = true; 239 } 240 241 244 public String getDomain() { 245 return domain; 246 } 247 250 public String getUsername() { 251 return username; 252 } 253 260 public String getPassword() { 261 return password; 262 } 263 267 public String getName() { 268 boolean d = domain.length() > 0 && domain.equals( "?" ) == false; 269 return d ? domain + "\\" + username : username; 270 } 271 272 275 public byte[] getAnsiHash( byte[] challenge ) { 276 if( hashesExternal ) { 277 return ansiHash; 278 } 279 switch (LM_COMPATIBILITY) { 280 case 0: 281 case 1: 282 return getPreNTLMResponse( password, challenge ); 283 case 2: 284 return getNTLMResponse( password, challenge ); 285 case 3: 286 case 4: 287 case 5: 288 if( clientChallenge == null ) { 289 clientChallenge = new byte[8]; 290 RANDOM.nextBytes( clientChallenge ); 291 } 292 return getLMv2Response(domain, username, password, challenge, 293 clientChallenge); 294 default: 295 return getPreNTLMResponse( password, challenge ); 296 } 297 } 298 301 public byte[] getUnicodeHash( byte[] challenge ) { 302 if( hashesExternal ) { 303 return unicodeHash; 304 } 305 switch (LM_COMPATIBILITY) { 306 case 0: 307 case 1: 308 case 2: 309 return getNTLMResponse( password, challenge ); 310 case 3: 311 case 4: 312 case 5: 313 321 return new byte[0]; 322 default: 323 return getNTLMResponse( password, challenge ); 324 } 325 } 326 327 334 public byte[] getUserSessionKey(byte[] challenge) { 335 if (hashesExternal) return null; 336 byte[] key = new byte[16]; 337 try { 338 getUserSessionKey(challenge, key, 0); 339 } catch (Exception ex) { 340 if( DebugFile.trace ) 341 new ErrorHandler(ex); 342 } 343 return key; 344 } 345 346 355 void getUserSessionKey(byte[] challenge, byte[] dest, int offset) 356 throws Exception { 357 if (hashesExternal) return; 358 MD4 md4 = new MD4(); 359 md4.update(password.getBytes("UnicodeLittleUnmarked")); 360 switch (LM_COMPATIBILITY) { 361 case 0: 362 case 1: 363 case 2: 364 md4.update(md4.digest()); 365 md4.digest(dest, offset, 16); 366 break; 367 case 3: 368 case 4: 369 case 5: 370 if( clientChallenge == null ) { 371 clientChallenge = new byte[8]; 372 RANDOM.nextBytes( clientChallenge ); 373 } 374 375 HMACT64 hmac = new HMACT64(md4.digest()); 376 hmac.update(username.toUpperCase().getBytes( 377 "UnicodeLittleUnmarked")); 378 hmac.update(domain.toUpperCase().getBytes( 379 "UnicodeLittleUnmarked")); 380 byte[] ntlmv2Hash = hmac.digest(); 381 hmac = new HMACT64(ntlmv2Hash); 382 hmac.update(challenge); 383 hmac.update(clientChallenge); 384 HMACT64 userKey = new HMACT64(ntlmv2Hash); 385 userKey.update(hmac.digest()); 386 userKey.digest(dest, offset, 16); 387 break; 388 default: 389 md4.update(md4.digest()); 390 md4.digest(dest, offset, 16); 391 break; 392 } 393 } 394 395 400 public boolean equals( Object obj ) { 401 if( obj instanceof NtlmPasswordAuthentication ) { 402 NtlmPasswordAuthentication ntlm = (NtlmPasswordAuthentication)obj; 403 if( ntlm.domain.toUpperCase().equals( domain.toUpperCase() ) && 404 ntlm.username.toUpperCase().equals( username.toUpperCase() )) { 405 if( hashesExternal && ntlm.hashesExternal ) { 406 return Arrays.equals( ansiHash, ntlm.ansiHash ) && 407 Arrays.equals( unicodeHash, ntlm.unicodeHash ); 408 412 } else if( !hashesExternal && password.equals( ntlm.password )) { 413 return true; 414 } 415 } 416 } 417 return false; 418 } 419 420 421 424 public int hashCode() { 425 return getName().toUpperCase().hashCode(); 426 } 427 431 public String toString() { 432 return getName(); 433 } 434 } 435 436 | Popular Tags |