Correct Horse Battery Staple
April 23, 2013
In his 936th xkcd comic strip, Randall Munro described what is wrong with common passwords and suggested a method of passphrase generation that is simpler to use and provides greater security. Unfortunately, I know of no popular websites that permit xkcd-style passphrases. I do still recall, however, the xkcd-style passphrase that CompuServe assigned me about twenty-five years ago (does anyone else remember upgrading from a 1200 baud modem to 9600 baud?)
Your task is to write an xkcd-style passphrase generator. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
perl -e ‘
my @pass = ();
my @arr = ();
while (){
chomp;
#Pick words of 6+ chars
push @arr, $_ if /.{5}.+/;
}
for (my $i = 0 ; $i < 5 ; $i++){
# Passphrase is 5 random words
push @pass, $arr[rand $#arr];
}
print ((join " ", @pass) . "\n");
' dictionary.txt
That while in there should have a open and close angle brackets inside the parens, but the website seems to have stripped them off.
Heh… as it happens, I wrote one in response to the xkcd strip. Note that this is guaranteed to only use a given word once.
my %words = read_words();
my @chosen = ();
for my $i (1 .. $num_words) {
my @keys = keys %words;
my $word = $keys[ rand(@keys) ];
push @chosen, $word;
delete $words{$word};
}
To ease compatibility with websites that have complexity requirements, you can upper-case the first letter and add a period on the end.
I have successfully used this strategy with Google, Facebook, Reddit, Twitter, LinkedIn…
[…] today’s Programming Praxis exercise, our goal is to generate xkcd-style passphrases consisting of four […]
My Haskell solution (see http://bonsaicode.wordpress.com/2013/04/23/programming-praxis-correct-horse-battery-staple/ for a version with comments):
import Data.Char import System.Random.Shuffle valid :: String -> Bool valid s = length s > 4 && length s < 10 && all isLower s main :: IO () main = putStrLn . unwords . take 4 =<< shuffleM . filter valid . lines =<< readFile "en_US.dic"from random import choice as c import sys def isvalid(word): return word.islower() and word.isalpha() and 4 < len(word) < 10 WORDS = [w for w in sys.stdin.read().split() if isvalid(w)] print '%s %s %s %s' % (c(WORDS), c(WORDS), c(WORDS), c(WORDS))Upgrading from 1200 baud to 9600 baud? I remember flamewars about the difference between baud and bps (I don’t even remember the maximum capacity of a telephone line – was it 2400baud? Each baud can carry many bits) – and I remember reading them at 300bps. Just about fast enough to read (if there were not too many ANSI-codes to change color)…
We even soldered a 2400bps modem in school. Try doing that with a todays 953BGPA chip…
And now I’m in a country where 128kbps is the top of the line for 100$/month. I’m feeling young again.
Python version.
import random def gen_pass_phrase(k=4): with open("/12dicts/2of12.txt", "rt") as f: words = [w for w in f.read().split() if len(w) < 9] return ' '.join(random.sample(words, k))When testing this routine it generated this pass-phrase: fuzzy pompous fiancee sally
I remember using a 300 baud acoustically coupled modem.
Scala –
def randPw (k: Int): String = { val lines = scala.io.Source.fromFile("/usr/share/dict/words").mkString.split("\n") def pickRand (k: Int) : String = { if (k <= 0) "" else lines(scala.util.Random.nextInt(lines.length).abs) + pickRand(k-1) } pickRand(k) } randPw(4)Reblogged this on David James Coding Blog and commented:
Excited to attempt this challenge, maybe even generate my new password out of it!
Guile:
(use-modules (ice-9 rdelim) ; read-line (ice-9 streams) (srfi srfi-1) ; lists (srfi srfi-26)) ; cut/cute ;;; Generate a password of four random words. (let* ((words (stream->vector (port->stream (open-input-file "/usr/share/dict/words") read-line))) (count (vector-length words))) (display (string-join (map (cut vector-ref words <>) (map (lambda (x) (random count)) (iota 4))) " ")) (newline))Using iota and map to make the list of four random numbers seemed silly, so I did it. ^_^