Tags: crypto 


This was a fairly easy and a fun challenge. We are given with files named `pseudo-key.py` and `pseudo-key-output.txt`,basically the latter is the output of the former script. Now we have to decrypt the ciphertext from the given code. This is the encrypt function the admins used.
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 += '_'
x = chr_to_num[ptxt[i]]
y = chr_to_num[key[i]]
ctxt += num_to_chr[(x + y) % 26]
return ctxt
ctxt = encrypt(ptxt,key)
pseudo_key = encrypt(key,key)

Let's understand what they did. Firstly, the converted the plaintext to all lowercase. Next, they created a roating key which is equivalent to the size of the plaintext. If plaintext = `_`, then ciphertext = `_`, else ciphertext = `num_to_chr[(chr_to_num[ptxt[i]] + chr_to_num[key[i]]) % 26]`. In the end tehy printed out the encrypted plaintext and the key.

So we must generate all possible values of the plain key first so that we can decrypt the plain text. To do this I wrote this small script.
c = 'z_jjaoo_rljlhr_gauf_twv_shaqzb_ljtyut'
ec = 'iigesssaemk'

keys = []
for i in range(26):
# Since a key is encrypted with itself, I basically listed out the possibilities,
# what would happen if a character is encrypted with itself
keys.append([num_to_chr[i], num_to_chr[i], num_to_chr[(2*i) % 26]])

key = ''
for i in range(len(ec)):
for j in keys:
if(j[2] == ec[i]):
print(i, j[1])
This generated the following output
Position - Possible Character

0 e 5 j 10 f
0 r 5 w 10 s
1 e 6 j
1 r 6 w
2 d 7 a
2 q 7 n
3 c 8 c
3 p 8 p
4 j 9 g
4 w 9 t

Hence for wach position of the key, I have generated the possible character which could be present over there. I guessed a bit over here. The key looked like `redpwwwnctf`, on choosing one character from the given two possiblities in each position. An alternative would be to bruteforce all the possible keys on the cipher text.

Now since we have the key, we can decrypt the cipher text using the same logic which we used to decrypt the key.

key = 'redpwwwnctf'

# generated all possible encryptions between two characters in alphabets
val = []
for i in range(26):
for j in range(26):
val.append([num_to_chr[i], num_to_chr[j], num_to_chr[(i + j) % 26]])

# print(val)
ctxt = c.lower()
key = ''.join(key[i % len(key)] for i in range(len(ctxt))).lower()

passw = []
for i in range(len(ctxt)):
for j in val:
x = ctxt[i]
y = key[i]
# condition which satisfies such that character in cipher is the encrypted value in the genrated list(val)
# and character in key is the character used to encrypt the plaintext
if(j[2] == x and j[0] == y):
# print(ptxt[i], j[0], j[1])

for i in passw:
print(i, end = '')

This gives the output `iguesspseudokeysarepseudosecure`
Inserting `_` at the mentioned places in the ciphertext gives the flag `flag{i_guess_pseudo_keys_are_pseudo_secure}`