Part 1: Implementing Repeating Key XOR Encryption

This is part one in a three part series on repeating key XOR encryption inspired by Cryptopals challenges five and six of set one. Herein lies a breakdown of how to understand and implement repeating key XOR.

Part two will teach you the theory behind breaking repeating key XOR and part three will show you how to implement what you learned in part two in Python.

To grok what follows you shouldn't need much. A little bit of encryption knowledge and minimal Python chops will help but if you don't have any of that, read on anyway, Google is your friend.

Also, heads up, all code is written in Python 3.

What is it?

Repeating key XOR encryption is basically a modern variant of the ancient Vigenère cipher which remained unbroken from its inception in 1553 until it was officially cracked by Friedrich Kasisky in 1863. Lasted a while eh?

The idea is that you choose some secret key and then repeat it until it's the same length as the plaintext you'd like to encrypt and for every char in your string you exclusive or (XOR) it with the corresponding char in the key. So, with the key ENIGMA the plaintext next to the repeating key would look like...

THE MONEY IS BENEATH THE FLOOR BOARDS
ENIGMAENIGMAENIGMAENIGMAENIGMAENIGMAE
Note that the repeating key is cut off at the end to match the length of the plaintext.

Each char in the plaintext and the corresponding key char are then converted to something that can be XOR'd (in Python integers are fine) and you XOR those suckers.

So, T (which converts to integer 84) gets XOR'd with E (which converts to integer 69), H gets XOR'd with N, E gets XOR'd with I, a space gets XOR'd with G and so on.

In our case the encrypted string represented in hex is...

11060c67000e0b0b10670412650c0c090800110669130504650805080213650c06061f0516
Hex strings are more readable for this sort of work. I'd recommend getting comfortable working with hex values and raw bytes as well as converting between equivalent strings for readability.

If you know the secret key the process can be reversed to decrypt the encrypted string back to plaintext.

A Python Implementation

# Hexlify is used here for converting bytes to hex
from binascii import hexlify

def repeating_key_xor(key, string):
    # i is the position within the key
    i = 0
    arr = []
    for ch in string:
    	# Convert the key char and the plaintext char to
        # integers using `ord`, XOR them and add them to
        # the array.
        arr.append(ord(ch) ^ ord(key[i]))
        
		# Manage the "repeating" part of the repeating key.
        # If the end of the key is reached start back at the
        # beginning.
        i += 1
        if (i == len(key)):
            i = 0

	# Finally convert our array to a byte array (which
    # hexlify likes), then convert to hex and return it.
    return hexlify(bytearray(arr))

string = 'THE MONEY IS BENEATH THE FLOOR BOARDS'
key = 'ENIGMA'

encrypted = repeating_key_xor(key, string)
print(encrypted)
I'd suggest some research into Python's hexlify and unhexlify they are both handy and kind of confusing.

The comments in the code should clarify what's going on but basically we have a function that takes a key (non-repeating) and our plaintext string and does the following...

  1. Loop over the plaintext string.
  2. Convert the current character and its corresponding key character to integers using ord.
  3. XOR the two integers together with the ^ operator.
  4. Append the encrypted value to an array.
  5. Covert the array to a byte array which can then be turned into hex using Python's hexlify.

Conclusion

Here we learned what repeating key XOR is and how to implement it.

As you'll see in the next post, this type of encryption, like the Vigenère cipher, is not secure. However, it's foundational knowledge to have for more advanced attacks. You would do well to understand how it works and how to crack it.

Next up: Breaking Repeating Key XOR, the Theory.

Resources