NOTE: This an old post I'm bring forward from my old blog. It was for a proof of concept password generator using /dev/urandom, then OpenSSL on a Linux system. It is not has no error checking or validation of the passwords it produces, so the user is on their own to verify them.
12/25/16: Original writing
The evolution of this generator has been messy, going from a crazy one-liner Bash shell script that pulled alpha-numeric chars from the /dev/urandom file to automating said one-liner using crontab to write to a file read by PHP on my website. As I said...messy, so I went back to the drawing board looking for a cleaner solution as well as an easy way to integrate symbols.
openssl rand -base64 $(openssl rand -base64 2000 | tr -dc [:digit:] | fold -w 2 | egrep "10|11|12|13|14" | head -1)
I read here that PHP works well with openssl as opposed to trying to read from urandom so I starting testing and found I could get much cleaner results with far fewer keystrokes. My latest script accomplishes the following:
- openssl generates a 2000 char long randomized string
- tr carves out all the numbers fro the string.
- fold binds the individual chars into pairs, like 13 43 87 ... etc, creating a sort of memory stack if you will.
- Pipe (|) string through egrep and pop the first pair between 9 and 15 to get the password length.
While limited to 10-14, I feel those lengths as well as their arbitrary creation is quite sufficient, though you can tune as desired/required.
Now that I have my password length, my final step to simply wrapping it in a 'openssl rand' statement. Alpha-numeric and symbol sets are all included, though there is nothing programmatically forcing them to all be used for each password.
If you'd like to see my original script for doing mostly the same thing using /dev/urandom, see below:
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $(cat /dev/urandom | tr -dc '0-9' | fold -w 2 | head -100 | egrep "10|11|12|13|14" | head -1) | head -1
So what exactly does does this old thing do? Well, lets break it down from the middle and work our way out.
... $(cat /dev/urandom | tr -dc '0-9' | fold -w 2 | head -100 | egrep "10|11|12|13|14" | head -1) ...
This call to /dev/urandom generates a random list of 100 two-digit numbers that looks like this:
$ cat /dev/urandom | tr -dc '0-9' | fold -w 2 | head -100
73 39 29 40 55 . . .
From this large list the script greps out in order of appearance the numbers 10-14
(...| egrep "10|11|12|13|14" | ...)
These are potential lengths of our final password:
$ cat /dev/urandom | tr -dc '0-9' | fold -w 2 | head -100 | egrep "10|11|12|13|14" 14 10 14 14 10 ...
From what is grepped out, the top number (head -1) is selected.
$ cat /dev/urandom | tr -dc '0-9' | fold -w 2 | head -100 | egrep "10|11|12|13|14" | head -1 14
Since the orginal list of 100 two-digit numbers is randomly generated, one cannot predict which number will be popped off the top. In this case the length will be 14 characters long, yet other times it will likely be something different, effectively randomizing the length of our passwords rather than hard coding value lengths.
Now that we have our length set, what about the rest? Lets take a look. To make it easy I'm going to substitute $pwlength for password length:
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $pwlength | head -1
As you can see, all that is really new here is the 'tr' designations. Since I want my password of $pwlength to contain mixed case and numbers (no special characters...yet), I simply add those items and let the computer create a new list of random passwords from which I can choose:
$ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w $pwlength | head -1 lZnrBrbeBd
Once I plug all this into a script I can alias in my .bashrc all that I need to do is run 'pwrand' and I have a solid password generated somewhere between 10 and 14 characters.
$ pwrand Q5G6aJ2MNPQ