KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > Ostermiller > util > RandPass


1 /*
2  * Generate random passwords.
3  * Copyright (C) 2001-2002 Stephen Ostermiller
4  * http://ostermiller.org/contact.pl?regarding=Java+Utilities
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * See COPYING.TXT for details.
17  */

18
19 package com.Ostermiller.util;
20
21 import java.security.SecureRandom JavaDoc;
22 import gnu.getopt.*;
23 import java.text.MessageFormat JavaDoc;
24 import java.util.ResourceBundle JavaDoc;
25 import java.util.Locale JavaDoc;
26 import java.util.Vector JavaDoc;
27
28 /**
29  * Generates a random String using a cryptographically
30  * secure random number generator.
31  * <p>
32  * The alphabet (characters used in the passwords generated)
33  * may be specified, and the random number generator can be
34  * externally supplied.
35  * <p>
36  * Care should be taken when using methods that limit the types
37  * of passwords may be generated. Using an alphabet that is too
38  * small, using passwords that are too short, requiring too many
39  * of a certain type of character, or not allowing repetition,
40  * may decrease security.
41  * <p>
42  * More information about this class is available from <a target="_top" HREF=
43  * "http://ostermiller.org/utils/RandPass.html">ostermiller.org</a>.
44  *
45  * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
46  * @since ostermillerutils 1.00.00
47  */

