# Androids Encryption¶

## Introduction¶

**Solved by**: hyperc.

**Event**: Pwn2Win 2020: https://ctftime.org/event/961

**Challenge name**: Androids Encryption (115 pts)

**Description**: We intercept an algorithm that is used among Androids. There are many hidden variables. Is it possible to recover the message?

**File**: `server.py`

## Encryption logic¶

The challenge was accessible on a remote server which provided us with two options:

Get an encrypted version of a plaintext provided by the user

Get an encrypted version of the flag

The Python implementation of the server was also provided in `server.py`

and allowed us to understand the logic behind the encryption method.

The main method of this app is the `encrypt`

function.

Given a plaintext, a key and an initialisation vector (IV), it:

Encrypts the plaintext using AES algorithm in the PCBC mode.

Returns the ciphertext concatenated with the IV used.

```
def encrypt(txt, key, iv):
global key2, iv2
assert len(key) == BLOCK_SIZE, f'Invalid key size'
assert len(iv) == BLOCK_SIZE, 'Invalid IV size'
assert len(txt) % BLOCK_SIZE == 0, 'Invalid plaintext size'
bs = len(key)
blocks = to_blocks(txt)
ctxt = b''
aes = AES.new(key, AES.MODE_ECB)
curr = iv
for block in blocks:
ctxt += aes.encrypt(xor(block, curr))
curr = xor(ctxt[-bs:], block)
iv2 = AES.new(key2, AES.MODE_ECB).decrypt(iv2)
key2 = xor(to_blocks(ctxt))
return str(base64.b64encode(iv+ctxt), encoding='utf8')
```

which can be illustrated by the following diagram:

The `encrypt`

function also does another important thing: it modifies two global variables, `iv2`

and `key2`

that are exactly the key and initialisation vector used by the application to return an encrypted version of the flag to the user.

```
key2 = xor(to_blocks(ctxt))
```

Hence, `key2`

is reinitialised after each encryption to the result of our previous encryption, which we obviously have.

Since this type of encryption is symmetric, getting `key2`

enables us to decrypt the encrypted flag.

## Step by step¶

### Send a random plaintext to the server and get the response ciphertext¶

```
response1 = 'qal7b3mi7fEvSccj+NcaYtqU4i4io4qT1g88K9wY2nQ='
iv_plus_ctext = base64.b64decode(response1)
ctext = al[16:] # IV is 16 bytes long
```

### Get key2 from the recevied ciphertext

```
key2 = xor(to_blocks(ctext))
```

### Query the encrypted flag from the server¶

```
enc_flag = '36X0Ug8ZEIvrRDeus6c3GBynEY7La36H0/A1Bqoy87go8FyYOeRQOuN7b0fXJXMYqWZ9lo9MWkS8EaN9/8Tl7A=='
enc_flag = base64.b64decode(enc_flag)
```

### Decrypt the ciphertext following the diagram above¶

```
from Crypto.Cipher import AES
iv2 = enc_flag[:16]
c1 = enc_flag[16:32]
c2 = enc_flag[32:48]
c3 = enc_flag[48:64]
aes = AES.new(key2, AES.MODE_ECB)
p1 = xor(aes.decrypt(c1),iv2)
p2 = xor(aes.decrypt(c2),xor(c1,p1))
p3 = xor(aes.decrypt(c3),xor(c2,p2))
```

### And find the flag!¶

```
assert(p1+p2+p3 == b'CTF-BR{kn3W_7h4T_7hEr3_4r3_Pc8C_r3pe471ti0ns?!?}')
```