1 18 19 package com.Ostermiller.util; 20 21 import java.security.SecureRandom ; 22 import gnu.getopt.*; 23 import java.text.MessageFormat ; 24 import java.util.ResourceBundle ; 25 import java.util.Locale ; 26 import java.util.Vector ; 27 28 48 public class RandPass { 49 50 55 public static final String version = "1.1"; 56 57 62 protected static ResourceBundle labels = ResourceBundle.getBundle("com.Ostermiller.util.RandPass", Locale.getDefault()); 63 64 65 70 private static final int DEFAULT_PASSWORD_LENGTH = 8; 71 72 78 public static final char[] NUMBERS_AND_LETTERS_ALPHABET = { 79 'A','B','C','D','E','F','G','H', 80 'I','J','K','L','M','N','O','P', 81 'Q','R','S','T','U','V','W','X', 82 'Y','Z','a','b','c','d','e','f', 83 'g','h','i','j','k','l','m','n', 84 'o','p','q','r','s','t','u','v', 85 'w','x','y','z','0','1','2','3', 86 '4','5','6','7','8','9', 87 }; 88 89 94 public static final char[] SYMBOLS_ALPHABET = { 95 '!','\"','#','$','%','&','\'','(', 96 ')','*','+',',','-','.','/',':', 97 ';','<','?','@','[','\\',']','^', 98 '_','`','{','|','}','~', 99 }; 100 101 106 public static final char[] PRINTABLE_ALPHABET = { 107 '!','\"','#','$','%','&','\'','(', 108 ')','*','+',',','-','.','/','0', 109 '1','2','3','4','5','6','7','8', 110 '9',':',';','<','?','@','A','B', 111 'C','D','E','F','G','H','I','J', 112 'K','L','M','N','O','P','Q','R', 113 'S','T','U','V','W','X','Y','Z', 114 '[','\\',']','^','_','`','a','b', 115 'c','d','e','f','g','h','i','j', 116 'k','l','m','n','o','p','q','r', 117 's','t','u','v','w','x','y','z', 118 '{','|','}','~', 119 }; 120 121 126 public static final char[] LOWERCASE_LETTERS_ALPHABET = { 127 'a','b','c','d','e','f','g','h', 128 'i','j','k','l','m','n','o','p', 129 'q','r','s','t','u','v','w','x', 130 'y','z', 131 }; 132 133 139 public static final char[] LOWERCASE_LETTERS_AND_NUMBERS_ALPHABET = { 140 'a','b','c','d','e','f','g','h', 141 'i','j','k','l','m','n','o','p', 142 'q','r','s','t','u','v','w','x', 143 'y','z','0','1','2','3','4','5', 144 '6','7','8','9', 145 }; 146 147 152 public static final char[] LETTERS_ALPHABET = { 153 'A','B','C','D','E','F','G','H', 154 'I','J','K','L','M','N','O','P', 155 'Q','R','S','T','U','V','W','X', 156 'Y','Z','a','b','c','d','e','f', 157 'g','h','i','j','k','l','m','n', 158 'o','p','q','r','s','t','u','v', 159 'w','x','y','z', 160 }; 161 162 167 public static final char[] UPPERCASE_LETTERS_ALPHABET = { 168 'A','B','C','D','E','F','G','H', 169 'I','J','K','L','M','N','O','P', 170 'Q','R','S','T','U','V','W','X', 171 'Y','Z', 172 }; 173 174 181 public static final char[] NONCONFUSING_ALPHABET = { 182 'A','B','C','D','E','F','G','H', 183 'J','K','M','N','P','Q','R','S', 184 'T','W','X','Y','Z','a','b','c', 185 'd','e','f','g','h','j','k','m', 186 'n','p','q','r','s','t','w','x', 187 'y','z','2','3','4','5','6','7', 188 '8','9', 189 }; 190 191 196 protected SecureRandom rand; 197 198 205 protected int repetition = -1; 206 207 216 protected char[] alphabet; 217 218 228 protected char[] firstAlphabet; 229 230 240 protected char[] lastAlphabet; 241 242 249 public RandPass(){ 250 this(new SecureRandom (), NONCONFUSING_ALPHABET); 251 } 252 253 262 public RandPass(SecureRandom rand){ 263 this(rand, NONCONFUSING_ALPHABET); 264 } 265 266 275 public RandPass(char[] alphabet){ 276 this(new SecureRandom (), alphabet); 277 } 278 279 289 public RandPass(SecureRandom rand, char[] alphabet){ 290 this.rand = rand; 291 this.alphabet = alphabet; 292 } 293 294 private class Requirement { 295 public Requirement(char[] alphabet, int num){ 296 this.alphabet = alphabet; 297 this.num = num; 298 } 299 public char[] alphabet; 300 public int num; 301 } 302 303 311 public static void main(String [] args) throws Exception { 312 LongOpt[] longopts = { 314 new LongOpt(labels.getString("help.option"), LongOpt.NO_ARGUMENT, null, 1), 315 new LongOpt(labels.getString("version.option"), LongOpt.NO_ARGUMENT, null, 2), 316 new LongOpt(labels.getString("about.option"), LongOpt.NO_ARGUMENT, null, 3), 317 new LongOpt(labels.getString("alphabet.option"), LongOpt.REQUIRED_ARGUMENT, null, 'a'), 318 new LongOpt(labels.getString("first.alphabet.option"), LongOpt.REQUIRED_ARGUMENT, null, 'F'), 319 new LongOpt(labels.getString("last.alphabet.option"), LongOpt.REQUIRED_ARGUMENT, null, 'L'), 320 new LongOpt(labels.getString("number.option"), LongOpt.REQUIRED_ARGUMENT, null, 'n'), 321 new LongOpt(labels.getString("maxrep.option"), LongOpt.REQUIRED_ARGUMENT, null, 'r'), 322 new LongOpt(labels.getString("length.option"), LongOpt.REQUIRED_ARGUMENT, null, 'l'), 323 new LongOpt(labels.getString("require.option"), LongOpt.REQUIRED_ARGUMENT, null, 'R'), 324 new LongOpt(labels.getString("verify.option"), LongOpt.REQUIRED_ARGUMENT, null, 'v'), 325 }; 326 String oneLetterOptions = "a:n:F:L:r:l:R:v:"; 327 Getopt opts = new Getopt(labels.getString("randpass"), args, oneLetterOptions, longopts); 328 int number = 1; 329 char[] alphabet = NONCONFUSING_ALPHABET; 330 char[] firstAlphabet = null; 331 char[] lastAlphabet = null; 332 Vector <String > reqs = new Vector <String >(); 333 Vector <String > ver = new Vector <String >(); 334 int maxreps = 0; 335 int length = 8; 336 int c; 337 while ((c = opts.getopt()) != -1){ 338 switch(c){ 339 case 1:{ 340 String [] helpFlags = new String []{ 342 "--" + labels.getString("help.option"), 343 "--" + labels.getString("version.option"), 344 "--" + labels.getString("about.option"), 345 "-a --" + labels.getString("alphabet.option") + " " + labels.getString("alphabet.argument"), 346 "-n --" + labels.getString("number.option") + " " + labels.getString("number.argument"), 347 "-F --" + labels.getString("first.alphabet.option") + " " + labels.getString("alphabet.argument"), 348 "-L --" + labels.getString("last.alphabet.option") + " " + labels.getString("alphabet.argument"), 349 "-l --" + labels.getString("length.option") + " " + labels.getString("number.argument"), 350 "-r --" + labels.getString("maxrep.option") + " " + labels.getString("number.argument"), 351 "-R --" + labels.getString("require.option") + " " + labels.getString("alphabet.argument"), 352 "-v --" + labels.getString("verify.option") + " " + labels.getString("class.argument"), 353 }; 354 int maxLength = 0; 355 for (int i=0; i<helpFlags.length; i++){ 356 maxLength = Math.max(maxLength, helpFlags[i].length()); 357 } 358 maxLength += 2; 359 System.out.println( 360 labels.getString("randpass") + " [-" + StringHelper.replace(oneLetterOptions, ":", "") + "]\n" + 361 labels.getString("purpose.message") + "\n" + 362 " " + StringHelper.postpad(helpFlags[0] ,maxLength, ' ') + labels.getString("help.message") + "\n" + 363 " " + StringHelper.postpad(helpFlags[1] ,maxLength, ' ') + labels.getString("version.message") + "\n" + 364 " " + StringHelper.postpad(helpFlags[2] ,maxLength, ' ') + labels.getString("about.message") + "\n" + 365 " " + StringHelper.postpad(helpFlags[3] ,maxLength, ' ') + labels.getString("a.message") + "\n" + 366 " " + StringHelper.postpad(helpFlags[4] ,maxLength, ' ') + labels.getString("n.message") + "\n" + 367 " " + StringHelper.postpad(helpFlags[5] ,maxLength, ' ') + labels.getString("F.message") + "\n" + 368 " " + StringHelper.postpad(helpFlags[6] ,maxLength, ' ') + labels.getString("L.message") + "\n" + 369 " " + StringHelper.postpad(helpFlags[7] ,maxLength, ' ') + labels.getString("l.message") + "\n" + 370 " " + StringHelper.postpad(helpFlags[8] ,maxLength, ' ') + labels.getString("r.message") + "\n" + 371 " " + StringHelper.postpad(helpFlags[9] ,maxLength, ' ') + labels.getString("R.message") + "\n" + 372 " " + StringHelper.postpad(helpFlags[10] ,maxLength, ' ') + labels.getString("v.message") + "\n" 373 ); 374 System.exit(0); 375 } break; 376 case 2:{ 377 System.out.println(MessageFormat.format(labels.getString("version"), (Object [])new String [] {version})); 379 System.exit(0); 380 } break; 381 case 3:{ 382 System.out.println( 383 labels.getString("randpass") + " -- " + labels.getString("purpose.message") + "\n" + 384 MessageFormat.format(labels.getString("copyright"), (Object [])new String [] {"2001-2002", "Stephen Ostermiller (http://ostermiller.org/contact.pl?regarding=Java+Utilities)"}) + "\n\n" + 385 labels.getString("license") 386 ); 387 System.exit(0); 388 } break; 389 case 'a':{ 390 String alph = opts.getOptarg(); 391 if (alph.length() == 0){ 392 alphabet = NONCONFUSING_ALPHABET; 393 } else { 394 alphabet = alph.toCharArray(); 395 } 396 } break; 397 case 'F':{ 398 String alph = opts.getOptarg(); 399 if (alph.length() == 0){ 400 firstAlphabet = null; 401 } else { 402 firstAlphabet = alph.toCharArray(); 403 } 404 } break; 405 case 'L':{ 406 String alph = opts.getOptarg(); 407 if (alph.length() == 0){ 408 lastAlphabet = null; 409 } else { 410 lastAlphabet = alph.toCharArray(); 411 } 412 } break; 413 case 'R':{ 414 String alph = opts.getOptarg(); 415 if (alph.length() != 0){ 416 reqs.add(alph); 417 } 418 } break; 419 case 'v':{ 420 ver.add(opts.getOptarg()); 421 } break; 422 case 'n':{ 423 try { 424 number = Integer.parseInt(opts.getOptarg()); 425 if (number <= 0) throw new NumberFormatException (); 426 } catch (NumberFormatException nfe){ 427 System.err.println(labels.getString("number.bad_argument")); 428 System.exit(0); 429 } 430 } break; 431 case 'r':{ 432 try { 433 maxreps = Integer.parseInt(opts.getOptarg()); 434 if (maxreps < 0) throw new NumberFormatException (); 435 } catch (NumberFormatException nfe){ 436 System.err.println(labels.getString("number.bad_argument")); 437 System.exit(0); 438 } 439 } break; 440 case 'l':{ 441 try { 442 length = Integer.parseInt(opts.getOptarg()); 443 if (length < 0) throw new NumberFormatException (); 444 } catch (NumberFormatException nfe){ 445 System.err.println(labels.getString("number.bad_argument")); 446 System.exit(0); 447 } 448 } break; 449 default:{ 450 System.exit(0); 451 } 452 } 453 } 454 RandPass randPass = new RandPass(); 455 randPass.setAlphabet(alphabet); 456 randPass.setFirstAlphabet(firstAlphabet); 457 randPass.setLastAlphabet(lastAlphabet); 458 randPass.setMaxRepetition(maxreps); 459 for (int i=0; i<reqs.size(); i++){ 460 randPass.addRequirement(((String )(reqs.elementAt(i))).toCharArray(), 1); 461 } 462 for (int i=0; i<ver.size(); i++){ 463 randPass.addVerifier((PasswordVerifier)((Class.forName((String )(ver.elementAt(i)))).newInstance())); 464 } 465 for (int i=0; i<number; i++){ 466 System.out.println(randPass.getPass(length)); 467 } 468 } 469 470 471 private Vector <Requirement> requirements = null; 472 473 482 public void addRequirement(char[] alphabet, int num){ 483 if (requirements == null) requirements = new Vector <Requirement>(); 484 requirements.add(new Requirement(alphabet, num)); 485 } 486 487 488 497 public void setAlphabet(char[] alphabet){ 498 if (alphabet == null) throw new NullPointerException ("Null alphabet"); 499 if (alphabet.length == 0) throw new ArrayIndexOutOfBoundsException ("No characters in alphabet"); 500 this.alphabet = alphabet; 501 } 502 503 510 public void setRandomGenerator(SecureRandom rand){ 511 this.rand = rand; 512 } 513 514 525 public void setFirstAlphabet(char[] alphabet){ 526 if (alphabet == null || alphabet.length == 0){ 527 this.firstAlphabet = null; 528 } else { 529 this.firstAlphabet = alphabet; 530 } 531 } 532 533 544 public void setLastAlphabet(char[] alphabet){ 545 if (alphabet == null || alphabet.length == 0){ 546 this.lastAlphabet = null; 547 } else { 548 this.lastAlphabet = alphabet; 549 } 550 } 551 552 570 public void setMaxRepetition(int rep){ 571 this.repetition = rep - 1; 572 } 573 574 590 public char[] getPassChars(char[] pass){ 591 boolean verified = false; 592 while (!verified){ 593 int length = pass.length; 594 for (int i=0; i<length; i++){ 595 char[] useAlph = alphabet; 596 if (i == 0 && firstAlphabet != null){ 597 useAlph = firstAlphabet; 598 } else if (i == length - 1 && lastAlphabet != null){ 599 useAlph = lastAlphabet; 600 } 601 int size = avoidRepetition(useAlph, pass, i, repetition, useAlph.length); 602 pass[i] = useAlph[rand.nextInt(size)]; 603 } 604 if (requirements != null) applyRequirements(pass); 605 verified = true; 606 for (int i=0; verified && verifiers != null && i<verifiers.size(); i++){ 607 verified = ((PasswordVerifier)verifiers.elementAt(i)).verify(pass); 608 } 609 } 610 return(pass); 611 } 612 613 private Vector <PasswordVerifier> verifiers = null; 614 615 623 public void addVerifier(PasswordVerifier verifier){ 624 if (verifiers == null) verifiers = new Vector <PasswordVerifier>(); 625 verifiers.add(verifier); 626 } 627 628 private boolean[] touched = null; 629 private int[] available = null; 630 631 private void applyRequirements(char[] pass){ 632 int size = requirements.size(); 633 if (size > 0){ 634 int length = pass.length; 635 if (touched == null || touched.length < length) touched = new boolean[length]; 636 if (available == null || available.length < length) available = new int[length]; 637 for (int i=0; i<length; i++){ 638 touched[i] = false; 639 } 640 for (int reqNum=0; reqNum<size; reqNum++){ 641 Requirement req = (Requirement)requirements.elementAt(reqNum); 642 int reqUsedInd = req.alphabet.length; 644 int fufilledInd = 0; 647 int availableInd = 0; 648 for (int i=0; i<length; i++){ 649 if (arrayContains(req.alphabet, pass[i]) && fufilledInd < req.num){ 650 fufilledInd++; 651 touched[i] = true; 652 if (repetition >= 0){ 653 reqUsedInd -= moveto(req.alphabet, reqUsedInd, pass[i]); 656 if(reqUsedInd < 0) reqUsedInd = req.alphabet.length; 658 } 659 } else if (!touched[i]){ 660 available[availableInd] = i; 661 availableInd++; 662 } 663 } 664 int toDo = req.num - fufilledInd; 666 for (int i=0; i<toDo && availableInd>0; i++){ 667 int slot = rand.nextInt(availableInd); 670 char passChar = req.alphabet[rand.nextInt(reqUsedInd)]; 671 pass[available[slot]] = passChar; 672 touched[available[slot]] = true; 673 availableInd--; 675 available[slot] = available[availableInd]; 676 if (repetition >= 0){ 677 reqUsedInd -= moveto(req.alphabet, reqUsedInd, passChar); 680 if(reqUsedInd < 0) reqUsedInd = req.alphabet.length; 682 } 683 } 684 } 685 } 686 } 687 688 private static boolean arrayContains(char[] alph, char c){ 689 for (int i=0; i<alph.length; i++){ 690 if (alph[i] == c) return true; 691 } 692 return false; 693 } 694 695 701 private static int avoidRepetition(char[] alph, char[] pass, int passSize, int repetition, int alphSize){ 702 if (repetition > -1){ 703 int repPos = 0; 706 while ((repPos = findRep(pass, repPos, passSize, repetition)) != -1){ 707 alphSize -= moveto(alph, alphSize, pass[repPos+repetition]); 711 repPos++; 712 } 713 if (alphSize == 0) alphSize = alph.length; 714 } 715 return alphSize; 716 } 717 718 724 private static int findRep(char[] pass, int start, int end, int length){ 725 for (int i=start; i<end-length; i++){ 726 boolean onTrack = true; 727 for (int j=0; onTrack && j<length; j++){ 728 if (pass[i+j] != pass[end-length+j]) onTrack = false; 729 } 730 if(onTrack) return i; 731 } 732 return -1; 733 } 734 735 741 private static int moveto(char[] alph, int numGood, char c){ 742 int count = 0; 743 for (int i=0; i<numGood; i++){ 744 if (alph[i] == c){ 745 numGood--; 746 char temp = alph[numGood]; 747 alph[numGood] = alph[i]; 748 alph[i] = temp; 749 count++; 750 } 751 } 752 return count; 753 } 754 755 767 public char[] getPassChars(int length){ 768 return(getPassChars(new char[length])); 769 } 770 771 782 public char[] getPassChars(){ 783 return(getPassChars(DEFAULT_PASSWORD_LENGTH)); 784 } 785 786 800 public String getPass(int length){ 801 return(new String (getPassChars(new char[length]))); 802 } 803 804 817 public String getPass(){ 818 return(getPass(DEFAULT_PASSWORD_LENGTH)); 819 } 820 } 821 | Popular Tags |