de.rrze.idmone.utils.jpwgen.PwGenerator.java Source code

Java tutorial

Introduction

Here is the source code for de.rrze.idmone.utils.jpwgen.PwGenerator.java

Source

/*
 * RRZEPwGen, developed as a part of the IDMOne project at RRZE.
 * Copyright 2007, RRZE, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors. This
 * product includes software developed by the Apache Software Foundation
 * http://www.apache.org/
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 * 
 * This software uses code and ideas from:
 *    http://sourceforge.net/projects/pwgen/
 *    Copyright (C) 2001,2002 by Theodore Ts'o
 * 
 */
package de.rrze.idmone.utils.jpwgen;

import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * The program is started from this class. It performs the actual password
 * generation. The idea of this class is to generate passwords that are
 * relatively easily to remember but at the same time complex enough. It
 * utilizes a predefined set of vowels and consonants that are brought together
 * by an iterative algorithm. The concept of dipthong is also used which can be
 * used as an additional flag for a consonant or a vowel. Typical examples of
 * dipthongs are <em>ei</em> for vowels and <em>th</em> for consonants.
 * 
 * Various algorithms for random generation can be used for feeding the process
 * of password generation. This ensures unique password creation.
 * 
 * By default two filters are registered in the PwGenerator. The first one is an
 * empty black list filter. It can be used to filter out forbidden predefined
 * passwords. The second one is based on regular expressions and uses frequently
 * utilized rules for filtering passwords such as the number of contained
 * symbols, digits and so on. See the help for a detailed description.
 * 
 * 
 * <table border="1px">
 * <caption>CLI options comparison to original pwgen</caption> <tbody>
 * <tr>
 * <th colspan="3">pwgen</th>
 * <th colspan="3">jpwgen</th>
 * </tr>
 * <tr>
 * <th>short</th>
 * <th>long</th>
 * <th>description</th>
 * <th>short</th>
 * <th>long</th>
 * <th>description</th>
 * </tr>
 * 
 * <tr>
 * <td>-0</td>
 * <td>--no-numerals</td>
 * <td>Don't include numbers in the generated passwords.</td>
 * <td>-O</td>
 * <td>--no-numerals</td>
 * <td>Don't include numbers in the generated passwords.</td>
 * </tr>
 * 
 * <tr>
 * <td>-n</td>
 * <td>--numerals</td>
 * <td>Include at least one number in the password</td>
 * <td>-n</td>
 * <td>--numerals</td>
 * <td>Include at least one number in the password</td>
 * </tr>
 * 
 * <tr>
 * <td>-y</td>
 * <td>--symbols</td>
 * <td>Include at least one special symbol in the password</td>
 * <td>-y</td>
 * <td>--symbols</td>
 * <td>Include at least one special symbol in the password</td>
 * </tr>
 * 
 * <tr>
 * <td>-z</td>
 * <td>--reduced-symbols</td>
 * <td>Include at least one special symbol from the reduced set in the password</td>
 * <td></td>
 * <td></td>
 * <td></td>
 * </tr>
 * 
 * <tr>
 * <td>-1</td>
 * <td>-</td>
 * <td>Print the generated passwords one per line.</td>
 * <td></td>
 * <td></td>
 * <td></td>
 * </tr>
 * 
 * <tr>
 * <td>-a</td>
 * <td>--alt-phonic</td>
 * <td>This option doesn't do anything special; it is present only for backwards
 * compatibility.</td>
 * <td></td>
 * <td></td>
 * <td></td>
 * </tr>
 * 
 * 
 * <tr>
 * <td>-B</td>
 * <td>--ambiguous</td>
 * <td>Don't include ambiguous characters in the password</td>
 * <td>-B</td>
 * <td>--ambiguous</td>
 * <td>Don't include ambiguous characters in the password</td>
 * </tr>
 * 
 * 
 * <tr>
 * <td>-c</td>
 * <td>--capitalize</td>
 * <td>Include at least one capital letter in the password. This is the default
 * if the standard output is a tty device.</td>
 * <td>-c</td>
 * <td>--capitalize</td>
 * <td>Include at least one capital letter in the password. This is the default
 * if the standard output is a tty device.</td>
 * </tr>
 * 
 * <tr>
 * <td>-s</td>
 * <td>--secure</td>
 * <td>Generate completely random passwords</td>
 * <td></td>
 * <td></td>
 * <td></td>
 * </tr>
 * 
 * 
 * <tr>
 * <td>-h</td>
 * <td>--help</td>
 * <td>Print a help message</td>
 * <td>-h</td>
 * <td>--help</td>
 * <td>Print a help message</td>
 * </tr>
 * 
 * <tr>
 * <td>-C</td>
 * <td></td>
 * <td>Print the generated passwords in columns</td>
 * <td>-C</td>
 * <td>--columns</td>
 * <td>Print the generated passwords in columns</td>
 * </tr>
 * 
 * <tr>
 * <td>-v</td>
 * <td>--no-vowels</td>
 * <td>Use sha1 hash of given file as a (not so) random generator</td>
 * <td></td>
 * <td></td>
 * <td></td>
 * </tr>
 * 
 * 
 * <tr>
 * <td>-H</td>
 * <td>--sha1=path/to/file[#seed]</td>
 * <td>Do not use any vowels so as to avoid accidental nasty words</td>
 * <td></td>
 * <td></td>
 * <td></td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-b</td>
 * <td>--start-no-small-letter</td>
 * <td>Generates password starting with a character different than a small
 * letter</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-d</td>
 * <td>--end-no-small-letter</td>
 * <td>Generates password ending with a character different than a small letter</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-D</td>
 * <td>--allow-ambiguous</td>
 * <td>Allow ambiguous characters in the password</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-e</td>
 * <td>--start-no-uppercase-letter</td>
 * <td>Generates password starting with a character different than a uppercase
 * letter</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-f</td>
 * <td>--end-no-uppercase-letter</td>
 * <td>Generates password ending with a character different than a uppercase
 * letter</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-g</td>
 * <td>--end-no-digit</td>
 * <td>Generates password ending with a character different than a digit</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-i</td>
 * <td>--start-no-digit-letter</td>
 * <td>Generates password starting with a character different than a digit</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-j</td>
 * <td>--start-no-symbol-letter</td>
 * <td>Generates password starting with a character different than a symbol</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-k</td>
 * <td>--end-no-symbol</td>
 * <td>Generates password ending with a character different than a symbol</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-l</td>
 * <td>--list-sr-providers</td>
 * <td>Lists the available security service providers for SecureRandom and exits
 * </td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-L</td>
 * <td>--list-providers</td>
 * <td>Lists all available security providers and algorithms</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-m</td>
 * <td>--one-upercase</td>
 * <td>Generates password containing exactly one uppercase letter</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-M</td>
 * <td>--max-attempts &lt;arg&gt;</td>
 * <td>Sets the maximum number of attempts for generating a password with the
 * provided policies</td>
 * </tr>
 * 
 * <tr>
 * <td>second parameter</td>
 * <td>second parameter</td>
 * <td></td>
 * <td>-N</td>
 * <td>--number &lt;arg&gt;</td>
 * <td>The number of passwords to be generated</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-o</td>
 * <td>--one-symbol</td>
 * <td>Generates password containing exactly one symbol</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-p</td>
 * <td>--two-symbol</td>
 * <td>Generates password containing at least two symbols</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-q</td>
 * <td>--one-digit</td>
 * <td>Generates password containing exactly one digit</td>
 * </tr>
 * 
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-r</td>
 * <td>--random</td>
 * <td>Use simple random for password generation</td>
 * </tr>
 * 
 * <tr>
 * <td>first parameter</td>
 * <td>first parameter</td>
 * <td>The length of the generated password</td>
 * <td>-s</td>
 * <td>--size &lt;arg&gt;</td>
 * <td>The length of the generated password</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-S</td>
 * <td>--set-algorithm &lt;arg&gt;</td>
 * <td>set-algorithm</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-t</td>
 * <td>--term-width &lt;arg&gt;</td>
 * <td>Sets the character width of the jpwgen terminal</td>
 * </tr>
 * 
 * <tr>
 * <td></td>
 * <td></td>
 * <td></td>
 * <td>-u</td>
 * <td>--two-digits</td>
 * <td>Generates password containing at least two digits</td>
 * </tr>
 * 
 * </tbody>
 * </table>
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * <h3>
 * Example:</h3>
 * <ul>
 * <br>
 * String flags = "-N 50 -M 100 -y -s 16 -m -o -q ";<br>
 * <br>
 * flags = BlankRemover.itrim(flags); <br>
 * String[] ar = flags.split(" "); <br>
 * 
 * 
 * PwGenerator.getDefaultBlacklistFilter().addToBlacklist("badpassword");
 * List<String> passwords = PwGenerator.process(ar); <br>
 * int count = 0;<br>
 * System.out.printf("\n");<br>
 * for (Iterator iter = passwords.iterator(); iter.hasNext();) <br>
 * {<br>
 * <br>
 * String element = (String) iter.next();<br>
 * System.out.printf("%3d Password: * %s\n", ++count, element); <br>
 * <br>
 * 
 * 
 * @author unrz205
 */
public class PwGenerator implements IPwGenConstants, IPwGenCommandLineOptions, IPwGenRegEx {
    protected static final Log logger = LogFactory.getLog(PwGenerator.class);

    // A static list of predefined vowels and consonants dipthongs. Suitable for
    // English speaking people.
    // This can be exchanged or extended with a different one if needed.
    public static final PwElement[] PW_ELEMENTS = { new PwElement("a", VOWEL), //$NON-NLS-1$
            new PwElement("ae", VOWEL | DIPTHONG), //$NON-NLS-1$
            new PwElement("ah", VOWEL | DIPTHONG), //$NON-NLS-1$
            new PwElement("ai", VOWEL | DIPTHONG), //$NON-NLS-1$
            new PwElement("b", CONSONANT), new PwElement("c", CONSONANT), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("ch", CONSONANT | DIPTHONG), //$NON-NLS-1$
            new PwElement("d", CONSONANT), new PwElement("e", VOWEL), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("ee", VOWEL | DIPTHONG), //$NON-NLS-1$
            new PwElement("ei", VOWEL | DIPTHONG), //$NON-NLS-1$
            new PwElement("f", CONSONANT), new PwElement("g", CONSONANT), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("gh", CONSONANT | DIPTHONG | NOT_FIRST), //$NON-NLS-1$
            new PwElement("h", CONSONANT), new PwElement("i", VOWEL), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("ie", VOWEL | DIPTHONG), //$NON-NLS-1$
            new PwElement("j", CONSONANT), new PwElement("k", CONSONANT), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("l", CONSONANT), new PwElement("m", CONSONANT), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("n", CONSONANT), //$NON-NLS-1$
            new PwElement("ng", CONSONANT | DIPTHONG | NOT_FIRST), //$NON-NLS-1$
            new PwElement("o", VOWEL), new PwElement("oh", VOWEL | DIPTHONG), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("oo", VOWEL | DIPTHONG), //$NON-NLS-1$
            new PwElement("p", CONSONANT), //$NON-NLS-1$
            new PwElement("ph", CONSONANT | DIPTHONG), //$NON-NLS-1$
            new PwElement("qu", CONSONANT | DIPTHONG), //$NON-NLS-1$
            new PwElement("r", CONSONANT), new PwElement("s", CONSONANT), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("sh", CONSONANT | DIPTHONG), new PwElement("t", CONSONANT), //$NON-NLS-2$
            new PwElement("th", CONSONANT | DIPTHONG), //$NON-NLS-1$
            new PwElement("u", VOWEL), new PwElement("v", CONSONANT), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("w", CONSONANT), new PwElement("x", CONSONANT), //$NON-NLS-1$ //$NON-NLS-2$
            new PwElement("y", CONSONANT), new PwElement("z", CONSONANT) }; //$NON-NLS-1$ //$NON-NLS-2$

    // The command options with which the program was started
    private static Options options = createOptions();

    private static int termWidth = DEFAULT_TERM_WIDTH;

    private static boolean doColumns = DEFAULT_DO_COLUMNS;

    private static IPasswordFilter defaultRegexFilter = new DefaultRegExFilter();

    private static IPasswordFilter defaultBlacklistFilter = new DefaultBlacklistFilter();

    private static Map<String, IPasswordFilter> filters = new HashMap<String, IPasswordFilter>();
    static {
        filters.put(defaultRegexFilter.getID(), defaultRegexFilter);
        filters.put(defaultBlacklistFilter.getID(), defaultBlacklistFilter);
    }

    /**
     * Adds a password filter to the registry
     * 
     * @param filter
     *            the filter instance to be registered
     * @return the registered instance
     */

    public static synchronized IPasswordFilter addFilter(IPasswordFilter filter) {
        return filters.put(filter.getID(), filter);
    }

    /**
     * Removes a filter from the registry by instance search
     * 
     * @param filter
     *            the instance of the filter
     * @return the removed instance
     */

    public static synchronized IPasswordFilter removeFilter(IPasswordFilter filter) {
        return filters.remove(filter.getID());
    }

    /**
     * Removes a filter from the registry by identifier search
     * 
     * @param id
     *            the identifier of the filter
     * @return the removed instance
     */

    public static synchronized IPasswordFilter removeFilter(String id) {
        return filters.remove(id);
    }

    /**
     * Logs a message as info or error depending on a flag
     * 
     * @param message
     *            the message to be logged
     * @param error
     *            indicates whether the message is an error or not
     */
    private static synchronized void log(String message, boolean error) {
        if (error)
            logger.error(message);

        logger.debug(message);
    }

    private static int initDefaultFlags() {
        // Flags used during the process of password generation
        int passwordFlags = 0;

        passwordFlags |= PW_UPPERS;
        logger.debug(Messages.getString("PwGenerator.TRACE_UPPERCASE_ON")); //$NON-NLS-1$
        passwordFlags |= PW_DIGITS;
        logger.debug(Messages.getString("PwGenerator.TRACE_DIGITS_ON")); //$NON-NLS-1$
        // passwordFlags |= PW_SYMBOLS;
        // passwordFlags |= PW_AMBIGUOUS;

        return passwordFlags;
    }

    /**
     * This method logs some general info about the given settings and tries to
     * generate passwords with the given flags and given length. The method
     * return <em>null</em> if it does not manage to create a suitable password
     * within the <em>MAX_ATTEMPTS</em>.
     * 
     * @param passwordLength
     *            the length of the password to be generated
     * @param passwordFlags
     *            the settings for the particular password
     * @return a suitable password or <em>null</em> if such could not be
     *         generated
     */

    public static synchronized String generatePassword(int passwordLength, int passwordFlags, int maxAttempts,
            Random random) {
        if (passwordLength <= 2) {
            passwordFlags &= ~PW_UPPERS;
            logger.warn(Messages.getString("PwGenerator.WARN_PL_UPERCASE_OFF")); //$NON-NLS-1$
        }
        if (passwordLength <= 1) {
            passwordFlags &= ~PW_DIGITS;
            logger.warn(Messages.getString("PwGenerator.WARN_PL_DIGITS_OFF")); //$NON-NLS-1$
        }
        if (passwordLength <= 2) {
            passwordFlags &= ~PW_SYMBOLS;
            logger.warn(Messages.getString("PwGenerator.WARN_PL_SYMBOLS_OFF")); //$NON-NLS-1$
        }
        if (passwordLength <= 2) {
            passwordFlags &= ~PW_SYMBOLS_REDUCED;
            logger.warn(Messages.getString("PwGenerator.WARN_PL_SYMBOLS_REDUCED_OFF")); //$NON-NLS-1$
        }

        String password = null;
        for (int i = 0; i < maxAttempts; i++) {
            password = phonemes(passwordLength, passwordFlags, random);

            Set<String> filterIDs = filters.keySet();

            for (Iterator<String> iter = filterIDs.iterator(); iter.hasNext();) {
                String element = (String) iter.next();
                IPasswordFilter filter = filters.get(element);
                password = filter.filter(passwordFlags, password);
                if (password == null)
                    break;
            }

            if (password != null)
                break;

            logger.debug(Messages.getString("PwGenerator.TRACE_ATTEMPT") + i //$NON-NLS-1$
                    + Messages.getString("PwGenerator.TRACE_ATTEMPT_GENERATE") //$NON-NLS-1$
                    + passwordFlags);
        }

        return password;
    }

    /**
     * Entry point of the program
     * 
     * @param args
     *            the program arguments
     */
    public static void main(String[] args) {
        List<String> passwords = process(args);
        if (doColumns) {
            printColumns(passwords, termWidth);
        } else {
            print(passwords);
        }
    }

    /**
     * This method parses the command line options, initializes the needed
     * objects and generates the required number of passwords by calling
     * <em>generatePassword()</em>. When not used as a stand-alone program this
     * method is to be preferred instead of the main(String[]).
     * 
     * @param args
     *            the arguments used to initialize the generation process
     * @return a list of passwords or <em>null</em> if no suitable passwords
     *         could be generated.
     */

    public static synchronized List<String> process(String[] args) {
        int passwordFlags = initDefaultFlags();

        // The length of the password to be generated
        int passwordLength = DEFAULT_PASSWORD_LENGTH;

        int numberOfPasswords = DEFAULT_NUMBER_OF_PASSWORDS;

        int maxAttempts = DEFAULT_MAX_ATTEMPTS;

        log(Messages.getString("PwGenerator.PASSWORD_GENERATOR"), //$NON-NLS-1$
                false);

        ArrayList<String> passwords = new ArrayList<String>();
        BasicParser parser = new BasicParser();
        try {
            CommandLine commandLine = parser.parse(options, args);

            parser.parse(options, args);
            if (commandLine.hasOption(CL_HELP)) {
                printUsage();
                log(Messages.getString("PwGenerator.SEPARATOR"), //$NON-NLS-1$
                        false);
                return passwords;
            }

            parser.parse(options, args);
            if (commandLine.hasOption(CL_SR_PROVIDERS)) {
                Set<String> serviceProviders = RandomFactory.getInstance()
                        .getServiceProviderFor(IRandomFactory.TYPE_SECURE_RANDOM);
                log(Messages.getString("PwGenerator.SERVICES_PROVIDERS_FOR") //$NON-NLS-1$
                        + IRandomFactory.TYPE_SECURE_RANDOM + Messages.getString("PwGenerator.NEW_LINE"), false); //$NON-NLS-1$
                for (Iterator<String> iter = serviceProviders.iterator(); iter.hasNext();) {
                    String element = (String) iter.next();
                    log(Messages.getString("PwGenerator.SERVICE_PROVIDERS") + element //$NON-NLS-1$
                            + Messages.getString("PwGenerator.NEW_LINE"), false); //$NON-NLS-1$
                    log(Messages.getString("PwGenerator.SEPARATOR"), //$NON-NLS-1$
                            false);
                    return passwords;
                }
            }

            parser.parse(options, args);
            if (commandLine.hasOption(CL_PROVIDERS)) {
                log(Messages.getString("PwGenerator.ALL_SEC_PROVIDERS") //$NON-NLS-1$
                        + IRandomFactory.TYPE_SECURE_RANDOM + Messages.getString("PwGenerator.NEW_LINE"), false); //$NON-NLS-1$
                Provider[] serviceProviders = RandomFactory.getInstance().getProviders();
                for (int i = 0; i < serviceProviders.length; i++) {
                    log(Messages.getString("PwGenerator.SEPARATOR"), //$NON-NLS-1$
                            false);
                    log(Messages.getString("PwGenerator.PROVIDER") + serviceProviders[i].getName() //$NON-NLS-1$
                            + Messages.getString("PwGenerator.NEW_LINE"), //$NON-NLS-1$
                            false);
                    Set<Provider.Service> services = serviceProviders[i].getServices();
                    log(Messages.getString("PwGenerator.SERVICES") + Messages.getString("PwGenerator.NEW_LINE"), //$NON-NLS-1$//$NON-NLS-2$
                            false);
                    log(services.toString(), false);
                    log(Messages.getString("PwGenerator.SEPARATOR"), //$NON-NLS-1$
                            false);
                }
                log(Messages.getString("PwGenerator.SEPARATOR"), //$NON-NLS-1$
                        false);
                return passwords;
            }

            if (commandLine.hasOption(CL_NUMBER_PASSWORD)) {
                String sNumberOfPasswords = commandLine.getOptionValue(CL_NUMBER_PASSWORD);
                if (sNumberOfPasswords != null)
                    numberOfPasswords = Integer.parseInt(sNumberOfPasswords);
                log(Messages.getString("PwGenerator.NUM_PASSWORDS") + numberOfPasswords, false); //$NON-NLS-1$
            }

            commandLine = parser.parse(options, args);
            if (commandLine.hasOption(CL_PASSWORD_LENGTH)) {
                String sPasswordLength = commandLine.getOptionValue(CL_PASSWORD_LENGTH);
                if (sPasswordLength != null)
                    passwordLength = Integer.parseInt(sPasswordLength);
                log(Messages.getString("PwGenerator.PASSWORD_LENGTH") + passwordLength, false); //$NON-NLS-1$
            }

            parser.parse(options, args);
            if (commandLine.hasOption(CL_COLUMN)) {
                doColumns = true;
                log(Messages.getString("PwGenerator.COLUMNS_ENABLED"), false); //$NON-NLS-1$
            }

            parser.parse(options, args);
            if (commandLine.hasOption(CL_TERM_WIDTH)) {
                String sTermWidth = commandLine.getOptionValue(CL_TERM_WIDTH);
                if (sTermWidth != null)
                    termWidth = Integer.parseInt(sTermWidth);
                log(Messages.getString("PwGenerator.TERMINAL_LENGTH") + termWidth, false); //$NON-NLS-1$
            }

            Random random = null;
            parser.parse(options, args);
            if (commandLine.hasOption(CL_RANDOM)) {
                random = RandomFactory.getInstance().getRandom();
                log(Messages.getString("PwGenerator.NORMAL_RANDOM"), false); //$NON-NLS-1$
            } else {
                try {
                    random = RandomFactory.getInstance().getSecureRandom();
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                    random = RandomFactory.getInstance().getRandom();
                } catch (NoSuchProviderException e) {
                    e.printStackTrace();
                    random = RandomFactory.getInstance().getRandom();
                }
            }

            parser.parse(options, args);
            if (commandLine.hasOption(CL_SR_ALGORITHM)) {
                String[] data = commandLine.getOptionValues(CL_SR_ALGORITHM);
                if (data.length == 2) {
                    try {
                        random = RandomFactory.getInstance().getSecureRandom(data[0], data[1]);

                        log(Messages.getString("PwGenerator.SEC_ALG") + data[0] //$NON-NLS-1$
                                + Messages.getString("PwGenerator.PROV") + data[1] //$NON-NLS-1$
                                + Messages.getString("PwGenerator.DOR"), false); //$NON-NLS-1$
                    } catch (NoSuchAlgorithmException e) {
                        log(Messages.getString("PwGenerator.ERROR") + e.getMessage() //$NON-NLS-1$
                                + Messages.getString("PwGenerator.NEW_LINE"), true); //$NON-NLS-1$
                        log(Messages.getString("PwGenerator.DEFAUL_RANDOM"), true); //$NON-NLS-1$
                    } catch (NoSuchProviderException e) {
                        log(Messages.getString("PwGenerator.ERROR") + e.getMessage() //$NON-NLS-1$
                                + Messages.getString("PwGenerator.NEW_LINE"), true); //$NON-NLS-1$
                        log(Messages.getString("PwGenerator.DEFAUL_RANDOM"), true); //$NON-NLS-1$
                    }
                }
            }

            if (commandLine.hasOption(CL_NUMERALS)) {
                passwordFlags |= PW_DIGITS;
                log(Messages.getString("PwGenerator.DIGITS_ON"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_NO_NUMERALS)) {
                passwordFlags &= ~PW_DIGITS;
                log(Messages.getString("PwGenerator.DIGITS_OFF"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_CAPITALIZE)) {
                passwordFlags |= PW_UPPERS;
                log(Messages.getString("PwGenerator.UPPERCASE_ON"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_NO_CAPITALIZE)) {
                passwordFlags &= ~PW_UPPERS;
                log(Messages.getString("PwGenerator.UPPERCASE_OFF"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_AMBIGOUS)) {
                passwordFlags |= PW_AMBIGUOUS;
                log(Messages.getString("PwGenerator.AMBIGOUS_ON"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_NO_AMBIGOUS)) {
                passwordFlags &= ~PW_AMBIGUOUS;
                log(Messages.getString("PwGenerator.AMBIGOUS_OFF"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_SYMBOLS)) {
                passwordFlags |= PW_SYMBOLS;
                log(Messages.getString("PwGenerator.SYMBOLS_ON"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_SYMBOLS_REDUCED)) {
                passwordFlags |= PW_SYMBOLS_REDUCED;
                log(Messages.getString("PwGenerator.SYMBOLS_REDUCED_ON"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_NO_SYMBOLS)) {
                passwordFlags &= ~PW_SYMBOLS;
                passwordFlags &= ~PW_SYMBOLS_REDUCED;
                log(Messages.getString("PwGenerator.SYMBOLS_OFF"), false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_MAX_ATTEMPTS)) {
                String sMaxAttempts = commandLine.getOptionValue(CL_MAX_ATTEMPTS);
                if (sMaxAttempts != null)
                    maxAttempts = Integer.parseInt(sMaxAttempts);
                log(Messages.getString("PwGenerator.MAX_ATTEMPTS") + maxAttempts, false); //$NON-NLS-1$
            }

            if (commandLine.hasOption(CL_REGEX_STARTS_NO_SMALL_LETTER))
                passwordFlags |= REGEX_STARTS_NO_SMALL_LETTER_FLAG;

            if (commandLine.hasOption(CL_REGEX_ENDS_NO_SMALL_LETTER))
                passwordFlags |= REGEX_STARTS_NO_SMALL_LETTER_FLAG;

            if (commandLine.hasOption(CL_REGEX_STARTS_NO_UPPER_LETTER))
                passwordFlags |= REGEX_STARTS_NO_UPPER_LETTER_FLAG;

            if (commandLine.hasOption(CL_REGEX_ENDS_NO_UPPER_LETTER))
                passwordFlags |= REGEX_ENDS_NO_UPPER_LETTER_FLAG;

            if (commandLine.hasOption(CL_REGEX_ENDS_NO_DIGIT))
                passwordFlags |= REGEX_ENDS_NO_DIGIT_FLAG;

            if (commandLine.hasOption(CL_REGEX_STARTS_NO_DIGIT))
                passwordFlags |= REGEX_STARTS_NO_DIGIT_FLAG;

            if (commandLine.hasOption(CL_REGEX_STARTS_NO_SYMBOL))
                passwordFlags |= REGEX_STARTS_NO_SYMBOL_FLAG;

            if (commandLine.hasOption(CL_REGEX_ENDS_NO_SYMBOL))
                passwordFlags |= REGEX_ENDS_NO_SYMBOL_FLAG;

            if (commandLine.hasOption(CL_REGEX_ONLY_1_CAPITAL))
                passwordFlags |= REGEX_ONLY_1_CAPITAL_FLAG;

            if (commandLine.hasOption(CL_REGEX_ONLY_1_SYMBOL))
                passwordFlags |= REGEX_ONLY_1_SYMBOL_FLAG;

            if (commandLine.hasOption(CL_REGEX_AT_LEAST_2_SYMBOLS))
                passwordFlags |= REGEX_AT_LEAST_2_SYMBOLS_FLAG;

            if (commandLine.hasOption(CL_REGEX_ONLY_1_DIGIT))
                passwordFlags |= REGEX_ONLY_1_DIGIT_FLAG;

            if (commandLine.hasOption(CL_REGEX_AT_LEAST_2_DIGITS))
                passwordFlags |= REGEX_AT_LEAST_2_DIGITS_FLAG;
            // -------------------------------------------------------------------

            log(Messages.getString("PwGenerator.GENRIC_FLAGS"), //$NON-NLS-1$
                    false);

            int res = passwordFlags & PW_DIGITS;
            log(Messages.getString("PwGenerator.DIGITS") + (res != 0), false); //$NON-NLS-1$
            res = passwordFlags & PW_AMBIGUOUS;
            log(Messages.getString("PwGenerator.AMBIGOUS") + (res != 0), false); //$NON-NLS-1$
            res = passwordFlags & PW_SYMBOLS;
            log(Messages.getString("PwGenerator.SYMBOLS") + (res != 0), false); //$NON-NLS-1$
            res = passwordFlags & PW_SYMBOLS_REDUCED;
            log(Messages.getString("PwGenerator.SYMBOLS_REDUCED") + (res != 0), false); //$NON-NLS-1$
            res = passwordFlags & PW_UPPERS;
            log(Messages.getString("PwGenerator.UPPERS") + (res != 0), false); //$NON-NLS-1$
            log(Messages.getString("PwGenerator.SEPARATOR"), //$NON-NLS-1$
                    false);

            log(Messages.getString("PwGenerator.GENERATING") + numberOfPasswords //$NON-NLS-1$
                    + Messages.getString("PwGenerator.PW_LENGTH") //$NON-NLS-1$
                    + passwordLength, false);
            log(Messages.getString("PwGenerator.PW"), //$NON-NLS-1$
                    false);

            int i;
            for (i = 0; i < numberOfPasswords; i++) {
                String password = generatePassword(passwordLength, passwordFlags, maxAttempts, random);
                if (password != null)
                    passwords.add(password);
            }
        } catch (ParseException e) {
            log(Messages.getString("PwGenerator.PARAM_ERROR") + e.getLocalizedMessage(), true); //$NON-NLS-1$
            printUsage();
        } catch (NumberFormatException e) {
            log(Messages.getString("PwGenerator.NUM_FORM_ERROR") + e.getLocalizedMessage(), true); //$NON-NLS-1$
            printUsage();
        }

        return passwords;
    }

    /**
     * Prints passwords into columns with a predefined terminal width(to
     * System.out). The number of columns is calculated from the terminal width.
     * 
     * @param passwords
     *            a list of passwords to be printed
     * @param termWidth
     *            the width in characters of the terminal
     */

    public static void printColumns(List<String> passwords, int termWidth) {

        log(Messages.getString("PwGenerator.N_SEPARATOR"), //$NON-NLS-1$
                false);

        for (int i = 0; i < passwords.size(); i++) {
            String password = (String) passwords.get(i);
            if (logger.isInfoEnabled()) {
                int numberOfColumns = termWidth / (password.length() + 1);
                if (numberOfColumns == 0)
                    numberOfColumns = 1;

                if (((i % numberOfColumns) == (numberOfColumns - 1))) {

                    System.out.print(password + Messages.getString("PwGenerator.NEW_LINE")); //$NON-NLS-1$
                } else {
                    System.out.print(password + ' ');
                }
            }
        }
        log(Messages.getString("PwGenerator.N_SEPARATOR"), //$NON-NLS-1$
                false);
    }

    /**
     * Prints a list of passwords to a terminal(System.out)
     * 
     * @param passwords
     *            a list of passwords to be printed
     */

    public static void print(List<String> passwords) {
        log(Messages.getString("PwGenerator.N_SEPARATOR"), //$NON-NLS-1$
                false);

        for (int i = 0; i < passwords.size(); i++) {
            String password = (String) passwords.get(i);
            if (logger.isInfoEnabled()) {
                System.out.print(password + Messages.getString("PwGenerator.NEW_LINE")); //$NON-NLS-1$
            }
        }
        log(Messages.getString("PwGenerator.N_SEPARATOR"), //$NON-NLS-1$
                false);
    }

    /**
     * The real password generation is performed in this method
     * 
     * @param size
     *            the length of the password
     * @param pw_flags
     *            the settings for the password
     * @return the newly created password
     */
    private synchronized static String phonemes(int size, int pw_flags, Random random) {
        int c, i, len, flags, feature_flags;
        int prev, should_be;
        boolean first;
        String str;
        char ch;
        StringBuffer buf = new StringBuffer();

        do {
            buf.delete(0, buf.length());
            feature_flags = pw_flags;
            c = 0;
            prev = 0;
            should_be = 0;
            first = true;
            should_be = random.nextBoolean() ? VOWEL : CONSONANT;

            while (c < size) {

                i = random.nextInt(PW_ELEMENTS.length);
                str = PW_ELEMENTS[i].getValue();
                len = str.length();
                flags = PW_ELEMENTS[i].getType();
                /* Filter on the basic type of the next element */
                if ((flags & should_be) == 0) {
                    continue;
                }
                /* Handle the NOT_FIRST flag */
                if (first && ((flags & NOT_FIRST) != 0))
                    continue;
                /* Don't allow VOWEL followed a Vowel/Dipthong pair */
                if (((prev & VOWEL) != 0) && ((flags & VOWEL) != 0) && ((flags & DIPTHONG) != 0))
                    continue;
                /* Don't allow us to overflow the buffer */
                if (len > size - c)
                    continue;
                /*
                 * OK, we found an element which matches our criteria, let's do
                 * it!
                 */
                buf.append(str);

                c += len;
                /* Handle the AMBIGUOUS flag */
                if ((pw_flags & PW_AMBIGUOUS) != 0) {
                    int k = -1;
                    for (int j = 0; j < PW_AMBIGUOUS_SYMBOLS.length(); j++) {
                        k = buf.indexOf(String.valueOf(PW_AMBIGUOUS_SYMBOLS.charAt(j)));
                        if (k != -1)
                            break;
                    }
                    if (k != -1) {
                        buf.delete(k, buf.length());
                        c = buf.length();
                    }
                }

                /* Time to stop? */
                if (c >= size) {
                    // System.out.println("BREAK 1: "+c + " - "+size);
                    break;
                }
                /*
                 * Handle PW_DIGITS
                 */
                if ((pw_flags & PW_DIGITS) != 0) {
                    if (!first && (random.nextInt(10) < 3)) {
                        do {
                            ch = (new Integer(random.nextInt(10))).toString().charAt(0);
                        } while (((pw_flags & PW_AMBIGUOUS) != 0) && (PW_AMBIGUOUS_SYMBOLS.indexOf(ch) != -1));
                        c++;
                        buf = buf.append(ch);
                        feature_flags &= ~PW_DIGITS;

                        first = true;
                        prev = 0;
                        should_be = random.nextBoolean() ? VOWEL : CONSONANT;
                        continue;
                    }
                }

                /* Handle PW_SYMBOLS */
                if ((pw_flags & PW_SYMBOLS) != 0) {
                    if (!first && (random.nextInt(10) < 2)) {
                        do {
                            ch = PW_SPECIAL_SYMBOLS.charAt(random.nextInt(PW_SPECIAL_SYMBOLS.length()));
                        } while (((pw_flags & PW_AMBIGUOUS) != 0) && (PW_AMBIGUOUS_SYMBOLS.indexOf(ch) != -1));
                        c++;
                        buf = buf.append(ch);
                        feature_flags &= ~PW_SYMBOLS;
                    }
                } else if ((pw_flags & PW_SYMBOLS_REDUCED) != 0) {
                    if (!first && (random.nextInt(10) < 2)) {
                        do {
                            ch = PW_SPECIAL_SYMBOLS_REDUCED
                                    .charAt(random.nextInt(PW_SPECIAL_SYMBOLS_REDUCED.length()));
                        } while (((pw_flags & PW_AMBIGUOUS) != 0) && (PW_AMBIGUOUS_SYMBOLS.indexOf(ch) != -1));
                        c++;
                        buf = buf.append(ch);
                        feature_flags &= ~PW_SYMBOLS_REDUCED;
                    }
                }

                /* Handle PW_UPPERS */
                if ((pw_flags & PW_UPPERS) != 0) {
                    if ((first || ((flags & CONSONANT) != 0)) && (random.nextInt(10) < 2)) {
                        int lastChar = buf.length() - 1;
                        buf.setCharAt(lastChar, Character.toUpperCase(buf.charAt(lastChar)));
                        feature_flags &= ~PW_UPPERS;
                    }
                }

                /*
                 * OK, figure out what the next element should be
                 */
                if (should_be == CONSONANT) {
                    should_be = VOWEL;
                } else { /* should_be == VOWEL */
                    if (((prev & VOWEL) != 0) || ((flags & DIPTHONG) != 0) || (random.nextInt(10) > 3))
                        should_be = CONSONANT;
                    else
                        should_be = VOWEL;
                }
                prev = flags;
                first = false;

            }
        } while ((feature_flags & (PW_UPPERS | PW_DIGITS | PW_SYMBOLS | PW_SYMBOLS_REDUCED)) != 0);

        return buf.toString();
    }

    /**
     * Initializes the CLI (Command Line Interface) options of the PwGenerator.
     * 
     * @return the CLI options
     */
    private synchronized static Options createOptions() {
        options = new Options();

        Option option = createOption(CL_NUMBER_PASSWORD, CL_NUMBER_PASSWORD_LONG, CL_NUMBER_PASSWORD_DESC, true,
                false);
        options.addOption(option);

        option = createOption(CL_PASSWORD_LENGTH, CL_PASSWORD_LENGTH_LONG, CL_PASSWORD_LENGTH_DESC, true, false);
        options.addOption(option);

        option = createOption(CL_CAPITALIZE, CL_CAPITALIZE_LONG, CL_CAPITALIZE_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_NO_CAPITALIZE, CL_NO_CAPITALIZE_LONG, CL_NO_CAPITALIZE_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_NUMERALS, CL_NUMERALS_LONG, CL_NUMERALS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_NO_NUMERALS, CL_NO_NUMERALS_LONG, CL_NO_NUMERALS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_SYMBOLS, CL_SYMBOLS_LONG, CL_SYMBOLS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_SYMBOLS_REDUCED, CL_SYMBOLS_REDUCED_LONG, CL_SYMBOLS_REDUCED_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_NO_SYMBOLS, CL_NO_SYMBOLS_LONG, CL_NO_SYMBOLS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_AMBIGOUS, CL_AMBIGOUS_LONG, CL_AMBIGOUS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_NO_AMBIGOUS, CL_NO_AMBIGOUS_LONG, CL_NO_AMBIGOUS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_HELP, CL_HELP_LONG, CL_HELP_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_RANDOM, CL_RANDOM_LONG, CL_RANDOM_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_COLUMN, CL_COLUMN_LONG, CL_COLUMN_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_SR_PROVIDERS, CL_SR_PROVIDERS_LONG, CL_SR_PROVIDERS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_PROVIDERS, CL_PROVIDERS_LONG, CL_PROVIDERS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_SR_ALGORITHM, CL_SR_ALGORITHM_LONG, CL_SR_ALGORITHM_LONG, true, false);
        option.hasArgs();
        option.setArgs(2);
        options.addOption(option);

        option = createOption(CL_TERM_WIDTH, CL_TERM_WIDTH_LONG, CL_TERM_WIDTH_DESC, true, false);
        options.addOption(option);

        option = createOption(CL_MAX_ATTEMPTS, CL_MAX_ATTEMPTS_LONG, CL_MAX_ATTEMPTS_DESC, true, false);
        options.addOption(option);

        // regex
        option = createOption(CL_REGEX_STARTS_NO_SMALL_LETTER, CL_REGEX_STARTS_NO_SMALL_LETTER_LONG,
                CL_REGEX_STARTS_NO_SMALL_LETTER_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_ENDS_NO_SMALL_LETTER, CL_REGEX_ENDS_NO_SMALL_LETTER_LONG,
                CL_REGEX_ENDS_NO_SMALL_LETTER_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_STARTS_NO_UPPER_LETTER, CL_REGEX_STARTS_NO_UPPER_LETTER_LONG,
                CL_REGEX_STARTS_NO_UPPER_LETTER_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_ENDS_NO_UPPER_LETTER, CL_REGEX_ENDS_NO_UPPER_LETTER_LONG,
                CL_REGEX_ENDS_NO_UPPER_LETTER_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_ENDS_NO_DIGIT, CL_REGEX_ENDS_NO_DIGIT_LONG, CL_REGEX_ENDS_NO_DIGIT_DESC,
                false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_STARTS_NO_DIGIT, CL_REGEX_STARTS_NO_DIGIT_LONG,
                CL_REGEX_STARTS_NO_DIGIT_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_STARTS_NO_SYMBOL, CL_REGEX_STARTS_NO_SYMBOL_LONG,
                CL_REGEX_STARTS_NO_SYMBOL_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_ENDS_NO_SYMBOL, CL_REGEX_ENDS_NO_SYMBOL_LONG, CL_REGEX_ENDS_NO_SYMBOL_DESC,
                false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_ONLY_1_CAPITAL, CL_REGEX_ONLY_1_CAPITAL_LONG, CL_REGEX_ONLY_1_CAPITAL_DESC,
                false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_ONLY_1_SYMBOL, CL_REGEX_ONLY_1_SYMBOL_LONG, CL_REGEX_ONLY_1_SYMBOL_DESC,
                false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_AT_LEAST_2_SYMBOLS, CL_REGEX_AT_LEAST_2_SYMBOLS_LONG,
                CL_REGEX_AT_LEAST_2_SYMBOLS_DESC, false, false);
        options.addOption(option);

        option = createOption(CL_REGEX_ONLY_1_DIGIT, CL_REGEX_ONLY_1_DIGIT_LONG, CL_REGEX_ONLY_1_DIGIT_DESC, false,
                false);
        options.addOption(option);

        option = createOption(CL_REGEX_AT_LEAST_2_DIGITS, CL_REGEX_AT_LEAST_2_DIGITS_LONG,
                CL_REGEX_AT_LEAST_2_DIGITS_DESC, false, false);
        options.addOption(option);

        return options;
    }

    /**
     * Creates a CLI entry.
     * 
     * @param shortOption
     *            a one letter flag
     * @param longOption
     *            long flag
     * @param description
     *            the description of the cCLI option
     * @param arg
     *            specifies whether the option has arguments
     * @param required
     *            specifies whether the option is required
     * @return a new instance of a CLI option with the predefined properties
     */
    private synchronized static Option createOption(String shortOption, String longOption, String description,
            boolean arg, boolean required) {
        OptionBuilder.withLongOpt(longOption);
        OptionBuilder.withDescription(description);
        OptionBuilder.isRequired(required);
        if (arg)
            OptionBuilder.hasArg();
        Option option = OptionBuilder.create(shortOption);

        return option;
    }

    /**
     * Prints the usage info
     */
    private static synchronized void printUsage() {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp(Messages.getString("PwGenerator.USAGE"), //$NON-NLS-1$
                options);
        log(Messages.getString("PwGenerator.EXAMPLE"), //$NON-NLS-1$
                false);
    }

    /**
     * Returns the instance of the default blacklist filter registered with the
     * PwGenerator
     * 
     * @return the default blacklist filter
     */

    public static IPasswordFilter getDefaultBlacklistFilter() {
        return defaultBlacklistFilter;
    }

    /**
     * Returns the instance of the default regular expression filter registered
     * with the PwGenerator
     * 
     * @return the default regular expression filter
     */

    public static IPasswordFilter getDefaultRegexFilter() {
        return defaultRegexFilter;
    }

}