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:
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.
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.
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.
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.