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()

Free T-shirts? It’s not a scam, it’s #decodeme again!

Editor’s note: The puzzle code below relies on a peccadillo of Python which makes it version and compiler specific, amongst other things. This means you’ll probably get the wrong results. We do know, however, that the code works on Duck’s Mac, so we’re going to shift to a “cloud model” for solving it. Email Duck the code and the input data (if any) you want to use. If you’re on the right track, he’ll run it “in the cloud” and send you the results. If not, he’ll give you a hint or two to point you in the right direction.

It’s May, and that means it’s time for Australia’s biggest security conference, AusCERT2011, which takes place at the Royal Pines Resort on Queensland’s Gold Coast. The conference runs from Sunday 15 May 2011 to Wednesday 18 May 2011.

Once again, the Sophos stand is going to be the place to hang out.

We’ve produced another puzzle T-shirt in our acclaimed DecoDeme geek fashion range. The puzzle is just hard enough to take a bit of solving, but not so hard that it will distract you from the conference or the evening cocktail parties.

So if you’re attending the event, be sure to come by the stand and pick up your free T-shirt. (Don’t forget to wear it while you’re at the conference!)

You can have a T-shirt even if you don’t intend to solve the puzzle. But we suggest you do – and we’ll be giving out hints on the stand to help you along – because that will put you in line to win a cool 1/16th scale remote-controlled tank.

Solve the puzzle, attend my talk (just before afternoon tea on Monday in the Purple room), and you could walk out with the tank.

In fact, you could win two tanks. We’re also running a prize draw for a second tank. Winning the puzzle prize is clearly the more glamorous option, and will give you several minutes of fame amongst a modestly-adoring crowd of a modest size, but you may as well enter the prize draw as well. Think of it as backup.

If you’re planning to have a go at the puzzle, the source code of the T-shirt is given below to save you typing it in from the image above. (We’ve been a bit sneaky by making the text on the shirt itself very slightly different. We do want to see you on our stand, after all.)

But if you write code to solve this “pre-release” version, you should be able to re-use it to solve the puzzle on the shirt within seconds. So it’s worth putting in a little early research.

And don’t forget, you can ask for hints at the conference. You can also follow me on Twitter(@duckblog) and watch out for clues with the hashtag #decodeme.

Oh. One more thing. We’ve got a bunch of funky-looking Naked Security T-shirts on the stand. But you’ll only know to ask for one if you’ve read this article.

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%
|                                      |
|     import-random!def-shrubbery(     |
|    ni):!-p='ewigsacgtwdbdzaco'!-k    |
|  =dict([[i,chr(97+i)]-for-i-in-rang  |
|  e(26)])!-ra                 ndom.s  |
|  eed(ni)!-                   random  |
|  .shuffle   (k)!-k=dict([[v,i]-for-i |
| ,v-in-k.i    tems()])!-c=''!-for-i-i |
|  n-range(l                 en(p)):-c |
|   +=chr(97+                k[p[i]])! |
|   -return-'http://sophos.    com/an  |
|    z/'+c+'.html'!#-Key-i     s-a-fo  |
|     ur-le                    tter-   |
|        wor                 d-fro     |
|           m-a--Monty--Python--       |
|             sketch!print(shr         |
|                ubbery(key            |
|                  --))--              |
|                                      |
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~%