We all know the right way to select a password, right? Mix upper and lower case, pick random letters, mix in some numbers and punctuation, and try to remember the final result for longer than 30 seconds. If you assign passwords like this to users, it's a matter of minutes before the religious radio station emails you with a request that his/her password be changed to "Jesus".
So I tried to grok the problem and come up with a solution. Why not use random passwords that are actually based on real language? I mean, people are used to being able to pronounce things, more or less, and certain patterns are more comfortable to remember. It's like phone numbers. String 8562621937 together, and it's tough to remember. Format it as 856-262-1937 and most people can recall it without too much trouble. (The area code is South Jersey, but I don't know whose number that is...I wouldn't suggest you dial it ;)
The algorithm I proposed to some security-minded friends is as follows:
No, it's not as secure as randomly picking all characters in any order. But it is a lot easier to remember the result, since you can usually pronounce it. Often it sounds like a real word. (Sometimes this is a problem...users probably don't want a password that has "feces" in it ;)
Here are some of the passwords this program generated for me:
Update 2 aug '01: Forgot my -w on the shebang line. Mea culpa. Applied said -w and was pleased there was nothing else to fix.
<CODE>#!/usr/bin/perl -w use strict; # some constants useful for changing the configuration use constant MIN_LENGTH => 6; use constant MAX_LENGTH => 12; use constant MIN_SAMPLES => 750; # min samples is the minimum number o +f times # a vowel-consonant pattern appears i +n the dictionary sub parsedict { # this sub parses a dictionary file (specified at the command line # into a series of vowel-consonant patterns, weighted by the number # of times each pattern appears in the dictionary. It writes the # hash of patterns and weights to a file called "lingua". It also # tracks the frequency of use for each letter of the alphabet, and # stores that information in a file called "letters". my @consonants = split //, 'bcdfghjklmnpqrstvwxz'; my @vowels = split //, 'aeiouy'; my (%letters, %letterdist, %result, %stats); foreach (@consonants) { $letters{$_} = "c"; } foreach (@vowels) { $letters{$_} = "v"; } while (<>) { chomp; my @chars = split //, lc($_); my $mapped; foreach (@chars) { $mapped .= $letters{$_}; $letterdist{$_}++; } $result{$mapped}++; $stats{"words"}++; } open LINGUA, ">lingua"; foreach (sort { $result{$b} <=> $result{$a} } keys %result) { (length($_) >= MIN_LENGTH - 2 && length($_) <= MAX_LENGTH - 2 && $ +result{$_} >= MIN_SAMPLES) and do { print LINGUA "$_\t$result{$_}\n"; $stats{"patterns"}++; } } close LINGUA; open LETTERS, ">letters"; foreach (sort { $letterdist{$b} <=> $letterdist{$a} } keys %letterdi +st) { print LETTERS "$_\t$letterdist{$_}\n"; } close LETTERS; return "Parsed $stats{'words'} words into $stats{'patterns'} pattern +s within criteria.\n"; } sub genpass { # this sub chooses a pattern at random from the lingua file, and exc +hanges # 'c's and 'v's in the pattern with consonants and vowels, respectiv +ely, # based on a random letter selection weighted by the frequency of ea +ch # letter in the dictionary file. # first, choose a pattern from the lingua file srand; # not strictly necessary as current versions of perl do this +automatically my @pattern; open (LINGUA, "<lingua") or die "Could not open lingua file: $!"; rand($.) < 1 && (@pattern = (split /\t/)) while (<LINGUA>); close LINGUA; # second, parse the letters file and build a hash of letters and wei +ghts my (%cons, %vowels, $constotal, $voweltotal); open (LETTERS, "letters") or die "Could not open letter file: $!"; while (<LETTERS>) { chomp; my ($key, $value) = split /\t/; if ($key =~ /[aeiouy]/) { $voweltotal += $value; $vowels{$key} = $ +voweltotal; } else { $constotal += $value; $cons{$key} = $ +constotal; } } # build a couple of routines for randomly selecting vowels and conso +nants # these two routines could be combined into one, but i was too lazy +to do it # the most elegant way...so it's like this. my $randomvowel = sub { my $index = rand($voweltotal); my $choice; foreach (sort { $vowels{$b} <=> $vowels{$a} +} keys %vowels) { $choice = $_; if ($vowels{$_} < $index) { last; } } return $choice; }; my $randomcons = sub { my $index = rand($constotal); my $choice; foreach (sort { $cons{$b} <=> $cons{$a} } ke +ys %cons) { $choice = $_; if ($cons{$_} < $index) { last; } } return $choice; }; # here's where we actually map random characters into the pattern my @tomap; my @orig = split //, $pattern[0]; foreach (@orig) { push @tomap, ($_ eq 'c') ? &$randomcons : &$random +vowel; } # good passwords will have at least one letter capitalized. choose o +ne here. # note that not all letters are given capital equivalents, making it + easier # to identify "confusing" letters. There are no capital O's, only ze +ros, # for example. my @case = split //, 'ABCDEFGHiJKLMNoPQRSTUVWXYZ'; my $ucpos = int (rand(@orig)); $tomap[$ucpos] = $case[ord($tomap[$ucpos]) - 97]; # good passwords also use some non-alpha characters, interspersed. t +his # algorithm tacks one on the front, and one on the back of the passw +ord # it just generated. not the most secure way to do it, but better th +an # not doing it (and still easy for the user to work with.) my @puncs = split //, '!?@#$%&0123456789'; my $mapped = $puncs[rand(@puncs)] . (join '', @tomap) . $puncs[rand( +@puncs)]; # finally, return the generated password. return $mapped . "\n"; } # simple enough main... # if an argument is given, parse it as the dictionary. if not, # generate a password. print @ARGV ? parsedict : genpass;
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Password generator using a linguistic rule base
by astaines (Curate) on Aug 02, 2001 at 01:40 UTC | |
by ginseng (Pilgrim) on Aug 02, 2001 at 01:57 UTC | |
|
Re: Password generator using a linguistic rule base
by bastard (Hermit) on Aug 02, 2001 at 02:53 UTC | |
by ginseng (Pilgrim) on Aug 02, 2001 at 03:17 UTC | |
by bastard (Hermit) on Aug 02, 2001 at 20:56 UTC | |
|
Re: Password generator using a linguistic rule base
by Chrisf (Friar) on Aug 01, 2001 at 18:16 UTC | |
|
Re: Password generator using a linguistic rule base
by I0 (Priest) on Aug 02, 2001 at 04:16 UTC | |
by Nitsuj (Hermit) on Aug 18, 2001 at 20:54 UTC |