Passwords - Noah.org

Passwords

From Noah.org

Jump to: navigation, search

Passwords are hard to remember. Randomly generated passwords are just annoying. Here is my password strategy... I string together a few easy to pronounce phonemes followed by a number.

I use a password safe to keep track of all my passwords. When I look up a password it's handy to be able to remember the password for a couple minutes without having to write it down. I find that if I pronounce a nonsense word plus a number in my head that I can remember it for a few minutes. Here are some examples of random, nonsense passwords that are still easy to pronounce. To me these sound like the names of giant Japanese fighting robots.

 todami54
 zukeka08
 bagopu48
 gomipu79
 jiyiku70

There are other password generators such as `apg` and `pwgen`. None one of thsse make passwords that are easy to pronounce or remember. They claim to be "pronounceable", but they don't work for me. Here are some examples from `pwgen`. These are terrible!

 ieL6gae8 fa1Oob7N Coh3uiso aijai1Qu uK0eeXup Ejooch1g ush1xuGa Otiup4Qu

What is the point of making a password that is only slightly easier than impossible to pronounce? You are still going to have to write it down. You still won't remember it a few minutes later.

This script will by default generate 61,412,500 unique passwords. That may not seem like very many, but most SSH daemons will only allow one login attempt per second, so it would still take nearly 2 years to try them all. This script also allows you to adjust the size of the password.

Passwords are a bad idea anyway. I use this along with public keys and an automatic ban system such as `fail2ban` which blocks out an IP address for a period of time if there are too many failed login attempts.

Click here to download this script: randpass

#!/usr/bin/env python
 
"""
SYNOPSIS
 
    randpass [-h, --help] [--cap] [--nato]
 
DESCRIPTION
 
    This generates a random password that is easy to pronounce. The passwords
    are built up of pairs of Conssonants and Vowels. It helps to read the
    letters in pairs. These passwords are easy to pronounce and I found that I
    can remember them for a few minutes without trying very hard.
 
    This is not intended to create great passwords, but "good enough"
    passwords. Some misguided admins create passwords so complicated that
    they guarantee that I will never remember them.
 
    The "apg" program uses an algorithm defined in FIPS PUB 181 which claims,
    "Approximately 18 million 6-character, 5.7 billion 8-character, and 1.6
    trillion 10-character passwords can be created by the program." The "pwgen"
    program simimlarly generates passwords. I don't find either of those
    password generators to create very pronouncable passwords. Most
    authentication systems limit login attempts, so I think these numbers are
    academic. The system in this script by default yields up to 61,412,500
    8-letter passwords -- which may not be a lot if you are using this for your
    recall codes, but at least it beats "poe". If the passwords are not long
    enough for your application then use the --num option to create a longer
    password. By default this script creates passwords made of three pairs of
    letters plus two digits (8 characters total).
 
EXAMPLES
 
    $ randpass
    mayomi22
 
    $ randpass --cap
    MoNuRi45
 
    $ randpass --nato
    wenogu36, "whiskey echo november oscar golf uniform three six"
 
    $ randpass --cap --nato
    HeSoTu95, "hotel echo sierra oscar tango uniform nine five"
 
    $ randpass --num=6
    hiwasitagumo67
 
AUTHOR
 
    Noah <noah@noah.org>
 
LICENSE
 
    This script is in the public domain, free from copyrights or restrictions.
 
VERSION
 
    $Id: randpass.py 144 2007-12-19 01:00:41Z root $
"""
 
import sys, os, traceback, optparse
import random
 
def nato (s):
 
    """This translates a string into NATO phonetics.
    """
 
    alpha = {'a':'alpha', 'b':'bravo', 'c':'charlie', 'd':'delta',
            'e':'echo', 'f':'foxtrot', 'g':'golf', 'h':'hotel', 'i':'india',
            'j':'juliet', 'k':'kilo', 'l':'lima', 'm':'mike', 'n':'november',
            'o':'oscar', 'p':'papa', 'q':'quebec', 'r':'romeo', 's':'sierra',
            't':'tango', 'u':'uniform', 'v':'victor', 'w':'whiskey',
            'y':'yankee', 'z':'zulu',
            '0':'zero', '1':'one', '2':'two', '3':'three', '4':'four',
            '5':'five', '6':'six', '7':'seven', '8':'eight', '9':'niner'}
    s = s.lower()
    n = ''
    n = [n+alpha[c] for c in s if c in alpha]
    n = ' '.join(n)
    return n
 
def main ():
 
    global options, args
 
    #C = ('th','ch','w','r','t','y','p','s','d','f','g','h','j','k','z','v','b','n','m')
    C = ('w','r','t','y','p','s','d','f','g','h','j','k','z','v','b','n','m')
    V = ('a','e','i','o','u')
    ph = [(c+v) for c in C for v in V]
    pc = len(ph)
 
    p = []
    for i in range(options.num):
        if options.cap:
            p.append (ph[random.randrange(pc)].capitalize())
        else:
            p.append (ph[random.randrange(pc)])
    n3 = random.choice('0123456789')
    n4 = random.choice('0123456789')
    if options.verbose:
        print "%d possible %d phoneme words" % (pow(pc,options.num),options.num)
        print "%d possible with a two digit random number" % (pow(pc,options.num)*100)
    pw = ''.join(p) + n3 + n4
    if options.nato:
        print pw + ', "' + nato(pw) + '"'
    else:
        print pw
 
if __name__ == '__main__':
    try:
        parser = optparse.OptionParser(formatter=optparse.TitledHelpFormatter(), usage=globals()['__doc__'], version='$Id: py.tpl 144 2007-12-19 01:00:41Z root $')
        parser.add_option ('-v', '--verbose', action='store_true', default=False, help='verbose output')
        parser.add_option ('-p', '--nato', action='store_true', default=False, help='NATO phonetic output')
        parser.add_option ('-c', '--cap', action='store_true', default=False, help='Capitalize each phoneme')
        parser.add_option ('-n', '--num', type='int', default=3, help='Number of phonemes')
 
        (options, args) = parser.parse_args()
        #if len(args) < 1:
        #    parser.error ('missing argument')
        main()
        sys.exit(0)
    except KeyboardInterrupt, e: # Ctrl-C
        raise e
    except SystemExit, e: # sys.exit()
        raise e
    except Exception, e:
        print 'ERROR, UNEXPECTED EXCEPTION'
        print str(e)
        traceback.print_exc()
        os._exit(1)
-->