Dictionary Password Generator in Powershell
A fellow at work wanted a script to generate strong passwords from a dictionary file. The "l337" hashtable in the first line is the list of characters that we'll be replacing. The $skip variable adds a little variance so we won't (likely) generate the same password twice given the same word.
$leet = @{e=3;o=0;l=1;a=4;i='!';t=7}
$rand = new-object System.Random
$words = import-csv dict.csv
$word = ($words[$rand.Next(0,$words.Count)]).Word
if ($args[0]) { $word = $args[0] }
$leet.Keys | foreach-object { $skip = $rand.Next(0,3); if ($skip -ne 0){ $word = $word.Replace($_,$leet[$_]) } }
$word
Here's the dictionary I used: File Attachment: dict.csv (6 KB)
> ./generate-password.ps1
1ass!7ude
!nterd!ct
c4j013
par!ah
ruff!4n
r3cant
pl3th0r4
> ./generate-password.ps1 "quixotic"
qu!x07!c
quixo7ic
quix0tic
UPDATE: Jeff opines (correctly) passphrases are where it's at, so...
$rand = new-object System.Random
$conjunction = "the","my","we","our","and","but","+"
$words = import-csv dict.csv
$word1 = ($words[$rand.Next(0,$words.Count)]).Word
$con = ($conjunction[$rand.Next(0,$conjunction.Count)])
$word2 = ($words[$rand.Next(0,$words.Count)]).Word
return $word1 + " " + $con + " " + $word2
Yielding:
> ./generate-passphrase.ps1'
foible my finesse
bolster but permeate
augury my dogmatic
surfeit the mercurial
reconcile but dexterity
acarpous our inveigh
perilous and bequest
cognizant we foible
calipers and vilify
trickle our enzyme
vigorous we ominous
ascertain + dubious
suborn but middling
I totally agree that passphrases are better. I've advocated them to family and friends and have a few long-ass passphrases myselfs
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
A great suggestion that Jeff Gibson made in the Security Now! podcast is to invent your own personal password algorithm that can be applied to a variety of sources. Something like "1" + [the first three letters of the site in reverse order] + "24! + [capitalized last letter of the site]. You won't have to remember every different password, just the algorithm, and its invulnerable to dictionary attacks.
I adopted this type of strategy about 6 months ago, and my passwords are not only much stronger, but I don't need to store them.
1) If the stars aligned and a character was being replaced with its 1337 equivilent, it was replaced throughout the entire password. While probably easier to remember, it's a level of predictability that I'm not comfortable with in a password generator.
2) A number of words in the dictionary are shorter than 8 characters. Many systems require 8 characters minimum.
3) Even though I'm a 1337 633|< myself, it sometimes takes me a second to realize what the 1337 word is supposed to be.
So I took the liberty of addressing these issues.
$leet = @{e=3;o=0;l=1;a=4;i='!';t=7}
$paddingchars = "abcdefghijklmnopqrstuvwxyz01234567890".ToCharArray()
$rand = new-object System.Random
$words = import-csv dict.csv
$word = ($words[$rand.Next(0,$words.Count)]).Word
if ($args[0]) { $word = $args[0] }
$outputchars = $word.ToCharArray()
$outputchars | foreach-object { $i=0 }{ $skip = $rand.Next(0,3); if ( $skip -ne 0 -AND $leet.ContainsKey([string]$_) ) { $outputchars[$i] = [char][string]$leet[[string]$_]}; $i+=1 }
while ($outputchars.Length -lt 8) { $outputchars += $paddingchars[$rand.Next(0,$paddingchars.Length)]}
$OFS = ""
$originalword = $word
$word = [string]$outputchars
"Generated password: $word (based on '$originalword')"
(gee, I hope that displays okay as a dasBlog comment)
A couple of other things I would have done if I didn't actually have to get some work done today:
- random capitalization
- passing of minimum length as a parameter (rather than hard-coded as 8)
Of course, I'm a day late and a dollar short, since Jeff correctly pointed out that passphrases are a better solution.
Awesome tool, maybe you'll add it to your Must Have tools list. Check it out. No, I don't work for them, just a happy user. It's free for up to 10 passwords too!
BOb
Comments are closed.
I wish more users would adopt passphrases:
http://www.codinghorror.com/blog/archives/000360.html
Perhaps you can code an example of powershell building a much more secure *AND* easier to remember passphrase from that same dictionary?