Official description
You will have to analyze the consumption traces of an early implementation of the AES made by Myster Mask. Will you be able to exploit these traces to make the difference?
The part to target corresponds to the inversion step in the calculation of the Sbox in the first round of the AES. Only this step is implemented, it is not necessary to know the AES since this challenge is specifically focused on the inversion step.
The consumption traces provided correspond to the following call:
1
masked_inversion(L)
Beware! Myster Mask has protected this inversion by honoring his name. Now it’s your turn to play!
SHA256(
traces.npz
) =d4e16ded8c53f6e295672567cd8bdd3453ebd1318bf353b827c40cda17698fe4
SHA256(inputs.npz
) =283b4245a36d7d238ba941a247eaaa38cc90d8db2f3c4e7db824d241a6c21603
We get 4 files: traces.npz
(sidechannel traces), inputs.npz
(plaintexts), myster_mask.py
(the algorithm) and output.txt
(the ciphertext to decode).
Exploration
output.txt
contains an initial vector iv
and a ciphertext c
.
myster_mask.py
shows how the masked algorithm works.
We take a look at mask
and unmask
functions. After a bit of paper reading,
we learn that this is a multiplicative 5 shares masking in Galois field 256
GF256
.
The challenge description indicates that sidechannel traces correspond to the execution of this function:


We recognize in the averaging of all sidechannel traces the 16 iterations of
j
in 5 iterations of i
.
During the challenge I tried multiplying every 5 spikes corresponding to each masking share, then correlating each {key hypothesis XOR input} on them. I was unable to recover the key using this method.
Proposed solution
Multiplicative Masking and Power Analysis of AES, by GoliÄ‡, J.D., Tymen, C. (2003) is a nice ressource to understand and solve this challenge. They introduce GF256 multiplicative masking then in section 2 explains how to setup a differential power analysis of AES.
As GF256(0)
equals 0, calling mask(0)
will always put a 0 in the first share.
This implies that if key[i]
and input[i]
are equals, then
key[i] XOR input[i]
is 0 i.e. the masked first share is 0.
Let’s attack each \(i\)th key byte separately.
For each \(K\) key byte hypothesis, let’s filter \(M\) traces in which
key[i]
and input[i]
are equals.
Then we compare the average of \(M\) to the average trace. If the difference is
the most important, then it means that the hypothesis may be the right key.


After some seconds, we get the flag:
0.03693260569852941 224
[...]
0.035091276041666675 63
b'FCSC{8e29ba7aa273cc1b3ea74defe5972fd7ff4a0180acf790bddb25980289c8
1d60}\n\t\t\t\t\t\t\t\t\t'