#!perl # Fun script to generate a password from "random" characters. Passwords # generated by this script will be eight characters in length and contain # exactly two numeric characters. # Created 06-2000 by Andrew Greenburg <andrew@analogmarketing.net>. # Modified 02-2001 by Andrew Greenburg <andrew@analogmarketing.net>. # If we have a dictionary file, where is it? # WARNING: Checking for real words makes this process amazingly slow. # $dictfile = "/usr/share/dict/words"; # If there is an argument, that's our number of passwords. if (length($ARGV[0])) { chomp($passnum = $ARGV[0]); } else { $passnum = 1; } # If the argument was bad, tell the user. if ((!($passnum =~ /^[0-9]+$/)) || ($passnum == 0)) { die "Usage: $0 <number of passwords>\n"; } # Seed the random number generator. srand(time ^ $$ ^ unpack "%L*", `ps auxww | gzip`); # Read the dictionary into memory. &dictread; # Do this as many times as the user wants. for ($count = 0; $count < $passnum; $count++) { # Initialize the variables. $pass = ""; $goodpass = 0; # Run this loop until we get one we like. while ($goodpass != 1) { &passgen; &passcheck; } # Print it and we're done. print "$pass\n"; } exit 0; # This subroutine throws together the characters. sub passgen { # Reset the variables. $pass = ""; # Add until we have eight of 'em. for ($i = 0; $i < 8; $i++) { # Pull a random number out. $number = int(rand(36)); # We only want numbers and lowercase letters. if ($number < 10) { # It's a number. Make it an ASCII number. $output = $number + 48; } else { # It's a letter. Make it an ASCII letter. $output = $number + 87; } # Make that ASCII number a character. $new = chr($output); # Append the character to the password. $pass = "$pass$new"; } } # Now we decide whether this password is suitable. Now we check for dictionary # words! (10-31-2000) sub passcheck { # Two numbers or else! $pass =~ /[0-9].+[0-9]/ || return; # But, we don't want more than two. $pass =~ /[0-9].*[0-9].*[0-9]/ && return; # From 0-9, for ($i = 0; $i < 10; $i++) { # Let's make sure they're not both the same number. $pass =~ /$i.*$i/ && return; } # From "a"-"z", for ($i = 97; $i < 123; $i++) { # Check each letter. $chkchr = chr($i); # No double letters. $pass =~ /$chkchr{2,}/ && return; # No more than two of each in a password. $pass =~ /$chkchr.*$chkchr.*$chkchr/ && return; } # Check it against the dictionary. if ($#words) { foreach $word (@words) { # Does our password contain this real word? $pass =~ /$word/ && return; } } # We passed our tests. $goodpass = 1; } # Maybe this will make the batch processing faster, if we only access the file # once... sub dictread { # Open the dictionary file for reading. # You might not want to bother with this if you're doing them in # batches, because it makes everything crawl. if (open (DICTIONARY, "$dictfile")) { while (<DICTIONARY>) { # Make it case insensitive, kill those pesky newlines. chomp($currentword = lc($_)); # If it's two or fewer letters, we're not concerned. if ((length($currentword) <= 2)) { next; } # Add it to the array push(@words, $currentword); } # That wasn't so bad, was it? close (DICTIONARY); } }