Aaron S. Hawley (aaronhawley) wrote,
Aaron S. Hawley

Shell hack: Random password generator

In a previous post about shell hacking, I wrote.

"The command tools in unix shell programming are general enough to do pretty monumental tasks using a small number of commands -- in both breadth and length. Even a little bit of properly written complex shell programming can write a pretty full-proof command -- as a proof-of-concept or as a temporary solution until you discover a shortcoming. [...] Although rare, if the shell doesn't have what you need, then you're using the wrong tool."

In that spirit, I wanted to see how the shell and its sister tools in unix-land could handle generating random passwords.

After searching around a bit, I was able to find some good strategies for generating random passwords with the shell, but nothing I was entirely pleased with. The following was the best implementation that fit my needs.

The canonical method to get an unlimited number of bits on a unix system is with the system device /dev/urandom. For shell programming, it can handily spit out random characters for you. I don't want every character possible, however. For the purpose of generating random passwords, the alpha-numeric and punctuation characters would be enough. I don't need the passwords to be human-readable or memorable. I want random. No word dictionaries, no weight on certain characters over others.

The tr command can filter the characters you want, and the head command can limit the number of characters you want. To get 6 random characters that are either alpha-numeric or punctuation you can use the following command in GNU Bash.

  $ tr -dc "[:alnum:][:punct:]" < /dev/urandom | head -c 6 && echo

The echo inserts a newline for display purposes after the characters are printed, since neither tr, /dev/urandom, or head insert an endline character for you.

According to the GNU Grep user manual , there are 32 punctuation characters in ASCII. That means there are a total of 94 distinct characters available to a random password here. If we generated just an 8 character password, that would give -- 94 to the power of 8 (948) -- 6,095,689,385,410,816 (6.1e15) different possibilities, roughly 2 to the power of 52 (252).

The other desirable characteristic of a random password generator is to have variable password lengths. How to generate a random integer in the shell? Most Bourne shells -- including GNU Bash -- have a built-in RANDOM environmental variable whose value is a random number.

  $ echo $RANDOM

To generate a random number between 8 and 16 -- inclusive:

  $ ( min_length=8; \
      max_length=16; \
      echo $(( $RANDOM % ($max_length - $min_length + 1) + $min_length )) )

Combine this all together.

  password=$(tr -dc "[:alnum:][:punct:]" < /dev/urandom \
             | head -c $( RANDOM=$$; echo $(( $RANDOM % (8 + 1) + 8 )) ) )
  echo "${password}";

Note, it's good practice to seed the random number generator with the current process number -- RANDOM=$$;, even though most shells properly initialize it, already.

How many distinct passwords of this type are available between 8 and 16 characters? According to my handy Emacs calculator, the sum of the series of 94 to the power of k where k ranges from 8 to 16 gives 37,556,971,331,618,802,283,689,774,779,136 (3.76e31) different possible passwords -- approximately 2 to the power of 104 (2^104).

I needed a random password generator to automatically reset a system password for accounts at my workplace. These accounts allowed remote SSH access for scheduled jobs with password-less, passphrase-less private-key access. We couldn't restrict logins to the account using password authentication methods, but needed a way to effectively disallow traditional password authentication. The solution was to use the result of the shell random password generator to feed the passwd command on a regular basis.

# ( password=$(tr -dc "[:alnum:][:punct:]" < /dev/urandom \
               | head -c $( RANDOM=$$; \
                            echo $(( $RANDOM % (8 + 1) + 8 )) ) ); \
    echo "${password}"; echo "${password}"; ) | passwd USERNAME
New UNIX password: Retype new UNIX password: passwd: password updated successfully

More appropriately, password administration on most GNU/Linux systems can be done with the chpasswd command.

# ( user=warehouse; \
    password=$(tr -dc "[:alnum:][:punct:]" < /dev/urandom \
               | head -c $( RANDOM=$$; \
                            echo $(( $RANDOM % (8 + 1) + 8 )) ) ); \
    echo "${user}:${password}" ) | chpasswd

Admittedly, this scriptlet is about as good as the pwgen command with the -s and -y options a program written in C and Perl.

For further reading, see pwgen.sh where I have accumulated all of this together into a shell script.

Tags: free software, howto, programming, unix
  • Post a new comment


    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.