1 19 20 package com.maverick.http; 21 22 import java.io.IOException ; 23 24 import com.maverick.crypto.encoders.Base64; 25 import com.maverick.crypto.engines.DESEngine; 26 27 31 class NTLM { 32 33 34 public static final String DEFAULT_CHARSET = "ASCII"; 36 37 private byte[] currentResponse; 38 39 40 private int currentPosition = 0; 41 42 43 private String credentialCharset = DEFAULT_CHARSET; 44 45 56 public String getResponseFor(String message, String username, String password, String host, String domain) throws IOException { 57 58 final String response; 59 if (message == null || message.trim().equals("")) { response = getType1Message(host, domain); 61 } else { 62 response = getType3Message(username, password, host, domain, parseType2Message(message)); 63 } 64 return response; 65 } 66 67 74 private DESEngine getCipher(byte[] key) throws IOException { 75 76 DESEngine cipher = new DESEngine(); 77 key = setupKey(key); 78 cipher.init(true, key); 79 return cipher; 80 81 } 82 83 89 private byte[] setupKey(byte[] key56) { 90 byte[] key = new byte[8]; 91 key[0] = (byte) ((key56[0] >> 1) & 0xff); 92 key[1] = (byte) ((((key56[0] & 0x01) << 6) | (((key56[1] & 0xff) >> 2) & 0xff)) & 0xff); 93 key[2] = (byte) ((((key56[1] & 0x03) << 5) | (((key56[2] & 0xff) >> 3) & 0xff)) & 0xff); 94 key[3] = (byte) ((((key56[2] & 0x07) << 4) | (((key56[3] & 0xff) >> 4) & 0xff)) & 0xff); 95 key[4] = (byte) ((((key56[3] & 0x0f) << 3) | (((key56[4] & 0xff) >> 5) & 0xff)) & 0xff); 96 key[5] = (byte) ((((key56[4] & 0x1f) << 2) | (((key56[5] & 0xff) >> 6) & 0xff)) & 0xff); 97 key[6] = (byte) ((((key56[5] & 0x3f) << 1) | (((key56[6] & 0xff) >> 7) & 0xff)) & 0xff); 98 key[7] = (byte) (key56[6] & 0x7f); 99 100 for (int i = 0; i < key.length; i++) { 101 key[i] = (byte) (key[i] << 1); 102 } 103 return key; 104 } 105 106 114 private byte[] encrypt(byte[] key, byte[] bytes) throws IOException { 115 116 DESEngine cipher = getCipher(key); 117 byte[] enc = cipher.doFinal(bytes); 118 return enc; 119 120 } 121 122 127 private void prepareResponse(int length) { 128 currentResponse = new byte[length]; 129 currentPosition = 0; 130 } 131 132 137 private void addByte(byte b) { 138 currentResponse[currentPosition] = b; 139 currentPosition++; 140 } 141 142 147 private void addBytes(byte[] bytes) { 148 for (int i = 0; i < bytes.length; i++) { 149 currentResponse[currentPosition] = bytes[i]; 150 currentPosition++; 151 } 152 } 153 154 160 private String getResponse() { 161 byte[] resp; 162 if (currentResponse.length > currentPosition) { 163 byte[] tmp = new byte[currentPosition]; 164 for (int i = 0; i < currentPosition; i++) { 165 tmp[i] = currentResponse[i]; 166 } 167 resp = tmp; 168 } else { 169 resp = currentResponse; 170 } 171 return new String (Base64.encode(resp)); 172 } 173 174 183 public String getType1Message(String host, String domain) { 184 host = host.toUpperCase(); 185 domain = domain.toUpperCase(); 186 byte[] hostBytes = host.getBytes(); 187 byte[] domainBytes = domain.getBytes(); 188 189 int finalLength = 32 + hostBytes.length + domainBytes.length; 190 prepareResponse(finalLength); 191 192 byte[] protocol = "NTLMSSP".getBytes(); addBytes(protocol); 195 addByte((byte) 0); 196 197 addByte((byte) 1); 199 addByte((byte) 0); 200 addByte((byte) 0); 201 addByte((byte) 0); 202 203 addByte((byte) 6); 205 addByte((byte) 82); 206 addByte((byte) 0); 207 addByte((byte) 0); 208 209 int iDomLen = domainBytes.length; 211 byte[] domLen = convertShort(iDomLen); 212 addByte(domLen[0]); 213 addByte(domLen[1]); 214 215 addByte(domLen[0]); 217 addByte(domLen[1]); 218 219 byte[] domOff = convertShort(hostBytes.length + 32); 221 addByte(domOff[0]); 222 addByte(domOff[1]); 223 addByte((byte) 0); 224 addByte((byte) 0); 225 226 byte[] hostLen = convertShort(hostBytes.length); 228 addByte(hostLen[0]); 229 addByte(hostLen[1]); 230 231 addByte(hostLen[0]); 233 addByte(hostLen[1]); 234 235 byte[] hostOff = convertShort(32); 237 addByte(hostOff[0]); 238 addByte(hostOff[1]); 239 addByte((byte) 0); 240 addByte((byte) 0); 241 242 addBytes(hostBytes); 244 245 addBytes(domainBytes); 247 248 return getResponse(); 249 } 250 251 258 public byte[] parseType2Message(String message) { 259 byte[] msg = Base64.decode(message); 261 byte[] nonce = new byte[8]; 262 for (int i = 0; i < 8; i++) { 264 nonce[i] = msg[i + 24]; 265 } 266 return nonce; 267 } 268 269 283 public String getType3Message(String user, String password, String host, String domain, byte[] nonce) throws IOException { 284 285 int ntRespLen = 0; 286 int lmRespLen = 24; 287 domain = domain.toUpperCase(); 288 host = host.toUpperCase(); 289 user = user.toUpperCase(); 290 byte[] domainBytes = domain.getBytes(); 291 byte[] hostBytes = host.getBytes(); 292 byte[] userBytes = user.getBytes(); 293 int domainLen = domainBytes.length; 294 int hostLen = hostBytes.length; 295 int userLen = userBytes.length; 296 int finalLength = 64 + ntRespLen + lmRespLen + domainLen + userLen + hostLen; 297 prepareResponse(finalLength); 298 byte[] ntlmssp = "NTLMSSP".getBytes(); addBytes(ntlmssp); 300 addByte((byte) 0); 301 addByte((byte) 3); 302 addByte((byte) 0); 303 addByte((byte) 0); 304 addByte((byte) 0); 305 306 addBytes(convertShort(24)); 308 addBytes(convertShort(24)); 309 310 addBytes(convertShort(finalLength - 24)); 312 addByte((byte) 0); 313 addByte((byte) 0); 314 315 addBytes(convertShort(0)); 317 addBytes(convertShort(0)); 318 319 addBytes(convertShort(finalLength)); 321 addByte((byte) 0); 322 addByte((byte) 0); 323 324 addBytes(convertShort(domainLen)); 326 addBytes(convertShort(domainLen)); 327 328 addBytes(convertShort(64)); 330 addByte((byte) 0); 331 addByte((byte) 0); 332 333 addBytes(convertShort(userLen)); 335 addBytes(convertShort(userLen)); 336 337 addBytes(convertShort(64 + domainLen)); 339 addByte((byte) 0); 340 addByte((byte) 0); 341 342 addBytes(convertShort(hostLen)); 344 addBytes(convertShort(hostLen)); 345 346 addBytes(convertShort(64 + domainLen + userLen)); 348 349 for (int i = 0; i < 6; i++) { 350 addByte((byte) 0); 351 } 352 353 addBytes(convertShort(finalLength)); 355 addByte((byte) 0); 356 addByte((byte) 0); 357 358 addByte((byte) 6); 360 addByte((byte) 82); 361 addByte((byte) 0); 362 addByte((byte) 0); 363 364 addBytes(domainBytes); 365 addBytes(userBytes); 366 addBytes(hostBytes); 367 addBytes(hashPassword(password, nonce)); 368 return getResponse(); 369 } 370 371 380 private byte[] hashPassword(String password, byte[] nonce) throws IOException { 381 byte[] passw = password.toUpperCase().getBytes(); 382 byte[] lmPw1 = new byte[7]; 383 byte[] lmPw2 = new byte[7]; 384 385 int len = passw.length; 386 if (len > 7) { 387 len = 7; 388 } 389 390 int idx; 391 for (idx = 0; idx < len; idx++) { 392 lmPw1[idx] = passw[idx]; 393 } 394 for (; idx < 7; idx++) { 395 lmPw1[idx] = (byte) 0; 396 } 397 398 len = passw.length; 399 if (len > 14) { 400 len = 14; 401 } 402 for (idx = 7; idx < len; idx++) { 403 lmPw2[idx - 7] = passw[idx]; 404 } 405 for (; idx < 14; idx++) { 406 lmPw2[idx - 7] = (byte) 0; 407 } 408 409 byte[] magic = { (byte) 0x4B, (byte) 0x47, (byte) 0x53, (byte) 0x21, (byte) 0x40, (byte) 0x23, (byte) 0x24, (byte) 0x25 }; 411 412 byte[] lmHpw1; 413 lmHpw1 = encrypt(lmPw1, magic); 414 415 byte[] lmHpw2 = encrypt(lmPw2, magic); 416 417 byte[] lmHpw = new byte[21]; 418 for (int i = 0; i < lmHpw1.length; i++) { 419 lmHpw[i] = lmHpw1[i]; 420 } 421 for (int i = 0; i < lmHpw2.length; i++) { 422 lmHpw[i + 8] = lmHpw2[i]; 423 } 424 for (int i = 0; i < 5; i++) { 425 lmHpw[i + 16] = (byte) 0; 426 } 427 428 byte[] lmResp = new byte[24]; 430 calcResp(lmHpw, nonce, lmResp); 431 432 return lmResp; 433 } 434 435 445 private void calcResp(byte[] keys, byte[] plaintext, byte[] results) throws IOException { 446 byte[] keys1 = new byte[7]; 447 byte[] keys2 = new byte[7]; 448 byte[] keys3 = new byte[7]; 449 for (int i = 0; i < 7; i++) { 450 keys1[i] = keys[i]; 451 } 452 453 for (int i = 0; i < 7; i++) { 454 keys2[i] = keys[i + 7]; 455 } 456 457 for (int i = 0; i < 7; i++) { 458 keys3[i] = keys[i + 14]; 459 } 460 byte[] results1 = encrypt(keys1, plaintext); 461 462 byte[] results2 = encrypt(keys2, plaintext); 463 464 byte[] results3 = encrypt(keys3, plaintext); 465 466 for (int i = 0; i < 8; i++) { 467 results[i] = results1[i]; 468 } 469 for (int i = 0; i < 8; i++) { 470 results[i + 8] = results2[i]; 471 } 472 for (int i = 0; i < 8; i++) { 473 results[i + 16] = results3[i]; 474 } 475 } 476 477 483 private byte[] convertShort(int num) { 484 byte[] val = new byte[2]; 485 String hex = Integer.toString(num, 16); 486 while (hex.length() < 4) { 487 hex = "0" + hex; } 489 String low = hex.substring(2, 4); 490 String high = hex.substring(0, 2); 491 492 val[0] = (byte) Integer.parseInt(low, 16); 493 val[1] = (byte) Integer.parseInt(high, 16); 494 return val; 495 } 496 497 500 public String getCredentialCharset() { 501 return credentialCharset; 502 } 503 504 507 public void setCredentialCharset(String credentialCharset) { 508 this.credentialCharset = credentialCharset; 509 } 510 511 } 512 | Popular Tags |