The code contains two messages. The first is represented as a simple numerical encoding. The second is a secret message that has been encrypted, alongside code for decrypting it. Here are some clues to make sense of how this second message has been encrypted.
Here’s a shorter version of the code in R:
gchq_message <- "gNSkYr+VqyGl1Lhko8fqYq7UpGajiuo67w==" |> base64enc::base64decode() gchq_key <- c(0xc6, 0xb5, 0xca, 0x01) |> as.raw() xor(gchq_message, gchq_key) |> rawToChar()
(No spoilers here…)
So, the steps to decrypt are:
- Translate the Base64 encoded message to raw bytes
- XOR those raw bytes with the key
- Translate the bytes to ASCII characters so we can read the message
The nice thing about this form of encryption is that the same algorithm does both encrypting and decrypting. So, if you wanted to reply, “No thanks, I’m good” you just do the same in reverse:
- Translate your ASCII text message to raw bytes
- XOR those bytes with the key
- Translate the result to Base64
"No thanks, I'm good" |> charToRaw() |> xor(gchq_key) |> base64enc::base64encode()
This gives “iNrqda7UpGq1mepI4djqZqnarg==”.
Fun! Also, I have a tattoo that uses the same approach, except I used Braille ASCII instead of Base64 to ensure that all the characters were tattooable 🙂
If you’re watching The Undeclared War, look out for the shout out to Base64 too:
But why is the key c6b5ca01? It’s not obviously the letters G, C, H, Q. In decimal, it looks like an IP address, but there’s nothing obvious at 18.104.22.168, and any four 8 bit numbers look like an IP address if you stare long enough.