The 2011 #DecoDeme challenge – the final, official version

At last! The final, conference-ready code for the #decodeme challenge is here.

Each year, at the AusCERT conference, Sophos publishes a challenge in the form of a T-shirt. Visit the Sophos stand and you can pick up a T-shirt for yourself.

Solve the challenge and you’re on your way to winning a remote controlled tank. You can read up on how to win here, or ask us when you pick up your shirt.

We made this year’s puzzle fairly easy, as you’ve only got until 14:30 on Monday 16 May 2011 to solve it. Even a brute-force attack on the keyspace needs fewer than 500,000 tries. With a suitable dictionary, the search space drops below 5000. If you assume that the answer includes at least one four-letter English word, your search space drops to about 1000.

So happy puzzling!

You can, of course, ask for hints at the conference. You can also follow me on Twitter(@duckblog) and watch out for clues with the hashtag #decodeme.

An extracted, re-formatted and updated version of the puzzle code can be grabbed below. Since our stand theme this year is Monty Python, the puzzle source language simply had to be Python. The code below shows you how to do three sorts of attack on the puzzle – by guesswork, by dictionary, and by brute force. The code has been tested with Python 2.6.1 on OS X (64-bit) and Python 2.7.1 on Linux 2.6 and Windows XP (32-bit).

By the way: congratulations to those who’ve already solved the T-shirt part – there are several of you who have already let me know that you’re there. Special congrats to David, whose has gone so far as to suggest on Twitter some alternative values for the ciphertext in the puzzle. (Nice try, David. But I remain unmoved by your protestations.)

import random, sys

#--------------------

def usage():
  print('Use: -f file to use a list,\n'+
        '     -i for interactive, or\n'+
        '     -a for brute force')

#-------------------- 

def anothershrubbery(ni):
 h=0
 for i in (0,1,2,3):
  h=h*256+ord(ni[i])
 return h+9628088427666806188

#-------------------- 

def shrubbery(ni):
 p='iwgegsaccwdbtadoz'
 k=dict([[i,chr(97+i)] for i in range(26)])
 random.seed(anothershrubbery(ni))
 random.shuffle(k)
 k=dict([[v,i] for i,v in k.items()])
 c=''
 for i in range(len(p)): c+=chr(97+k[p[i]])
 return 'http://sophos.com/anz/'+c+'.html'

# Key is a four letter word
# from a Monthy Python sketch

if __name__ == "__main__":
  if len(sys.argv) < 2:
    usage()

  elif sys.argv[1] == '-f':
    f = open(sys.argv[2],'rt')
    for l in f:
      if len(l) >= 4:
        l = l[:4]
        print(l,shrubbery(l))

  elif sys.argv[1] == '-i':
    while 1:
      l = raw_input("Key ('anne elk' quits): ")
      if l == 'anne elk': break
      if len(l) >= 4:
        l = l[:4]
        print(l,shrubbery(l))

  elif sys.argv[1] == '-a':
    k=('a','b','c','d','e','f','g','h','i',
       'j','k','l','m','n','o','p','q','r',
       's','t','u','v','w','x','y','z')
    for a in k:
      for b in k:
        for c in k:
          for d in k:
            w = a+b+c+d
            print(w,shrubbery(w))

  else:
    usage()