Power Analysis against Secure CAN

Hi,
I am currently trying to perform the attack GitHub - newaetech/secure-CAN-demo: Implementation of secure CAN network in "Power Analysis and Fault Attacks against Secure CAN: How Safe Are Your Keys?".. To begin with I ignore the complete CAN setup and only generate AES-CCM powertraces on my STM32F303 target based on the code from the repo. Now I want to attack the encryption key.
The problem is that, due to the architecture of the protocol, only the first three bytes of the plaintext are variable and the rest is static. This means that the CPA attack can only be successfully executed on the first 2-3 bytes. An attack on the ciphertext is not possible as this is not known due to the protocol.
In my research I found out that I can solve the problem by attacking an inner round of the AES, where the 3 variable bytes have already caused enough variation. However, I have problems implementing this, as I would have to simulate the first rounds with theoretical values.
Is this even possible or have I understood everything correctly? And if so, is there any code in the ChipWhisperer project that could help me with the implementation?

Thanks in advance!

No, we don’t have any examples for attacking AES-CCM specifically.
You can find papers which explain practicalities of CCM attacks, for example: https://eprint.iacr.org/2015/529.pdf

1 Like

Hi, thanks for the paper. I have implemented the attack based on the Lab 4.2 solution notebook:

import chipwhisperer.analyzer as cwa


### Attack subbyte 1 and 2, as there is enough variation here due to the counter
### Code from SOLN_Lab 4_2 - CPA on Firmware Implementation of AES.ipynb

t_bar = np.sum(trace_array, axis=0)/len(trace_array)
o_t = np.sqrt(np.sum((trace_array - t_bar)**2, axis=0))

cparefs = [0] * 16 
bestguess = [0] * 16 

for bnum in trange(1, 3):
    maxcpa = [0] * 256
    for kguess in range(0, 256):
        hws = np.array([[HW[aes_internal(textin[bnum],kguess)] for textin in textin_array]]).transpose()
        hws_bar = mean(hws)
        o_hws = std_dev(hws, hws_bar)
        correlation = cov(trace_array, t_bar, hws, hws_bar)
        cpaoutput = correlation/(o_t*o_hws)
        maxcpa[kguess] = max(abs(cpaoutput))
    bestguess[bnum] = np.argmax(maxcpa)
    cparefs[bnum] = max(maxcpa)

print("Best Key Guess: ", end="")
for b in bestguess: print("%02x     " % b, end="")

print("\nBest Key Proba: ", end="")
for b in cparefs: print(f"{round(b*100,1)}%   ", end="")

print("\nReal Key:       ", end="")
for b in key: print("%02x     " % b, end="")


bestguess[0] = 0

# Simulate next round based on https://eprint.iacr.org/2015/529.pdf

textin_round2_array = []

for text in textin_array:
    state = [0] * 16
    state[1] = text[1] ^ bestguess[1]
    state[2] = text[2] ^ bestguess[2]
    state = cwa.attacks.models.aes.funcs.subbytes(state)
    state = cwa.attacks.models.aes.funcs.shiftrows(state)

    state = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, state[10], 0, 0, state[13], 0, 0]
    state = cwa.attacks.models.aes.funcs.mixcolumns(state)
    textin_round2_array.append(state)



# Using the CPA code again but with the output of round 1 mixcolumns

cparefs = [0] * 16 #put your key byte guess correlations here
bestguess = [0] * 16 #put your key byte guesses here

for bnum in trange(0, 16):
    maxcpa = [0] * 256
    for kguess in range(0, 256):
        hws = np.array([[HW[aes_internal(textin[bnum],kguess)] for textin in textin_round2_array]]).transpose()
        hws_bar = mean(hws)
        o_hws = std_dev(hws, hws_bar)
        correlation = cov(trace_array, t_bar, hws, hws_bar)
        cpaoutput = correlation/(o_t*o_hws)
        maxcpa[kguess] = max(abs(cpaoutput))
    bestguess[bnum] = np.argmax(maxcpa)
    cparefs[bnum] = max(maxcpa)

print("Best Key Guess: ", end="")
for b in bestguess: print("%02x     " % b, end="")

print("\nBest Key Proba: ", end="")
for b in cparefs: print(f"{round(b*100,1)}%   ", end="")


# Compare with the first Round key
first_round_key = cwa.attacks.models.aes.key_schedule.key_schedule_rounds(key, 0, 1)

print("\nFirst Round Key: ", end="")
for b in first_round_key: print("%02x     " % b, end="")

With the help of this code I am able to get subbyte 1 and 2 correctly. Unfortunately, the output of the attack on round 2 does not seem to work. Here is the output for the first and the second attack:

I hope I’m not asking for too much, but do you have any ideas what might go wrong?