Language of choice for this is Python. Probably not everyone’s first choice but since v3 the support for bytes as a native type makes it much easier to handle the below.
Set 1
1. Convert hex to base64
That one was easy - just remember that base64.b64encode
returns something of type byte, not str.
As a bit of trivia h
is the hex representation of “I’m killing your brain like a poisonous mushroom” - a sentence from “Ice Ice Baby” (which is a recurring theme in this challenge >_<).
2. Fixed XOR
Nothing much here either, apart that a_xor_b
is “the kid don’t play”.
3. Single-byte XOR cipher
This one is a little more tricky. We’re given a piece of ciphertext encrypted with a single character but not told what the character is. The instructions suggest using frequency analysis - but I think the ciphertext is too small. Instead I opted for a brute force approach : )
And we quickly see that when k
is X
the ciphertext decrypts to “Cooking MC’s like a pound of bacon”.
4. Detect single-character XOR
This makes it a little harder to brute force - instead of having a single string, we are given 60. We need to optimise!
We know one of those strings will decode to something from “Ice Ice Baby” - which means it’ll be ASCII. Specifically, all characters should be printable. Behold string.printable
. Except if we did that it’d generate too much noise. We certainly don’t expect digits or non-standard symbols like (
or %
to be present. We this we can create a filter that will discard anything that doesn’t match the given criteria.
Running this quickly isolates the string in question, which decodes to “Now that the party is jumping”.
5. Implement repeating-key XOR
To get our repeating key, it’s probably easiest to use a generator.
6. Break repeating-key XOR
To get this under way we need to do a little prep work. The first is being able to compute the hamming distance between two lists of bytes:
Which is expected (as per the instructions). We hardcode 8 because that’s how long a byte it. Wrapping the above in a method yields:
We also need something that allows us to divide a list into chunks. Note we only want complete chunks… I think (?).
It’s not magic - we could have done the same thing with range
but this is a little neater.
Next up we need to compute the hamming distance between each block.
Which yields:
smallest distance 2.7593244194229416 was found with chunk size 29
Indicating the key is of length 29.
We now need to transpose each block (so 29 blocks all of the same length, apart potentially from the last one), and find the single character XOR key that yields the best ‘English-looking’ histogram. In other words, we’ll gather 29 samples of what an english text should look like - where the byte which occurs the most often in each sample should match that which would occur the most often in an english text.
Most people (myself included) automatically think that ‘e’ is the most common letter - and that’s true. But it isn’t the most frequent character. According to this page it’s actually space. So by property of XOR, xor’ing the most frequent byte in the chunk with space should give us the character the chunk was encrypted with.
Yielding:
bytearray(b'Terminator X: Bring the noise')
7. AES in ECB mode
We’re not re-implementing AES - just looking at the ECB mode.
Which will give you the lyrics to “Play That Funky Music” by Vanilla Ice.