48 public class RandPass {
49
50     /**
51      * Version number of this program
52      *
53      * @since ostermillerutils 1.00.00
54      */

55     public static final String JavaDoc version = "1.1";
56
57     /**
58      * Locale specific strings displayed to the user.
59      *
60      * @since ostermillerutils 1.00.00
61      */

62     protected static ResourceBundle JavaDoc labels = ResourceBundle.getBundle("com.Ostermiller.util.RandPass", Locale.getDefault());
63
64
65     /**
66      * Default length for passwords
67      *
68      * @since ostermillerutils 1.00.00
69      */

70     private static final int DEFAULT_PASSWORD_LENGTH = 8;
71
72     /**
73      * Alphabet consisting of upper and lowercase letters A-Z and
74      * the digits 0-9.
75      *
76      * @since ostermillerutils 1.00.00
77      */

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     /**
90      * Alphabet consisting of all the printable ASCII symbols.
91      *
92      * @since ostermillerutils 1.00.00
93      */

94     public static final char[] SYMBOLS_ALPHABET = {
95         '!','\"','#','$','%','&','\'','(',
96         ')','*','+',',','-','.','/',':',
97         ';','<','?','@','[','\\',']','^',
98         '_','`','{','|','}','~',
99     };
100
101     /**
102      * Alphabet consisting of all the printable ASCII characters.
103      *
104      * @since ostermillerutils 1.00.00
105      */

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     /**
122      * Alphabet consisting of the lowercase letters A-Z.
123      *
124      * @since ostermillerutils 1.00.00
125      */

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     /**
134      * Alphabet consisting of the lowercase letters A-Z and
135      * the digits 0-9.
136      *
137      * @since ostermillerutils 1.00.00
138      */

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     /**
148      * Alphabet consisting of upper and lowercase letters A-Z.
149      *
150      * @since ostermillerutils 1.00.00
151      */

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     /**
163      * Alphabet consisting of the upper letters A-Z.
164      *
165      * @since ostermillerutils 1.00.00
166      */

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     /**
175      * Alphabet consisting of upper and lowercase letters A-Z and
176      * the digits 0-9 but with characters that are often mistaken
177      * for each other when typed removed. (I,L,O,U,V,i,l,o,u,v,0,1)
178      *
179      * @since ostermillerutils 1.00.00
180      */

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     /**
192      * Random number generator used.
193      *
194      * @since ostermillerutils 1.00.00
195      */

196     protected SecureRandom JavaDoc rand;
197
198     /**
199      * One less than the maximum number of repeated characters
200      * that are allowed in a password.
201      * Set to -1 to disable this feature.
202      *
203      * @since ostermillerutils 1.00.00
204      */

205     protected int repetition = -1;
206
207     /**
208      * Set of characters which may be
209      * used in the generated passwords.
210      * <p>
211      * This value may not be null or have
212      * no elements.
213      *
214      * @since ostermillerutils 1.00.00
215      */

216     protected char[] alphabet;
217
218     /**
219      * Set of characters which may be
220      * used for the first character
221      * in the generated passwords.
222      * <p>
223      * This value may be null but it mus
224      * have at least one element otherwise.
225      *
226      * @since ostermillerutils 1.00.00
227      */

228     protected char[] firstAlphabet;
229
230     /**
231      * Set of characters which may be
232      * used for the last character
233      * in the generated passwords.
234      * <p>
235      * This value may be null but it mus
236      * have at least one element otherwise.
237      *
238      * @since ostermillerutils 1.00.00
239      */

240     protected char[] lastAlphabet;
241
242     /**
243      * Create a new random password generator
244      * with the default secure random number generator
245      * and default NONCONFUSING alphabet for all characters.
246      *
247      * @since ostermillerutils 1.00.00
248      */

249     public RandPass(){
250         this(new SecureRandom JavaDoc(), NONCONFUSING_ALPHABET);
251     }
252
253     /**
254      * Create a new random password generator
255      * with the given secure random number generator
256      * and default NONCONFUSING alphabet for all characters.
257      *
258      * @param rand Secure random number generator to use when generating passwords.
259      *
260      * @since ostermillerutils 1.00.00
261      */

262     public RandPass(SecureRandom JavaDoc rand){
263         this(rand, NONCONFUSING_ALPHABET);
264     }
265
266     /**
267      * Create a new random password generator
268      * with the default secure random number generator
269      * and given alphabet for all characters.
270      *
271      * @param alphabet Characters allowed in generated passwords.
272      *
273      * @since ostermillerutils 1.00.00
274      */

275     public RandPass(char[] alphabet){
276         this(new SecureRandom JavaDoc(), alphabet);
277     }
278
279     /**
280      * Create a new random password generator
281      * with the given secure random number generator
282      * and given alphabet for all characters.
283      *
284      * @param rand Secure random number generator to use when generating passwords.
285      * @param alphabet Characters allowed in generated passwords.
286      *
287      * @since ostermillerutils 1.00.00
288      */

289     public RandPass(SecureRandom JavaDoc 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     /**
304      * Generate a random passwords.
305      * Run with --help argument for more information.
306      *
307      * @param args Command line arguments.
308      *
309      * @since ostermillerutils 1.00.00
310      */

311     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
312         // create the command line options that we are looking for
313
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 JavaDoc 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 JavaDoc<String JavaDoc> reqs = new Vector JavaDoc<String JavaDoc>();
333         Vector JavaDoc<String JavaDoc> ver = new Vector JavaDoc<String JavaDoc>();
334         int maxreps = 0;
335         int length = 8;
336         int c;
337         while ((c = opts.getopt()) != -1){
338             switch(c){
339                 case 1:{
340                     // print out the help message
341
String JavaDoc[] helpFlags = new String JavaDoc[]{
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                     // print out the version message
378
System.out.println(MessageFormat.format(labels.getString("version"), (Object JavaDoc[])new String JavaDoc[] {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 JavaDoc[])new String JavaDoc[] {"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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc();
426                     } catch (NumberFormatException JavaDoc 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 JavaDoc();
435                     } catch (NumberFormatException JavaDoc 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 JavaDoc();
444                     } catch (NumberFormatException JavaDoc 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 JavaDoc)(reqs.elementAt(i))).toCharArray(), 1);
461         }
462         for (int i=0; i<ver.size(); i++){
463             randPass.addVerifier((PasswordVerifier)((Class.forName((String JavaDoc)(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 JavaDoc<Requirement> requirements = null;
472
473     /**
474      * Require that a certain number of characters from an
475      * alphabet be present in generated passwords.
476      *
477      * @param alphabet set of letters that must be present
478      * @param num number of letters from the alphabet that must be present.
479      *
480      * @since ostermillerutils 1.00.00
481      */

482     public void addRequirement(char[] alphabet, int num){
483         if (requirements == null) requirements = new Vector JavaDoc<Requirement>();
484         requirements.add(new Requirement(alphabet, num));
485     }
486
487
488     /**
489      * Set the alphabet used by this random password generator.
490      *
491      * @param alphabet Characters allowed in generated passwords.
492      * @throws NullPointerException if the alphabet is null.
493      * @throws ArrayIndexOutOfBoundsException if the alphabet has no elements.
494      *
495      * @since ostermillerutils 1.00.00
496      */

497     public void setAlphabet(char[] alphabet){
498         if (alphabet == null) throw new NullPointerException JavaDoc("Null alphabet");
499         if (alphabet.length == 0) throw new ArrayIndexOutOfBoundsException JavaDoc("No characters in alphabet");
500         this.alphabet = alphabet;
501     }
502
503     /**
504      * Set the random number generator used by this random password generator.
505      *
506      * @param rand Secure random number generator to use when generating passwords.
507      *
508      * @since ostermillerutils 1.00.00
509      */

510     public void setRandomGenerator(SecureRandom JavaDoc rand){
511         this.rand = rand;
512     }
513
514     /**
515      * Set the alphabet used by this random password generator for the first character
516      * of passwords.
517      * <p>
518      * If the alphabet for the first character is set to null or has no elements, the main alphabet will
519      * be used for the first character.
520      *
521      * @param alphabet Characters allowed for the first character of the passwords.
522      *
523      * @since ostermillerutils 1.00.00
524      */

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     /**
534      * Set the alphabet used by this random password generator for the last character
535      * of passwords.
536      * <p>
537      * If the alphabet for the last character is set to null or has no elements, the main alphabet will
538      * be used for the last character.
539      *
540      * @param alphabet Characters allowed for the last character of the passwords.
541      *
542      * @since ostermillerutils 1.00.00
543      */

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     /**
553      * Set the maximum number of characters that may appear in sequence more than
554      * once in a password. Your alphabet must be large enough to handle this
555      * option. If your alphabet is {'a', 'b'} and you want 8 character passwords
556      * in which no character appears twice (repetition 1) you are out of luck.
557      * In such instances your request for no repetition will be ignored.
558      * <p>
559      * For example setRepetition(3) will allow a password ababab but not allow
560      * abcabc.
561      * <p>
562      * Using this method can greatly reduce the pool of passwords that are generated.
563      * For example if only one repetition is allowed then the pool of passwords
564      * is the permutation of the alphabet rather than the combination.
565      *
566      * @param rep Maximum character repetition.
567      *
568      * @since ostermillerutils 1.00.00
569      */

570     public void setMaxRepetition(int rep){
571         this.repetition = rep - 1;
572     }
573
574     /**
575      * Fill the given buffer with random characters.
576      * <p>
577      * Using this method, the password character array can easily
578      * be reused for efficiency, or overwritten with new random
579      * characters for security.
580      * <p>
581      * NOTE: If it is possible for a hacker to examine memory to find passwords,
582      * the password should be overwritten in memory as soon as possible after i
583      * is no longer in use.
584      *
585      * @param pass buffer that will hold the password.
586      * @return the buffer, filled with random characters.
587      *
588      * @since ostermillerutils 1.00.00
589      */

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 JavaDoc<PasswordVerifier> verifiers = null;
614
615     /**
616      * Add a class that will verify passwords. No password
617      * will be returned unless all verifiers approve of it.
618      *
619      * @param verifier class that performs verification of password.
620      *
621      * @since ostermillerutils 1.00.00
622      */

623     public void addVerifier(PasswordVerifier verifier){
624         if (verifiers == null) verifiers = new Vector JavaDoc<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                 // set the portion of this alphabet available for use.
643
int reqUsedInd = req.alphabet.length;
644                 // figure out how much of this requirement is already fulfilled
645
// and what is available to fulfill the rest of it.
646
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                             // move already used characters so they can'
654
// be used again. This prevents repetition.
655
reqUsedInd -= moveto(req.alphabet, reqUsedInd, pass[i]);
656                             // allow repetition if we have no other choice
657
if(reqUsedInd < 0) reqUsedInd = req.alphabet.length;
658                         }
659                     } else if (!touched[i]){
660                         available[availableInd] = i;
661                         availableInd++;
662                     }
663                 }
664                 // fulfill the requirement
665
int toDo = req.num - fufilledInd;
666                 for (int i=0; i<toDo && availableInd>0; i++){
667                     // pick a random available slot
668
// and a random member of the available alphabet
669
int slot = rand.nextInt(availableInd);
670                     char passChar = req.alphabet[rand.nextInt(reqUsedInd)];
671                     pass[available[slot]] = passChar;
672                     touched[available[slot]] = true;
673                     // make the slot no longer available
674
availableInd--;
675                     available[slot] = available[availableInd];
676                     if (repetition >= 0){
677                         // move already used characters so they can'
678
// be used again. This prevents repetition.
679
reqUsedInd -= moveto(req.alphabet, reqUsedInd, passChar);
680                         // allow repetition if we have no other choice
681
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     /**
696      * Avoid repetition (if possible) by moving all characters that would cause repetition to
697      * the end of the alphabet and returning the size of the alphabet that may be used.
698      *
699      * @since ostermillerutils 1.00.00
700      */

701     private static int avoidRepetition(char[] alph, char[] pass, int passSize, int repetition, int alphSize){
702         if (repetition > -1){
703             // limit the alphabet to those characters that
704
// will not cause repeating sequences
705
int repPos = 0;
706             while ((repPos = findRep(pass, repPos, passSize, repetition)) != -1){
707                 // shuffle characters that would cause repetition
708
// to the end of the alphabet and adjust the size
709
// so that they will not be used.
710
alphSize -= moveto(alph, alphSize, pass[repPos+repetition]);
711                 repPos++;
712             }
713             if (alphSize == 0) alphSize = alph.length;
714         }
715         return alphSize;
716     }
717
718     /**
719      * Find a repetition of the desired length. The characters to search
720      * for are located at pass[end-length] to pass[end]
721      *
722      * @since ostermillerutils 1.00.00
723      */

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     /**
736      * move all of the given character to the end of the array
737      * and return the number of characters moved.
738      *
739      * @since ostermillerutils 1.00.00
740      */

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     /**
756      * Generate a random password of the given length.
757      * <p>
758      * NOTE: If it is possible for a hacker to examine memory to find passwords,
759      * the password should be overwritten in memory as soon as possible after i
760      * is no longer in use.
761      *
762      * @param length The desired length of the generated password.
763      * @return a random password
764      *
765      * @since ostermillerutils 1.00.00
766      */

767     public char[] getPassChars(int length){
768         return(getPassChars(new char[length]));
769     }
770
771     /**
772      * Generate a random password of the default length (8).
773      * <p>
774      * NOTE: If it is possible for a hacker to examine memory to find passwords,
775      * the password should be overwritten in memory as soon as possible after i
776      * is no longer in use.
777      *
778      * @return a random password
779      *
780      * @since ostermillerutils 1.00.00
781      */

782     public char[] getPassChars(){
783         return(getPassChars(DEFAULT_PASSWORD_LENGTH));
784     }
785
786     /**
787      * Generate a random password of the given length.
788      * <p>
789      * NOTE: Strings can not be modified. If it is possible
790      * for a hacker to examine memory to find passwords, getPassChars()
791      * should be used so that the password can be zeroed out of memory
792      * when no longer in use.
793      *
794      * @param length The desired length of the generated password.
795      * @return a random password
796      *
797      * @see #getPassChars(int)
798      * @since ostermillerutils 1.00.00
799      */

800     public String JavaDoc getPass(int length){
801         return(new String JavaDoc(getPassChars(new char[length])));
802     }
803
804     /**
805      * Generate a random password of the default length (8).
806      * <p>
807      * NOTE: Strings can not be modified. If it is possible
808      * for a hacker to examine memory to find passwords, getPassChars()
809      * should be used so that the password can be zeroed out of memory
810      * when no longer in use.
811      *
812      * @return a random password
813      *
814      * @see #getPassChars()
815      * @since ostermillerutils 1.00.00
816      */

817     public String JavaDoc getPass(){
818         return(getPass(DEFAULT_PASSWORD_LENGTH));
819     }
820 }
821
Popular Tags