**Regarding the thumbnail.**This is my Discord avatar combined with Komi from the anime

*Komi can’t communicate*, where the challenge

*Mystiz can’t code*is referred to. Made by

*@byronwai*.

We will continue walking through the remaining crypto challenges I wrote for HKCERT CTF 2022: *Mystiz can't code*, *Slow keystream* and *King of Rock, Paper, Scissors*.

## 亞洲協會香港中心 / Mystiz can't code (Crypto)

### Challenge Summary

Mystiz can't code! He wanted to implement Advanced Encryption Standard (AES) in batch but he couldn't do it correctly.

Anyway, he decided to give up and uploads what he has for now. Since this is implemented based on AES, it should be almost as secure as AES as well?

We are given a batch script which *attempts* to implement AES. We are also given two ciphertexts encrypted with the same key (and one of the plaintexts is given).

### Solution

**Objection!**I can actually code. I actually built a wrote a working AES then broke it in the way I wanted.

#### Part I: Background story

I am a newbie to batch scripts. The only batch script I wrote was to shut down a machine. Back in the day *MSN* still exists (an application in the stone age, huh?), I used to rename those batch scripts into files, changed their icons and sent them to my friends. It was pretty satisfying when you see they became offline as soon as they receive the files.

Well, after uncountably many years, I am asked to write batch scripts for my work to maintain Windows machines. I was stuck into an issue for a few hours... and it was pretty amusing. Anyway, I thought that is worth making it into a CTF challenge.

#### Part II: Understanding the cipher

Denote the flawed AES by $AES_{†}$. When we compare the batch script with the below figure showing the implementation, it seems that everything matches.

For instance, the `EncryptBlock`

and the `AddRoundKey`

functions below looked legit (except that the `state`

is a global variable).

If you are convinced, then unfortunately you fell into the same pitfall as I did. In reality, there is a bizarre behaviour that I couldn't understand while writing the challenge. In short, both `EncryptBlock`

and `AddRoundKey`

are flawed so that $AES_{†}$ is not working as intended. The below figure shows how the messages are encrypted using $AES_{†}$. $n$ in the figure is the number of blocks the script has encrypted.

We can see from above that only two bytes from the subkeys are used when encrypting a block, which is $k_{33}$ from the 0-th and the $n$-th round keys. The other parts are performed in the same way that AES does. Up to here, we can already write a script to exhaust the $_{16}$ subkey candidates for each block.

#### Part III: Batch, why?

**RIP brain cells.**I am unable to figure out all the details… It didn’t work as expected. Please let me know if you know what’s going on.

In this section, we will study the causes of the problem. In short, the commands in the parentheses are executed simultaneously^{1}.

For batch scripts, all function variables are global unless we specify `SETLOCAL`

in the function. Let's consider how the first block is encrypted. It calls `LoadState`

at the very beginning, which eventually sets $j←15$. Since $j$ is global, its value will be shared. After that, `AddRoundKey`

, which is defined below, is called with the argument `round_id = 0`

.

Since the commands are executed simultaneously, $j$ was unable to update timely when it is used to update the state. The value of $j$ in the line that sets the value of `STATE[i]`

is fixed for all $i=0,1,...,15$. Therefore, instead of XORing the message with the round key, every byte of the message is XORed with `KEY[15]`

(i.e., $k_{33}$ from the 0-th round key).

Let's have a look at the `EncryptBlock`

function. The parameter for the `AddRoundKey`

function, `%round_key%`

, is actually zero for all the rounds. This sets $j←15$ when `AddRoundKey`

is called, which will be used in the final `AddRoundKey`

call. With that said, when $n=0$, only `KEY[15]`

will be used for encryption.

On the other hand for $n>0$, `LoadState`

sets $j←16n+15$. This $j$ will only be used on the first `AddRoundKey`

(and the subsequent $j$s for `AddRoundKey`

are 15), which implies that `KEY[16*n+15]`

(i.e., $k_{33}$ of the $n$-th round key) will be used for the first `AddRoundKey`

and $k_{33}$ of the 0-th round key.

## 澳洲牛奶公司 / Slow keystream (Crypto)

### Challenge Summary

Want a challenge in Hong Kong?

Enter the Australia Dairy Company and execute the 379-byte flag generator written in Golang. I bet you will be expelled from the restaurant before the second character of the flag appears.

We are given a binary written in Golang (with source code given below), and `flag.enc`

. The objective is to recover the input.

### Solution

#### Part I: What is in Golang's PRNG?

In this challenge, the characters of the encrypted flag is XORed with the outputs from `rand.Uint64`

. With that said, we have to look deeper into the internals of the PRNG. We can start with the documentation - with that, we can read the source code and see where the actual code is. Tracing in the codebase, eventually, we end up at its implementation (snippets below):

#### Part II: Fibonnnnacccci and its matrix representation

**Note.**The operations below are taken modulo $_{64}$.

We can see that `rng.vec`

is an array of 607 64-bit numbers. When `Uint64`

is called, two numbers from the array are retrieved, summed and returned. The sum will be stored in the array for future calls. Let $v_{(n)}:=(v_{0},v_{1},...,v_{606})$ be the vector after $n$ `Uint64`

calls. Then the first two $v_{(n)}$s being:

$v_{k}:={v+vv ifk=otherwise ,v_{k}:={v+vv ifk=otherwise ,...$

It is obvious that `Uint64`

changes only one entry at a time. Let's define

$(a_{0},a_{1},...,a_{606}):=(v_{333},v_{332},...,v_{0},v_{606},v_{605},...,v_{334}).$

Furthermore, let also $a_{607},a_{608},...$ be the only changing entry in each round, i.e., $a_{607}:=v_{333}$, $a_{608}:=v_{332}$ and so on. Therefore $a_{607}=a_{0}+a_{334},a_{608}=a_{1}+a_{335},...$.

This is simply a lagged Fibonacci generator. We can represent it as a matrix multiplication, which will be useful when we compute the values efficiently: