Question

I need to generate some passwords, I want to avoid characters that can be confused for each other. Is there a definitive list of characters I should avoid? my current list is

il10o8B3Evu![]{}

Are there any other pairs of characters that are easy to confuse? for special characters I was going to limit myself to those under the number keys, though I know that this differs depending on your keyboards nationality!

As a rider question, I would like my passwords to be 'wordlike'do you have a favoured algorithm for that?

Thanks :)

Was it helpful?

Solution

Here are the character sets that Steve Gibson uses for his "Perfect Paper Password" system. They are "characters to allow" rather than "characters to avoid", but they seem pretty reasonable for what you want:

A standard set of 64 characters

!#%+23456789:=?@ABCDEFGHJKLMNPRS
TUVWXYZabcdefghijkmnopqrstuvwxyz

A larger set of 88 characters

!"#$%&'()*+,-./23456789:;<=>?@ABCDEFGHJKLMNO
PRSTUVWXYZ[\]^_abcdefghijkmnopqrstuvwxyz{|}~

For pronounceable passwords, I'm not familiar with the algorithms but you might want to look at APG and pwgen as a starting point.

OTHER TIPS

My preferred method is to get a word list of 3, 4 and 5 letter words. Then select at least 2 of those, and place a random 2 digit number or special symbol (%&*@#$) between each word. If you want to you can capitalize up to one character per word at random.

Depending on your strength requirements you end up with easy-to-remember and communicate passwords like:

  • lemon%desk
  • paper&boy32hat

Keep in mind you occasionally get interesting or inappropriate combinations of words (I'll let you use your imagination). I usually have a button allowing the generation of a new password if the one presented is disliked.

As a rule, only use symbols that people commonly know the name for. On a US Standard keyboard I would avoid ~`'/\^

I guess this more answered your rider question than your main question . ..

Good luck!

Read Choosing Secure Passwords.

One interesting tidbit from there: For more secure passwords, make sure some numbers and special characters appear in the middle. Cracking programs check for them at the beginning and ends sooner.

To add to Jim's answer you could also use the word list and randomly replace certain characters with symbols (an @ for an A, a 0 (zero) for an O or a 5 for an S) and/or remove the vowels from the words.

  • lmn%Desk
  • p@per&b0y32H@t

Still mostly human readable.

As another option, you could use a monospace/terminal font like courier for printing the passwords. Similar characters should be a lot more distinguishable that way.

For an international client several years ago, I had to generate random, secure passwords that were then mail-merged into documents by my client and sent by postal mail to recipients in 40 countries. Not knowing what typeface was to be used in the documents, I used a list of characters like the Steve Gibson 64-character set to eliminate the confusion between similar glyphs.

To make the resulting passwords pronounceable, and thus easier to remember, I paired consonants and vowels together, with some consonant digraphs (sh, th, wh, etc.) added to the mix.

To reduce the chances of inappropriate or offensive words from being generated (in English or in the recipients’ languages), I limited runs of consecutive alpha characters to two, with numerals or punctuation characters betwee:

Es4tU$sA6
wH@cY8Go2

Looking back over my method now, I realize that there was room for improvement in the inappropriateness algorithm. Using the just the rules above, some offensive words are possible now that some numerals and punctuation are substituted for letters.

For human-readable passwords, I recently used a PHP script very similar to the one below. It worked well. Granted, the passwords aren't going to be incredibly secure (as they're prone to dictionary attacks), but for memorisable, or at least readable, passwords it works well. However, this function shouldn't be used as-is, it's more for illustration than anything else.

function generatePassword($syllables = 2, $use_prefix = true)
{

    // Define function unless it is already exists
    if (!function_exists('arr'))
    {
        // This function returns random array element
        function arr(&$arr)
        {
            return $arr[rand(0, sizeof($arr)-1)];
        }
    }

    // Random prefixes
    $prefix = array('aero', 'anti', 'auto', 'bi', 'bio',
                    'cine', 'deca', 'demo', 'dyna', 'eco',
                    'ergo', 'geo', 'gyno', 'hypo', 'kilo',
                    'mega', 'tera', 'mini', 'nano', 'duo',
                    'an', 'arch', 'auto', 'be', 'co',
                    'counter', 'de', 'dis', 'ex', 'fore',
                    'in', 'infra', 'inter', 'mal', 
                    'mis', 'neo', 'non', 'out', 'pan',
                    'post', 'pre', 'pseudo', 'semi',
                    'super', 'trans', 'twi', 'vice');

    // Random suffixes
    $suffix = array('dom', 'ity', 'ment', 'sion', 'ness',
                    'ence', 'er', 'ist', 'tion', 'or',
                    'ance', 'ive', 'en', 'ic', 'al',
                    'able', 'y', 'ous', 'ful', 'less',
                    'ise', 'ize', 'ate', 'ify', 'fy', 'ly'); 

    // Vowel sounds 
    $vowels = array('a', 'o', 'e', 'i', 'y', 'u', 'ou', 'oo', 'ae', 'ea', 'ie'); 

    // Consonants 
    $consonants = array('w', 'r', 't', 'p', 's', 'd', 'f', 'g', 'h', 'j', 
                        'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm', 'qu');

    $password = $use_prefix?arr($prefix):'';
    $password_suffix = arr($suffix);

    for($i=0; $i<$syllables; $i++)
    {
        // selecting random consonant
        $doubles = array('n', 'm', 't', 's');
        $c = arr($consonants);
        if (in_array($c, $doubles)&&($i!=0)) { // maybe double it
            if (rand(0, 2) == 1) // 33% probability
                $c .= $c;
        }
        $password .= $c;
        //

        // selecting random vowel
        $password .= arr($vowels);

        if ($i == $syllables - 1) // if suffix begin with vovel
            if (in_array($password_suffix[0], $vowels)) // add one more consonant 
                $password .= arr($consonants);

    }

    // selecting random suffix
    $password .= $password_suffix;

    return $password;
}

In my (electrical engineering, techie) graduate school, all computer accounts were initialized with passwords that, I assume, were generated by a standard linux utility. They consisted of three random syllables, with three lowercase letters in each syllable. The result was reasonably secure (on the order of billions of possible combinations) yet so pronounce-able that I still use some of those passwords over a decade later. James' example is an excellent demonstration of this.

A comment on passwords in general, from a network-security professional: they're terrible, for several reasons, including:

  • Generally easily broken, either through social engineering or with attack software, especially if you know anything about your target.

    Example 1: I recently needed to revise a password-protected technical document. Looking at the date, I knew who our Tech Writer in residence was at the time, typed the first word that entered my mind, and immediately unlocked the document.

    Example 2: Standard password-cracking programs allow the cracker to specify a set of rules that operate on a user-supplied dictionary. It's trivial to replace certain letters with $ymb01$, or to translate into 1337, etc.

  • "Secure" passwords aren't. Given the sheer number of passwords most people need to remember, the most common way to "remember" a "strong" password like "a4$N!8_q" is to write it on a piece of paper (or, worse, store it in a text file). 'Nuff said.

If you need truly secure authentication, multi-factor (or two-factor) is the industry-accepted mechanism. The "two factors" are usually something you have (such as an access card) and something you know that enables it (such as a PIN). Neither one works without the other--you need both.

On the other hand, consider the level of security you really need. What are you protecting? How badly do the "bad guys" want to get it, and what are the consequences if they do? Chances are, "Its@Secret!" is more than good enough. :-)

I don't love the wordlist approach. For example, in /usr/share/dict/words on OSX, there are 5110 4-character words. Using two of them with a seperator character produces ~600M combinations. But if you used the character set directly with a strong random number generator, you'd have 88^9 possible passwords, 3.16e+17 combinations.

Either way, the likely attack against this system is going to be against the random number generator, so make sure you're using a cryptographically strong one. If you use PHP's standard rand function, it will be attacked by registering and resetting thousands of passwords to sample the RNG state and then predict the remaining RNG state, which will reduce the number of possible passwords an attacker needs to test.

A starting approach might be to generate mostly valid english syllables, mix them, then throw in a text->l33t conversion. There's been work done on generational natural language grammars, so one of those might help.

E.g. ah ul ing are all valid syllables or close to it... mix them -> Ingulah...l33t it -> 1ngu4h. Is it the best out there? Nah. But at least it is semipronouncable(if you speak l33t) and more computationally secure.

If you're interested in generating pronounceable passwords, there is a C# port at: http://www.hoogervorst.ca/arthur/?attachment_id=1708

Within the code, you'll find helpful links to learn more. http://www.multicians.org/thvv/gpw.html

Good Luck. James

function random_readable_pwd($length=12){
    // special characters
    $sym="!\"§$%&/()={[]}\,.-_:;@>|";

    // read words from text file to array
    $filename="special.txt";
    if (!file_exists($filename)) { die('File "'.$filename.'" is not exists!'); }
    $lines = file($filename);
    foreach ($lines as $line_num => $line) {
        $line=substr($line, 0, -2);
        $words[].=$line;
    }

    // Add words while password is smaller than the given length
    $pwd = '';
    $ran_date=date("s");
    while (strlen($pwd) < $length){
        $r = mt_rand(0, count($words)-1);
        // randomly upercare word but not all in one time
        if ($ran_date % 3 == 0) $words[$r]=ucwords($words[$r]);
        $pwd .= $words[$r];
        //randomly add symbol
        if ($ran_date % 2 == 0) $pwd .= $sym{mt_rand(0,strlen($sym))};
        $ran_date++;
    }

    // append a number at the end if length > 2 and
    // reduce the password size to $length
    $num = mt_rand(1, 99);
    if ($length > 2){
        $pwd = substr($pwd,0,$length-strlen($num)).$num;
    } else { 
        $pwd = substr($pwd, 0, $length);
    }

    return $pwd;

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top