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.

Pages: 1 2

11 Responses to “Correct Horse Battery Staple”

  1. Anon said

    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

  2. Anon said

    That while in there should have a open and close angle brackets inside the parens, but the website seems to have stripped them off.

  3. Maurits said

    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…

  4. […] today’s Programming Praxis exercise, our goal is to generate xkcd-style passphrases consisting of four […]

  5. 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"
    
  6. Daniel Näslund said
    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))
    
  7. Linus said

    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.

  8. Mike said

    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.

  9. 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)
    
  10. Reblogged this on David James Coding Blog and commented:
    Excited to attempt this challenge, maybe even generate my new password out of it!

  11. fisherro said

    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. ^_^

Leave a comment