001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010:
011: package org.mmbase.util;
012:
013: import org.mmbase.util.logging.Logger;
014: import org.mmbase.util.logging.Logging;
015:
016: /**
017: * Module for the automatic generation of passwords.
018: * Based on the code of Arnold G. Reinhold, Cambridge, MA, USA.
019: * This code is under the GNU License as specified by the original author.
020: * <br />
021: * The passwords generated by this class are based on a template.
022: * A template can exists of a number of characters, which are replaced by
023: * the generator as follows:<br />
024: * A : is replaced by a random letter (a - z).<br />
025: * C : is replaced by a random alphanumeric character (0-9, a-z)<br />
026: * H : is replaced by a random hex character (0-9,A-F)<br />
027: * S : is replaced by a random syllable. This, alterating, an element from a set of
028: * consonants or an element form a set of vowels. A syllable can be more than
029: * one character (i.e. "qu").<br />
030: * 6 : is replaced by a random dice-roll (1-6)<br />
031: * 9 : is replaced by a random digit (0-9)<br />
032: * <br />
033: *
034: * @license uses the GNU license, should be moved external
035: * @author Rico Jansen
036: * @author Pierre van Rooden (javadocs)
037: * @version $Id: PasswordGenerator.java,v 1.13 2007/10/26 11:09:55 michiel Exp $
038: */
039:
040: public class PasswordGenerator implements PasswordGeneratorInterface {
041:
042: private static final Logger log = Logging
043: .getLoggerInstance(PasswordGenerator.class);
044:
045: /**
046: * List of consonants that can be used in a password.
047: */
048: private static String consonants[] = { "b", "c", "d", "f", "g",
049: "h", "j", "k", "l", "m", "n", "p", "qu", "r", "s", "t",
050: "v", "w", "x", "z", "ch", "cr", "fr", "nd", "ng", "nk",
051: "nt", "ph", "pr", "rd", "sh", "sl", "sp", "st", "th", "tr" };
052:
053: /**
054: * List of vowels that can be used in a password.
055: */
056: private static String vowels[] = { "a", "e", "i", "o", "u", "y" };
057:
058: /**
059: * Pool of random numbers.
060: */
061: RandomPool ranPool;
062:
063: /**
064: * Default template to use when generating passwords.
065: */
066: String defaulttemplate = "SSSSSS";
067:
068: /**
069: * Creates the generator
070: */
071: public PasswordGenerator() {
072: ranPool = new RandomPool();
073: }
074:
075: /**
076: * Entry point when calling from teh command line.
077: * Used for testing.
078: */
079: public static void main(String args[]) {
080: PasswordGenerator PG = new PasswordGenerator();
081: log.info("Password " + PG.getPassword());
082: log.info("Password " + PG.getPassword("SSS 9 SSS"));
083: log.info("Password " + PG.getPassword("SSSS"));
084: log.info("Password " + PG.getPassword("SSSSS"));
085: log.info("Password " + PG.getPassword("SSSSSS"));
086: log.info("Password " + PG.getPassword("CCC CCC CCC"));
087: log.info("Password " + PG.getPassword("HHHH HHHH HHHH"));
088: log.info("Password " + PG.getPassword("AAAAA AAAAA AAAAA"));
089: log.info("Password " + PG.getPassword("99999 99999 99999"));
090: log.info("Password " + PG.getPassword("66666 66666 66666"));
091: }
092:
093: /**
094: * Returns the positive modulus of the arguments.
095: * @param x the argument to modulate
096: * @param y the argument to modulate with
097: * @return the positive modulus of x modulus y.
098: */
099: private int mod(long x, long y) {
100: if (x < 0)
101: x = -x;
102: if (y < 0)
103: y = -y;
104: return (int) (x % y);
105: }
106:
107: /**
108: * Generate a password, based on the default template for this module.
109: * @return the generated password.
110: */
111: public String getPassword() {
112: return getPassword(defaulttemplate);
113: }
114:
115: /**
116: * Generate a password, based on the given template.
117: * @param template the template the password should be based on.
118: * @return the generated password.
119: */
120: public String getPassword(
121: @org.mmbase.util.functions.Name("template")
122: String template) {
123: int len;
124: boolean next = true;
125: StringBuilder pwd = new StringBuilder();
126:
127: len = template.length();
128: for (int i = 0; i < len; i++) {
129: ranPool.stir(i * 93762 + 49104); // Increasing value
130: next = addChar(pwd, template, i, next);
131: }
132: return pwd.toString();
133: }
134:
135: /**
136: * Add a random character to the password as specified by the template.
137: * @param password the <code>StringBuffer</code> containing the password to add a new character to
138: * @param template template to use when generating the password
139: * @param ntmpl index in the template indicating the template character to use
140: * @param consonantNext if <code>true</code>, the 'S' template character will
141: * return a consonant. otherwise it will return a vowel.
142: * @return <code>false</code> if the value returned was a conmsonant generated by the 'S'
143: * template character, otherwise <code>true</code>.
144: */
145: private boolean addChar(StringBuilder password, String template,
146: int ntmpl, boolean consonantNext) {
147: int ch = 0;
148: char tmplChar;
149: String charsOut = null;
150:
151: if (ntmpl >= template.length()) {
152: consonantNext = true;
153: return consonantNext;
154: }
155: tmplChar = template.charAt(ntmpl);
156:
157: if (tmplChar == ' ') {
158: ch = ' ';
159:
160: } else if (tmplChar == 'A') { //random letter
161: ch = mod(ranPool.value(), 26) + (int) 'a';
162:
163: } else if (tmplChar == 'C') { //random alphanumeric [0-9,A-Z]
164: ch = mod(ranPool.value(), 36);
165: if (ch < 10)
166: ch = ch + (int) '0';
167: else
168: ch = ch + (int) 'a' - 10;
169:
170: } else if (tmplChar == 'H') { //random hex digit
171: ch = mod(ranPool.value(), 16);
172: if (ch < 10)
173: ch = ch + (int) '0';
174: else
175: ch = ch + (int) 'a' - 10;
176:
177: } else if (tmplChar == 'S') { //random syllable
178: if (consonantNext) {
179: charsOut = consonants[mod(ranPool.value(),
180: consonants.length)];
181: if (!"qu".equals(charsOut))
182: consonantNext = false;
183: } else {
184: charsOut = vowels[mod(ranPool.value(), vowels.length)];
185: consonantNext = true;
186: }
187:
188: } else if (tmplChar == '6') { //random dice throw
189: ch = mod(ranPool.value(), 6) + (int) '1';
190:
191: } else if (tmplChar == '9') { //random digit
192: ch = mod(ranPool.value(), 10) + (int) '0';
193:
194: } else {
195: return consonantNext;
196: }
197:
198: if (charsOut == null) {
199: charsOut = String.valueOf((char) ch);
200: consonantNext = true;
201: }
202: password.append(charsOut);
203: return consonantNext;
204: }
205:
206: /**
207: * Returns a description of the module.
208: */
209: public String getModuleInfo() {
210: return "Password Generator module, based on the code of Arnold G. Reinhold, Cambridge, MA, USA. Author Rico Jansen";
211: }
212: }
|