# Space (crypto, 100p, 41 solved)
The challenge code is:
```pythonfrom hashlib import md5from base64 import b64decodefrom base64 import b64encodefrom Crypto.Cipher import AESfrom Crypto.Random import get_random_bytesfrom random import randrangeimport string
alphabet = string.ascii_lowercase + string.ascii_uppercase + string.digitsiv = md5(b"ignis").digest()
flag = "ijctf{i am not the real flag :)}"message = b"Its dangerous to solve alone, take this" + b"\x00"*9 
keys = []for i in range(4):    key = alphabet[randrange(0,len(alphabet))] + alphabet[randrange(0,len(alphabet))]    keys.append(key.encode() + b'\x00'*14)
for key in keys:    cipher = AES.new(key, AES.MODE_CBC, IV=iv)    flag = cipher.encrypt(flag) for key in keys:    cipher = AES.new(key, AES.MODE_CBC, IV=iv)    message = cipher.encrypt(message)
print(f"flag= {b64encode(flag)}")print(f"message= {b64encode(message)}")```
And we know:
```Here is your message: NeNpX4+pu2elWP+R2VK78Dp0gbCZPeROsfsuWY1Knm85/4BPwpBNmClPjc3xA284And here is your flag: N2YxBndWO0qd8EwVeZYDVNYTaCzcI7jq7Zc3wRzrlyUdBEzbAx997zAOZi/bLinVj3bKfOniRzmjPgLsygzVzA==```
## Solution overview
So we have a known plaintext-ciphertext pair, encrypted in sequence 4 times via AES-CBC with known IV, but each AES has a key with only 2 bytes of entropy.We can't really bruteforce them just like that, because 8 bytes would be too much.But we can use meet-in-the-middle approach here:
- Perform 2 encryption rounds of the known plaintext with all possible keys (2+2 bytes of entropy)- Store all results in a map `ciphertext -> keys`- Perform 2 decryption rounds of the known ciphertext with all possible keys (2+2 bytes of entropy)- Look for the decryption step results in the encryptions map- Once we find a match, we know all 4 keys and we can decrypt the flag
## Forward step
First we generate encryptions map `2-round-encrypted-plaintext -> keys`.To make things a bit faster we run this on multiple cores:
```pythonimport itertoolsfrom Crypto.Cipher import AESfrom crypto_commons.brute.brute import brute
iv = md5(b"ignis").digest()msg = b"Its dangerous to solve alone, take this" + b"\x00" * 9alphabet = string.ascii_lowercase + string.ascii_uppercase + string.digits
def enc_worker(keys):    key1, allkeys = keys    result = {}    for key2 in allkeys:        enc_msg = msg        cipher1 = AES.new(key1 + '\x00' * 14, AES.MODE_CBC, IV=iv)        enc_msg = cipher1.encrypt(enc_msg)        cipher2 = AES.new(key2 + '\x00' * 14, AES.MODE_CBC, IV=iv)        enc_msg = cipher2.encrypt(enc_msg)        result[enc_msg] = (key1, key2)    return result
def generate_forward(allkeys):    full_result = {}    partial_results = brute(enc_worker, [(key1, allkeys) for key1 in allkeys], processes=7)    for partial in partial_results:        full_result.update(partial)    return full_result```
## Backwards step
Now we need to perform similar operation, but use decrypt instead of encrypt and check if result is in the forward map.Again we distribute the work to make it faster:
```pythondef dec_worker(keys):    key1, allkeys, ct, flag_ct, forward = keys    for key2 in allkeys:        msg_c = ct        cipher1 = AES.new(key1 + '\x00' * 14, AES.MODE_CBC, IV=iv)        msg_c = cipher1.decrypt(msg_c)        cipher2 = AES.new(key2 + '\x00' * 14, AES.MODE_CBC, IV=iv)        msg_c = cipher2.decrypt(msg_c)        if msg_c in forward:            print(forward[msg_c], key2, key1)            keys = [forward[msg_c][0], forward[msg_c][1], key2, key1]            for key in keys[::-1]:                cipher = AES.new(key + '\x00' * 14, AES.MODE_CBC, IV=iv)                flag_ct = cipher.decrypt(flag_ct)            print(flag_ct)            return keys
def check_backwards(ct, allkeys, flag_ct, forward):    datasets = [(key1, allkeys, ct, flag_ct, forward) for key1 in allkeys]    brute(dec_worker, datasets, processes=4)```
## Flag
Now we just run this on our inputs:
```def solve(ct_flag, ct_message):    all_keys = map(lambda x: "".join(x), itertools.product(alphabet, repeat=2))    print(len(all_keys))    forward = generate_forward(all_keys)    print("Generated forward")    check_backwards(ct_message, all_keys, ct_flag, forward)
def main():    msg = 'NeNpX4+pu2elWP+R2VK78Dp0gbCZPeROsfsuWY1Knm85/4BPwpBNmClPjc3xA284'    flag = 'N2YxBndWO0qd8EwVeZYDVNYTaCzcI7jq7Zc3wRzrlyUdBEzbAx997zAOZi/bLinVj3bKfOniRzmjPgLsygzVzA=='    solve(flag.decode("base64"), msg.decode("base64"))```
And after a moment we get: `ijctf{sp4ce_T1me_Tr4d3off_is_c00l_but_crYpt0_1s_c00l3r_abcdefgh}`