LogCaesar - Crypto - Reply Challenge 2019

For this challenge we were given an encrypted file and a python script with an encrypt function:

#!/usr/bin/env python3
import sys

if len(sys.argv) != 4:
    print("Usage: "+sys.argv[0]+" message_file key encrypted")

def encrypt(message, key):
    with open(message, 'rb') as content_file:
        content = content_file.read()
    if len(content) != 256:
        raise Exception('This is a block cipher, messages have to be exactly 256 bytes long')
    ciphertext = list(' ' * 256)
    for i in range(0,256):
        new_pos = (3**(key+i)) % 257
        ciphertext[new_pos-1] = ((content[i])^i)^(new_pos-1)
    return bytes(ciphertext)

ciphertext = encrypt(sys.argv[1],int(sys.argv[2]))
with open(sys.argv[3],'wb') as encryped_file:

What the function does is a mix between transposition and transformation. Each character's new position is calculated with this formula where i is the current character's position:

(3**(key+i)) % 257

And the character itself becomes:


Because we didn't had much time to do things well, I wrote a function that given the new character's position it does a bruteforce on all 256 possibile original positions and finds the correct one:

def find(n, key):
    for i in range(256):
        if 3**(key+i) % 257 == n:
            return i

And here's the decrypt function:

def decrypt(content, key):
    cleartext = list(' ' * 256)
    for i in range(256):
        orig_pos = find(i+1, key)
        cleartext[orig_pos] = (content[i] ^ (orig_pos)) ^ (i)
    s = ''
    for byte in cleartext:
        s += chr(byte)
    return s

Knowing that the flag format is {FLG:here_goes_the_flag} we can write a bruteforce function that tries all the 256 keys and search for the flag:

def crack(filename):
    enc = open(filename, 'rb').read()
    for i in range(256):
        dec = decrypt(enc, i)
        if '{FLG:' in dec:

And here's it's output:


We can see the flag on the second line.