2 minutes
FDCA Xmas 2024 Day 13 - Hel’s Key Hell
Challenge Description
Danish (original)
Vi har opsnappet et meget kryptisk signal mellem Hel og Loke. Det har dog vist sig besværligt at bryde deres Ase Existens Skjuler kryptering, selvom nøglen allerede stod deri, og ECB burde være easy at knække. Det er som om vi bare bliver ved med at få samme resultat, når vi prøver at dekryptere den.
Måske du har bedre held med at knække signalet?
English (from chatgpt)
We have intercepted a very cryptic signal between Hel and Loki. However, it has proven difficult to break their Aesir Existence Hider encryption, even though the key was already in it, and the ECB should be easy to crack. It’s as if we keep getting the same result when we try to decrypt it.
Maybe you’ll have better luck cracking the signal?
File
We are also given the following file:
Solution
Unzipping the file we get a binary file with a key at the top then encrypted data:
$ 7z x signal.7z
[expunged for readability]
$ ls
signal.7z suspicious_signal.bin
$ xxd -l 128 suspicious_signal.bin
00000000: 6b65 793d 4533 3041 3338 3136 3638 4646 key=E30A381668FF
00000010: 4436 4631 4345 3633 3443 3742 3538 4431 D6F1CE634C7B58D1
00000020: 3634 3332 3839 3930 3236 3741 3146 3132 64328990267A1F12
00000030: 3441 3338 3338 4639 4137 4541 3841 4430 4A3838F9A7EA8AD0
00000040: 4534 3634 0a93 41fc 0170 34df d97f aeea E464..A..p4.....
00000050: 4d26 c74c 6080 a71c d4c7 7cbb f65f 435c M&.L`.....|.._C\
00000060: 58d8 568f b1ff 88f5 48db 5218 e16f 5411 X.V.....H.R..oT.
00000070: e095 7f70 c93f 5583 306b 0988 df70 6671 ...p.?U.0k...pfq
From the challenge description it should encrypted using AES ECB mode:
from Crypto.Cipher import AES
with open('suspicious_signal.bin', 'rb') as fp:
data = fp.read()
key, ciphertext = data.split(b'\n', maxsplit=1)
key = bytes.fromhex(key.decode().removeprefix('key='))
cipher = AES.new(key, AES.MODE_ECB)
plaintext = cipher.decrypt(ciphertext)
print(plaintext[:100])
Running the above code, we see that there is yet another layer of encryption:
$ python decrypt_once.py
b'key=BA05E2B072984133E10BA582EE8FF8531210109933423CBFA3AAA205108FEE52\nPp\x18\xdf\xc2]\xa8:\x8d?\x0f\x9c\xcf\x9c\xbb<\x1b\xeb\xe4U\xc9\x18\xb4\xa0\ny\x08\xbf\xad\x12\x0f'
So lets make a script that unpacks the encryption layer by layer til we get to end:
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
with open('suspicious_signal.bin', 'rb') as fp:
signal = fp.read()
def decrypt_layer(data: bytes) -> bytes:
key, part = data.split(b'\n', maxsplit=1)
key = bytes.fromhex(key.decode())
cipher = AES.new(key, AES.MODE_ECB)
return unpad(cipher.decrypt(part), 16)
while signal.startswith(b'key='):
signal = decrypt_layer(signal.removeprefix(b'key='))
print(signal)
$ python solve.py
b'FDCA{B3tter_don3_tha7_aut0matic4lly}\n'