Search

The LJ Password Generator Tool

Mnemonic passwords generally stink. A random
sequence of letters, digits and punctuation is more secure—just don't
write down your passwords, like the knucklehead antagonist does in Ready
Player One!

In the password generating tool from my last
article,
at its most simple, you specify the number of characters you want in the
password, and each is then chosen randomly from a pool of acceptable values.
With the built-in RANDOM in the Linux shell, that's super easy to do:

In the actual script, I set okay to a single value rather than
build it in
two steps; this is just for formatting here online. Otherwise,
ltrs is set to
the length of $okay as a speedy shortcut, and the result is built up by using
the string slicing syntax of:

${variable:indexlocation:length}

To extract just the fourth character of a string, for example,
${string:4:1}, this
works fine and is easy. The result speaks for itself:

Where this becomes a more complex challenge is when you decide you
don't want to have things randomly selected but instead want to weight
the results so that you have more letters than digits, or no more than a few
punctuation characters, even on a 15–20 character password.

Which is, of course, exactly what I've been building.

I have to admit that there's a certain lure to making something complex,
if nothing else than just to see if it can be done and work properly.

Adding Weight to Letter Choices

As a result, the simple few lines above changed to this in my last
article:

In the above code, I'm assigning probability that a given letter will be
one of four classes: uppercase, lowercase, punctuation or digits. The first
three are each 2:7 chances, and punctuation is 1:7, or half as likely to be
produced.

A run of four iterations of the above algorithm produces these results:

q.x0bAPmZb
P}aWX2N-U]
5jdI&ep7rt
-k:TA[1I!3

Since random is, well, random, in both situations, you actually can end up
with a password that includes no punctuation. So, how do you force a specific
number of occurrences of punctuation symbols? One solution is to check after
the fact to see if you met your target count.

To do that, you'll need two things: goals and counters. Let's add
the former as startup options in a typical getops block:

If the total length of the requested password is reasonable compared to the
random chance that a digit or punctuation character will be added, this will
work fine. A 15-character password with at least two punctuation
characters will be generated without a hiccup almost every single time.

This begs the most important question of the script algorithm: what do
you do once you realize that you haven't met your digit and punctuation
character goals?

Failed Password Generation: Now What?

One solution is simply to try again, but if the user sets up an impossible
situation, like a six-character password with four digits and four
punctuation characters, or
even four and two, that's no bueno.

Another possibility is to step through the generated password, replacing
unconstrained values (such as upper and lowercase) with the specific value
required. This has the consequence that if you ask for a lot of punctuation
or digits, you're going to end up having those requested characters
front-loaded, which isn't exactly random.

So, Let's Rethink the Problem

What if, instead of producing a random password, you split it into two steps?
The first step is to generate the required number of random digits and
random punctuation characters, add completely random values to add up to the
desired length, then "shuffle" the result to produce the final
password.

I know, you're almost done with this program, but that's a really
interesting solution that sidesteps a lot of problems, so let's just
retrench and start over!

Actually, it's not that bad, because most of the work's already been
done. This will just make it simpler:

You clearly can see how these are front-loaded, with the digits required,
the punctuation required and then "everything else".

There are a lot of ways to shuffle the letters in a word within a shell
script, ranging from invoking Perl or Awk to using the Linux
shuf command to
solving it yourself. I'm going to leave this as an exercise for the
reader, because with that small added step, you've got a fully functional
password generator that's ready to take on your hundreds of system
users.

Dave Taylor has been hacking shell scripts on UNIX and Linux systems for a
really long time. He's the author of Learning Unix for Mac OS
X and Wicked Cool Shell Scripts. You can find him on Twitter
as @DaveTaylor, and you can reach him through his tech Q&A site: Ask Dave Taylor.