Generating Good Passwords, Part I

Dave starts a new method for generating secure passwords with the help of 1Password.

A while back I shared a script concept that would let you enter a proposed password for an account and evaluate whether it was very good (well, maybe "secure" would be a better word to describe the set of tests to ensure that the proposed password included uppercase, lowercase, a digit and a punctuation symbol to make it more unguessable).

Since then, however, I've really been trying personally to move beyond mnemonic passwords of any sort to those that look more like gobbledygook. You know what I mean—passwords like fRz3li,4qDP? that turn out to be essentially random and, therefore, impossible to crack using any sort of dictionary attack.

Aiding me with this is the terrific password manager 1Password. You can learn more about it here, but the key feature I'm using is a combination of having it securely store my passwords for hundreds of websites and having a simple and straightforward password generator feature (Figure 1).

Figure 1. 1Password Password Generation System

If I'm working on the command line, however, why pop out to the program to get a good password? Instead, a script can do the same thing, particularly if I again tap into the useful $RANDOM shortcut for generating random numbers.

Generating Secure Passwords

The easiest way to fulfill this task is to have a general-purpose approach to generating a random element from a specific set of possibilities. So, a random uppercase letter might be generated like this:


uppers="ABCDEFGHIJKLMNOPQRSTUVWXYZ"

letter=${uppers:$(( $RANDOM % 26 )):1}

The basic notational convention used here is the super handy Bash shell variable slicing syntax of:


${variable:startpoint:charcount}

To get the first character only of a variable, for example, you can simply reference it as:


${variable:1:1}

That's easy enough. Instead of a fixed reference number, however, I'm using $(( $RANDOM % 26 )) as a way to generate a value between 0–25 that's different each time.

Add strings that contain all the major character classes you seek and you've got a good start:


lowers="abcdefghijklmnopqrstuvwxyz"
digits="0123456789"
punct="()./?;:[{]}|=+-_*&^%$#@!~"  # skip quotes

To get even fancier, there's another notation ${#variable} that returns the number of characters in a variable, so the following shows that there are 24 characters in that particular string: