CPA attack for AES256

I am trying to perform a CPA attack on CW305 with AES-256.

The default ChipWhisperer demo/notebooks are for AES-128.

I would like to know:

  • What changes are needed in the CPA analyzer for AES-256?

  • Can the same leakage models used for AES-128 be used for AES-256?

  • Any example or guidance for adapting the CW305 AES-128 demo to AES-256?

We explain that in this notebook: Extending AES-128 Attacks to AES-256.ipynb.

As for the CW305 AES demo, you should be able to simply change the size_i input of aes_core.v. On the Python API side you’ll have to modify CW305.py to send the larger key.

I have successfully modified the CW305 AES demo from AES-128 to AES-256 on FPGA side, and capture is working properly. I am able to collect traces without issues.

However, I am facing problems during the CPA attack stage. The default leakage model used in the demo:

attack = cwa.cpa(project, cwa.leakage_models.last_round_state_diff)

does not seem to work correctly for AES-256.

I suspect this may be because the default leakage model and attack configuration are mainly designed for AES-128. Since AES-256 uses 14 rounds and a different key schedule, the last-round leakage model may no longer align properly.

We don’t have out-of-the-box support for AES256 leakage models. We may add it in the future - for now you can either consider coding it yourself (see e.g. this notebook where we teach how to build a leakage model from scratch for AES-128: chipwhisperer-jupyter/courses/sca101/Lab 4_2 - CPA on Firmware Implementation of AES (MAIN).ipynb at fe7e2aa1585798c3a5a6b247f231abe2e2b4a2cd · newaetech/chipwhisperer-jupyter · GitHub), or use a third-party library like SCARED or LASCAR.

Dear Sir,

I am able to recover the Phase-1 (Round-14) key using the referenced AES-256 CPA attack methodology.

However, I am unable to recover the Phase-2 key. I have implemented the leakage model based on your inputs.

Could you please suggest how I can verify that the Phase-2 CPA attack, leakage model, and key schedule implementation are correct?

Regards,
Jogendra

What’s phase 2? That’s not something we reference in our notebooks.

chipwhisperer-jupyter/courses/sca201/Extending AES-128 Attacks to AES-256.ipynb at fe7e2aa1585798c3a5a6b247f231abe2e2b4a2cd · newaetech/chipwhisperer-jupyter · GitHub, In this link you are saying Getting second half of the key you have mentioned in the procedure. 1st half of the key i am getting peg values are zero. but in the second half of the key i am getting higher PGE values.

I have done the coding for 2nd half of the key using your shared document as below..“”"

def leakage(self, pt, ct, guess, bnum):

K14_recovered must be defined in the cell above before this runs

state = [ct[i] ^ K14_recovered[i] for i in range(16)] # undo AddRoundKey(K14)
state = self.inv_shiftrows(state) # undo ShiftRows
state = self.inv_subbytes(state) # undo SubBytes — ATTACK POINT
state = self.inv_mixcolumns(state) # undo MixColumns
state = self.inv_shiftrows(state) # undo Round 13 ShiftRows
return self.inv_sbox(state[bnum] ^ guess[bnum]) # predict leakage


def process_known_key(self, inpkey):
    K13 = key_schedule_rounds(list(inpkey), 0, 13)
    return list(inv_shiftrows(list(inv_mixcolumns(K13))))

leak_model_p2 = cwa.leakage_models.new_model(AES256_Round13_Model)
attack2 = cwa.cpa(project, leak_model_p2)

Try to attack via first and second addRoundKey. It is much easier. Use HW(pt ^ key) leakage model.

Hi, can you share the any document pl.. or any procedure document can you share

I would recommend to study what you are doing first otherwise all your activity will be useless.

The side channel attacks are what you should do by yourself without templates and stereotypes.

This part is correct

state = [ct[i] ^ K14_recovered[i] for i in range(16)] # undo AddRoundKey(K14)
state = self.inv_shiftrows(state) # undo ShiftRow
sstate = self.inv_subbytes(state) # undo SubBytes

The problem is you are trying to move to the round 13 entry with just a single key byte. You cannot do this as MixColumn13 and Sbox13 make it impossible for just a single byte of key guess.

state = self.inv_mixcolumns(state) # undo MixColumns
state = self.inv_shiftrows(state) # undo Round 13 ShiftRows
return self.inv_sbox(state[bnum] ^ guess[bnum]) # predict leakage

Well, you already recovered the K14 round key by guessing the key candidates and measuring correlation between last round input and ciphertext.

The next step is you have to try to attack the state before and after addRoundKey13.

val_before_key = state_14_in[bnum] ^ guess # get "before addRoundKey13" state

hw(val_before_key ^ state_14_in[bnum])     # HD before and after addRoundKey13 states

Important thing which worth to mention - you are able to recover the first part of the key easily due to specific of AES implementation in hardware. Usually, the round state is written into the state register. So, having ciphertext and the fact the last round state is latched into the register gives you benefit to recover the key.

The second part is more problematic (assuming you are recovering the key from the tail of encryption). The MixColumn output is usually not latched into the own register. It is pure combinational logic. You can try to increase the sampling rate and hope that XOR gates of addRoundKey produce the leakage.

I guess you used the AES-256 attack scenario from here

But I have doubts this code is valid and works:

def leakage(self, pt, ct, guess, bnum):
        #You must but YOUR recovered 14th round key here - this example may not be accurate!
        calc_round_key = [0xea, 0x79, 0x79, 0x20, 0xc8, 0x71, 0x44, 0x7d, 0x46, 0x62, 0x5f, 0x51, 0x85, 0xc1, 0x3b, 0xcb]
        xored = [calc_round_key[i] ^ pt[i] for i in range(0, 16)]
        block = xored
        block = self.inv_shiftrows(block)
        block = self.inv_subbytes(block)
        block = self.inv_mixcolumns(block)
        block = self.inv_shiftrows(block)
        result = block
        return self.inv_sbox((result[bnum] ^ guess[bnum]))

even if mixColumn’s linearity will be passed by the Pearson correlation properties, Sbox non-linearity will break everything and makes impossible to guess the single byte of the key. MixColumns will spread the key bits but Sbox completely destroys relations.

That code is valid for software AES256 at least. You know the state up until the final inv sbox/ARK, so very similar to a typical sbox leakage model, except for the fact you need to transform the resulting key to account for mixcolumns and shiftrows. It’s better explained here: chipwhisperer-jupyter/courses/sca201/Extending AES-128 Attacks to AES-256.ipynb at main · newaetech/chipwhisperer-jupyter · GitHub

I agree that the position of the state register in the algorithm is likely the issue. You may need to do something like a chosen plaintext attack like described here: chipwhisperer-jupyter/courses/sca201/Lab 2_3 - Attacking Across MixColumns.ipynb at main · newaetech/chipwhisperer-jupyter · GitHub

IIRC we did try looking for leakage from just the combinational logic on a different implementation and did get a partially successful attack somewhere in the millions of traces.