1 16 17 22 23 package com.luigidragone.net.ntlm; 24 25 import java.security.*; 26 import java.security.spec.*; 27 import javax.crypto.*; 28 import javax.crypto.spec.*; 29 import java.io.*; 30 31 195 public class NTLM { 196 protected NTLM() {} 197 200 protected static final byte[] MAGIC = new byte[] {0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25}; 201 211 protected static int unsignedByteToInt(byte b) { 212 return (int)b & 0xFF; 213 } 214 protected static byte getLoByte(char c) { 215 return (byte)c; 216 } 217 protected static byte getHiByte(char c) { 218 return (byte)((c >>> 8) & 0xFF); 219 } 220 protected static short swapBytes(short s) { 221 return (short)(((s << 8) & 0xFF00) | ((s >>> 8) & 0x00FF)); 222 } 223 241 protected static Key computeDESKey(byte[] keyData, int offset) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException { 242 byte[] desKeyData = new byte[8]; 243 int[] k = new int[7]; 244 245 for(int i = 0; i < 7; i++) 246 k[i] = unsignedByteToInt(keyData[offset + i]); 247 248 desKeyData[0] = (byte)(k[0] >>> 1); 249 desKeyData[1] = (byte)(((k[0] & 0x01) << 6) | (k[1] >>> 2)); 250 desKeyData[2] = (byte)(((k[1] & 0x03) << 5) | (k[2] >>> 3)); 251 desKeyData[3] = (byte)(((k[2] & 0x07) << 4) | (k[3] >>> 4)); 252 desKeyData[4] = (byte)(((k[3] & 0x0F) << 3) | (k[4] >>> 5)); 253 desKeyData[5] = (byte)(((k[4] & 0x1F) << 2) | (k[5] >>> 6)); 254 desKeyData[6] = (byte)(((k[5] & 0x3F) << 1) | (k[6] >>> 7)); 255 desKeyData[7] = (byte)(k[6] & 0x7F); 256 257 for(int i=0; i<8; i++) 258 desKeyData[i] = (byte)(unsignedByteToInt(desKeyData[i]) << 1); 259 260 KeySpec desKeySpec = new DESKeySpec(desKeyData); 261 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 262 SecretKey secretKey = keyFactory.generateSecret(desKeySpec); 263 return secretKey; 264 } 265 282 protected static byte[] encrypt(byte[] keys, byte[] plaintext) throws InvalidKeyException, NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException, ShortBufferException { 283 byte[] ciphertext = new byte[24]; 284 Cipher c = Cipher.getInstance("DES/ECB/NoPadding"); 285 Key k = computeDESKey(keys, 0); 286 c.init(Cipher.ENCRYPT_MODE, k); 287 c.doFinal(plaintext, 0, 8, ciphertext, 0); 288 k = computeDESKey(keys, 7); 289 c.init(Cipher.ENCRYPT_MODE, k); 290 c.doFinal(plaintext, 0, 8, ciphertext, 8); 291 k = computeDESKey(keys, 14); 292 c.init(Cipher.ENCRYPT_MODE, k); 293 c.doFinal(plaintext, 0, 8, ciphertext, 16); 294 return ciphertext; 295 } 296 297 308 public static byte[] computeLMPassword(String password) throws IllegalArgumentException , NoSuchPaddingException, NoSuchAlgorithmException { 309 if(password == null) 310 throw new IllegalArgumentException ("password : null value not allowed"); 311 try { 312 int len = password.length(); 314 if(len > 14) 315 len = 14; 316 Cipher c = Cipher.getInstance("DES/ECB/NoPadding"); 317 318 byte[] lm_pw = new byte[14]; 319 byte[] bytes = password.toUpperCase().getBytes(); 320 int i; 321 for(i = 0; i < len; i++) 322 lm_pw[i] = bytes[i]; 323 for(; i < 14; i++) 324 lm_pw[i] = 0; 325 326 byte[] lm_hpw = new byte[16]; 327 Key k = computeDESKey(lm_pw, 0); 329 c.init(Cipher.ENCRYPT_MODE, k); 330 c.doFinal(MAGIC, 0, 8, lm_hpw, 0); 332 333 k = computeDESKey(lm_pw, 7); 335 c.init(Cipher.ENCRYPT_MODE, k); 336 c.doFinal(MAGIC, 0, 8, lm_hpw, 8); 337 338 return lm_hpw; 339 } catch(InvalidKeySpecException ex) { 340 return null; 341 } catch(InvalidKeyException ex) { 342 return null; 343 } catch(BadPaddingException ex) { 344 return null; 345 } catch(IllegalBlockSizeException ex) { 346 return null; 347 } catch(ShortBufferException ex) { 348 return null; 349 } 350 } 351 352 362 public static byte[] computeNTPassword(String password) throws IllegalArgumentException , NoSuchAlgorithmException { 363 if(password == null) 364 throw new IllegalArgumentException ("password : null value not allowed"); 365 int len = password.length(); 367 if(len > 14) 368 len = 14; 369 byte[] nt_pw = new byte[2 * len]; 370 for(int i = 0; i < len; i++) { 371 char ch = password.charAt(i); 372 nt_pw[2 * i] = getLoByte(ch); 373 nt_pw[2 * i + 1] = getHiByte(ch); 374 } 375 376 MessageDigest md = MessageDigest.getInstance("MD4"); 378 return md.digest(nt_pw); 379 } 380 400 public static void computeNTLMResponse(byte[] lmPassword, byte[] ntPassword, byte[] nonce, byte[] lmResponse, byte[] ntResponse) throws IllegalArgumentException , NoSuchPaddingException, NoSuchAlgorithmException { 401 if(lmPassword.length != 16) 402 throw new IllegalArgumentException ("lmPassword : illegal size"); 403 if(ntPassword.length != 16) 404 throw new IllegalArgumentException ("ntPassword : illegal size"); 405 if(nonce.length != 8) 406 throw new IllegalArgumentException ("nonce : illegal size"); 407 if(lmResponse.length != 24) 408 throw new IllegalArgumentException ("lmResponse : illegal size"); 409 if(ntResponse.length != 24) 410 throw new IllegalArgumentException ("ntResponse : illegal size"); 411 try { 412 byte[] lmHPw = new byte[21]; 414 byte[] ntHPw = new byte[21]; 415 System.arraycopy(lmPassword, 0, lmHPw, 0, 16); 416 System.arraycopy(ntPassword, 0, ntHPw, 0, 16); 417 for(int i = 16; i < 21; i++) { 418 lmHPw[i] = 0; 419 ntHPw[i] = 0; 420 } 421 System.arraycopy(encrypt(lmHPw, nonce), 0, lmResponse, 0, 24); 423 System.arraycopy(encrypt(ntHPw, nonce), 0, ntResponse, 0, 24); 424 } catch(ShortBufferException ex) { 425 } catch(IllegalBlockSizeException ex) { 426 } catch(BadPaddingException ex) { 427 } catch(InvalidKeySpecException ex) { 428 } catch(InvalidKeyException ex) { 429 } 430 } 431 432 453 public static byte[] formatRequest(String host, String hostDomain) throws IOException { 454 hostDomain = hostDomain.toUpperCase(); 455 host = host.toUpperCase(); 456 short domainLen = (short)hostDomain.length(); 457 short hostLen = (short)host.length(); 458 short hostOff = 0x20; 459 short domainOff = (short)(hostOff + hostLen); 460 ByteArrayOutputStream os = new ByteArrayOutputStream(1024); 461 DataOutputStream dataOut = new DataOutputStream(os); 462 dataOut.writeBytes("NTLMSSP\0"); 463 dataOut.writeByte(0x01); 464 dataOut.writeByte(0x00); 465 dataOut.writeByte(0x00); 466 dataOut.writeByte(0x00); 467 dataOut.writeShort(swapBytes((short)0xb203)); 468 dataOut.writeShort(0x0000); 469 dataOut.writeShort(swapBytes(domainLen)); 470 dataOut.writeShort(swapBytes(domainLen)); 471 dataOut.writeShort(swapBytes(domainOff)); 472 dataOut.writeShort(0x0000); 473 dataOut.writeShort(swapBytes(hostLen)); 474 dataOut.writeShort(swapBytes(hostLen)); 475 dataOut.writeShort(swapBytes(hostOff)); 476 dataOut.writeShort(0x0000); 477 dataOut.write(host.getBytes()); 478 dataOut.write(hostDomain.getBytes()); 479 dataOut.flush(); 480 return os.toByteArray(); 481 } 482 483 500 public static byte[] getNonce(byte[] msg) throws IllegalArgumentException { 501 if(msg.length < 32) 502 throw new IllegalArgumentException ("msg : illegal size"); 503 byte[] nonce = new byte[8]; 504 System.arraycopy(msg, 24, nonce, 0, 8); 505 return nonce; 506 } 507 508 538 public static byte[] formatResponse(String host, String user, String userDomain, byte[] lmPassword, byte[] ntPassword, byte[] nonce) throws IllegalArgumentException , IOException, NoSuchAlgorithmException, NoSuchPaddingException { 539 if(host == null) 540 throw new IllegalArgumentException ("host : null value not allowed"); 541 if(user == null) 542 throw new IllegalArgumentException ("user : null value not allowed"); 543 if(userDomain == null) 544 throw new IllegalArgumentException ("userDomain : null value not allowed"); 545 if(lmPassword == null) 546 throw new IllegalArgumentException ("lmPassword : null value not allowed"); 547 if(ntPassword == null) 548 throw new IllegalArgumentException ("ntPassword : null value not allowed"); 549 if(nonce == null) 550 throw new IllegalArgumentException ("nonce : null value not allowed"); 551 if(lmPassword.length != 16) 552 throw new IllegalArgumentException ("lmPassword : illegal size"); 553 if(ntPassword.length != 16) 554 throw new IllegalArgumentException ("ntPassword : illegal size"); 555 if(nonce.length != 8) 556 throw new IllegalArgumentException ("nonce : illegal size"); 557 558 byte[] lmResponse = new byte[24]; 559 byte[] ntResponse = new byte[24]; 560 561 computeNTLMResponse(lmPassword, ntPassword, nonce, lmResponse, ntResponse); 562 563 userDomain = userDomain.toUpperCase(); 564 host = host.toUpperCase(); 565 short lmRespLen = (short)0x18; 566 short ntRespLen = (short)0x18; 567 short domainLen = (short)(2 * userDomain.length()); 568 short hostLen = (short)(2 * host.length()); 569 short userLen = (short)(2 * user.length()); 570 short domainOff = (short)0x40; 571 short userOff = (short)(domainOff + domainLen); 572 short hostOff = (short)(userOff + userLen); 573 short lmRespOff = (short)(hostOff + hostLen); 574 short ntRespOff = (short)(lmRespOff + lmRespLen); 575 short msgLen = (short)(ntRespOff + ntRespLen); 576 ByteArrayOutputStream os = new ByteArrayOutputStream(1024); 577 DataOutputStream dataOut = new DataOutputStream(os); 578 dataOut.writeBytes("NTLMSSP\0"); 579 dataOut.writeByte(0x03); 580 dataOut.writeByte(0x00); 581 dataOut.writeByte(0x00); 582 dataOut.writeByte(0x00); 583 dataOut.writeShort(swapBytes(lmRespLen)); 584 dataOut.writeShort(swapBytes(lmRespLen)); 585 dataOut.writeShort(swapBytes(lmRespOff)); 586 dataOut.writeShort(0x0000); 587 dataOut.writeShort(swapBytes(ntRespLen)); 588 dataOut.writeShort(swapBytes(ntRespLen)); 589 dataOut.writeShort(swapBytes(ntRespOff)); 590 dataOut.writeShort(0x0000); 591 dataOut.writeShort(swapBytes(domainLen)); 592 dataOut.writeShort(swapBytes(domainLen)); 593 dataOut.writeShort(swapBytes(domainOff)); 594 dataOut.writeShort(0x0000); 595 dataOut.writeShort(swapBytes(userLen)); 596 dataOut.writeShort(swapBytes(userLen)); 597 dataOut.writeShort(swapBytes(userOff)); 598 dataOut.writeShort(0x0000); 599 dataOut.writeShort(swapBytes(hostLen)); 600 dataOut.writeShort(swapBytes(hostLen)); 601 dataOut.writeShort(swapBytes(hostOff)); 602 dataOut.writeShort(0x0000); 603 dataOut.writeInt(0x00000000); 604 dataOut.writeShort(swapBytes(msgLen)); 605 dataOut.writeShort(0x0000); 606 dataOut.writeShort(0x0000); dataOut.writeShort(0x0000); 608 609 for(int i = 0; i < userDomain.length(); i++) 610 dataOut.writeShort(swapBytes((short)userDomain.charAt(i))); 611 for(int i = 0; i < user.length(); i++) 612 dataOut.writeShort(swapBytes((short)user.charAt(i))); 613 for(int i = 0; i < host.length(); i++) 614 dataOut.writeShort(swapBytes((short)host.charAt(i))); 615 dataOut.write(lmResponse); 616 dataOut.write(ntResponse); 617 dataOut.flush(); 618 return os.toByteArray(); 619 } 620 } 621 | Popular Tags |