Skip to content

Latest commit

 

History

History

pseudo-key

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

pseudo-key

Author: roerohan

Basic reversing challenge.

Requirements

  • Python

Source

Keys are not always as they seem...

Note: Make sure to wrap the plaintext with flag{} before you submit!
#!/usr/bin/env python3

from string import ascii_lowercase

chr_to_num = {c: i for i, c in enumerate(ascii_lowercase)}
num_to_chr = {i: c for i, c in enumerate(ascii_lowercase)}

def encrypt(ptxt, key):
    ptxt = ptxt.lower()
    key = ''.join(key[i % len(key)] for i in range(len(ptxt))).lower()
    ctxt = ''
    for i in range(len(ptxt)):
        if ptxt[i] == '_':
            ctxt += '_'
            continue
        x = chr_to_num[ptxt[i]]
        y = chr_to_num[key[i]]
        ctxt += num_to_chr[(x + y) % 26]
    return ctxt

with open('flag.txt') as f, open('key.txt') as k:
    flag = f.read()
    key = k.read()

ptxt = flag[5:-1]

ctxt = encrypt(ptxt,key)
pseudo_key = encrypt(key,key)

print('Ciphertext:',ctxt)
print('Pseudo-key:',pseudo_key)

Exploitation

The most important function is of course, the encrypt function.

def encrypt(ptxt, key):
    ptxt = ptxt.lower()
    key = ''.join(key[i % len(key)] for i in range(len(ptxt))).lower()
    ctxt = ''
    for i in range(len(ptxt)):
        if ptxt[i] == '_':
            ctxt += '_'
            continue
        x = chr_to_num[ptxt[i]]
        y = chr_to_num[key[i]]
        ctxt += num_to_chr[(x + y) % 26]

This takes ptxt and key, makes key match the size of ptxt by repeating characters in a cyclic fashion, then adds the number equivalent (a->0, z->25) of each character of key to that of ptxt and mods it with 26. This value is converted to the corresponding character.

There is also a pseudo key along with this file. The pseudo key is made by encrypting the key using the key itself.

pseudo_key = encrypt(key,key)

Which means, there might be many possible keys (because of the %26). However, we can get all possible characters in the key by adding 26 and by not adding 26 to the number equivalent of each character:

def get_key(pkey):
    x = ''
    y = ''
    for i in range(len(pkey)):
        c = chr_to_num[pkey[i]]
        x += num_to_chr[c/2]
        y += num_to_chr[(c+26)/2]
    print(x)
    print(y)

This gives us 2 strings:

eedcjjjacgf
rrqpwwwnpts

If you see carefully, you can combine these 2 keys to get redpwwwnctf (first character from key2, second and third from key1, and so on...), which seems like it's going to be the correct key. (Yes, it's sort of a guess)

Now, we can simply use almost exactly the same function to decrypt the key, except, here you subtract instead of adding:

from string import ascii_lowercase

chr_to_num = {c: i for i, c in enumerate(ascii_lowercase)}

num_to_chr = {i: c for i, c in enumerate(ascii_lowercase)}
ctxt = 'z_jjaoo_rljlhr_gauf_twv_shaqzb_ljtyut'
pseudo_key = 'iigesssaemk'

def get_key(pkey):
    x = ''
    y = ''
    for i in range(len(pkey)):
        c = chr_to_num[pkey[i]]
        x += num_to_chr[c/2]
        y += num_to_chr[(c+26)/2]
    print(x)
    print(y)

get_key(pseudo_key)

key = 'redpwwwnctf'

def decrypt(ct, key):
    flag = ''
    key = ''.join(key[i % len(key)] for i in range(len(ct))).lower()
    for i in range(len(ct)):
        if ct[i] == '_':
            flag += '_'
            continue
        flag += num_to_chr[(chr_to_num[ct[i]] - chr_to_num[key[i]]) % 26]
    print(flag)
decrypt(ctxt, key)

You can run this using python to get the flag.

$ python pseudo-key/crack.py 
eedcjjjacgf
rrqpwwwnpts
i_guess_pseudo_keys_are_pseudo_secure

The flag is:

flag{i_guess_pseudo_keys_are_pseudo_secure}