Tags: xor crypto hex 

Rating: 3.0

### Problem description:
```
Please select one of flowing options:
1 - You send me any message then I will give you corresponding cipher text
2 - I show you the challenge flag and you have 3 times to guess the plain text
Your choice: 1
Your message: a
The cipher text: TUVHQg==
...
Your choice: 2
Nice! Your challenge message: MHGCKGADMEGBIACFONEIIECBMJGMKPAKPPFKJFDAOHECNPHKLHBCPAFFLHBCONEIIJCMOLEOIDCGPGFDKDAGPJFMLIBNPNFILEBBNMHJJKDPNDHGJNDIMKGPIICNOCEHJHDCNEHBOFEALFBAOHECKGADOCEHIGCDMMGJLOBLNLHOJEDB
Your guess:
```
The server provides 2 functions:
1. encrypt any message you provided, output base64 encoded encryption result;
2. given encrypted challenge message,

### Solving:
start from basic length 1 string, I got following encryption result (after base64 decoding).
```
0 JFDA
1 JEDB
2 JHDC
3 JGDD
4 JBDE
5 JADF
6 JDDG
7 JCDH
8 JNDI
9 JMDJ
A OEEB
B OHEC
C OGED
D OBEE
E OAEF
F ODEG
G OCEH
H ONEI
I OMEJ
J OPEK
K OOEL
L OJEM
M OIEN
N OLEO
O OKEP
P PFFA
Q PEFB
R PHFC
S PGFD
T PBFE
U PAFF
V PDFG
W PCFH
X PNFI
Y PMFJ
Z PPFK
a MEGB
b MHGC
c MGGD
d MBGE
e MAGF
f MDGG
g MCGH
h MNGI
i MMGJ
j MPGK
k MOGL
l MJGM
m MIGN
n MLGO
o MKGP
p NFHA
q NEHB
r NHHC
s NGHD
t NBHE
u NAHF
v NDHG
w NCHH
x NNHI
y NMHJ
z NPHK
```
Some observations:
1. all results are of length 4;
2. all bytes of output are in range "ABCDEFGHIJKLMNOP"
3. the last 2 bytes of each output are in ascending order.

Sounds like hex encoding? OK. replacing 'ABCDEFGHIJKLMNOP‘ with hexidecimal digits, we got:
```
0 9530
1 9431
...
A e441
B e742
...
a c461
b c762
```
1. the output is hex encoding of 2 bytes, and the 2nd byte equals to the input byte.
2. the xor of 2 bytes is 0xA5

Now for multi-byte input:
```
hello MNGIKIANMEGBKIANMHGC cd68a80dc461a80dc762
world NCHHLNBIMPGKKDAGMHGC d277bd18cf6aa306c762
```
1. the output is in group of 4 bytes, 1 group for each input byte;
2. each group has the same property as the 1 byte encryption output.

Dropping every other byte, we got:
```
hello 68 0d 61 0d 62
world 77 18 6a 06 62
```
1. the 1st output byte gives (hex encoded) 1st input byte;
2. xor of adjacent output bytes gives the subsequent input bytes.

So here is the decryption function:
```
# decoding one byte from 4 output bytes.
def dec4(w):
w = w.decode('hex')
assert len(w) == 2 and (ord(w[0])^ord(w[1])) == 0xa5
return w[1]

import string
tr = string.maketrans('ABCDEFGHIJKLMNOP', '0123456789abcdef')

# decoding input string.
def decrypt(s):
res = s.translate(tr)
c = [dec4(res[i:i+4]) for i in range(0, len(res), 4)]
o = [c[0]]*len(c)
for i in range(1, len(o)):
o[i] = chr(ord(c[i-1])^ord(c[i]))
o = ''.join(o)
return o
```

Now apply the decryption to the given flag, and send back the result, we got:
> Awesome! Here is the final flag: Good fun with bad crypto