Writing a ROT13 Decrypter/Encrypter in Python

Running through my PicoCTF Mod26 Write Up prompted me to do a little project around ROT13, partly to document the Caesar Cypher technique a bit and partly to learn some Python.

My background’s in Ada and C and C++, not exactly the ideal scripting languages. So I should probably get up to speed in something a bit more suited, like Python. I’ve had a bit of a play in the past, but it’s probably time to take it a bit more seriously.

This is my first cut, probably not the best way to do it and I’m more than reasonably sure this is not canonical Python. However, it works and it kind of shows the maths pretty well but it’s very C/C++ in style and there’s an awful lot of code.

Python
# Implements ROT13 encryption and decryption
# See https://en.wikipedia.org/wiki/ROT13

inputtext = "Hello World!"
cyphertext = ""
plaintext = ""

for i in range (0, len(inputtext)): 
  ch = inputtext[i]
  ascii = ord(ch)
  if ch >= 'A' and ch <= 'Z':
    cyphertext += chr((ascii - ord('A') + 13) % 26 + ord('A'))
  elif ch >= 'a' and ch <= 'z':
    cyphertext += chr((ascii - ord('a') + 13) % 26 + ord('a'))
  else:
    cyphertext += ch
print ("Encrypted input text is: " + cyphertext)

for i in range (0, len(cyphertext)): 
  ch = cyphertext[i]
  ascii = ord(ch)
  if ch >= 'A' and ch <= 'Z':
    plaintext += chr((ascii - ord('A') + 13) % 26 + ord('A'))
  elif ch >= 'a' and ch <= 'z':
    plaintext += chr((ascii - ord('a') + 13) % 26 + ord('a'))
  else:
    plaintext += ch
print ("Decrypted cyphertext is: " + plaintext)

Let’s see what everybody else does.

The canonical Python way of doing it is as follows:

Python
import codecs
inputtext = "Hello World!"
cyphertext = codecs.encode(inputtext, "rot_13")
plaintext = codecs.decode(cyphertext, "rot_13")
print (cyphertext)
print (plaintext)

Which is nice and succinct and clear, but it explains nothing about how the algorithm works. Sometimes a black box is exactly what you want though. I mean if somebody gave you a brief to ROT13 the string Hello World! this is what you should deliver.

A compromise might be something like this, which uses a list comprehension (these are quite cool aren’t they?) to index each character in the inputtext into each alphabet and encode it. Assuming you know a bit of python this is quite expressive and takes away all the verbosity of my efforts.

Python
text = "Hello World!"

for operation in ["encode", "decode"]:
	for alphabet in ["abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]:
		text = ''.join([alphabet[(alphabet.index(ch) + 13) % 26] if ch in alphabet else ch for ch in text])
	print(text)

But here’s the thing though, I stand by my code as the best of the three. For the purposes of this article. Why? Because sometimes the purpose of code is nothing to do with its execution, or its use of provided language features, or its succinctness, or its elegance. Sometimes it’s to elucidate the ideas it embodies in as simple a way as possible for as wide an audience as possible.

Despite that fact that its five times the length of the other implementations, my version is no more complex than the other two. The first one just hides all the complexity behind a library call and the second one hides it all behind an obscure (OK, obscure-ish to non-Python coders) language feature. And feigned simplicity is just a barrier to understanding.

My version wears its heart on its sleeve. It tells you a story. A story that flows easily and can be read by anyone with just the fundamentals of coding learned in whatever language they happen to have studied. Some simple variables, some loops, some if-else decisions, some type manipulation and some output. That’s all the knowledge you need.

I think there’s a valuable lesson here. When I was writing the draft of this article, I apologised for my feeble attempts at writing Python. But when I actually looked at the alternatives I realised mine was better.

When you’re writing up a CTF, or pretty much any other kind of write-up that would benefit from some code, don’t be tempted to write the ‘best’ code, for some conventional definition of the word. I just realised that the best code to put in a write-up is code that doesn’t get in the way of the reader, for some as-broad-as-possible definition of ‘reader’, understanding the point you’re trying to make.

Because I don’t have a clue how to code in Python, I ended up writing like a noob. And that’s exactly how it should have been written.

Nah, sorry, that’s all bollocks. Who am I trying to kid? The best way is definitely to do it in C:

C
main(a){while(a=~getchar())putchar(~a-1/(~(a|32)/13*2-11)*13);}