Fault101 Lab 1_4, Recovering incorrect AES key

I’m working on “Authenticated AES Bootloader” and successfully bypassed the authentication check in the first half of the lab. However, my script for the second half (recovering the AES key) is returning an incorrect key, and I’m having trouble determining where my issue is.

I’m using a ChipWhisperer Lite with the XMEGA target board.

The following glitch parameters worked for both the authentication bypass and the Fault101 1_3 lab:

scope.glitch.width = 45.3125
scope.glitch.offset = -49.609375

This is my current script:

import chipwhisperer.common.results.glitch as glitch
from tqdm.notebook import trange
import struct

scope.glitch.width = 45.3125
scope.glitch.offset = -49.609375
gc.set_range("ext_offset", 8800, 8920)
step = 1
gc.set_global_step(step)
scope.glitch.repeat = 1

scope.adc.timeout = 0.1

reboot_flush()
target.reset_comms()
x = []
req_enc = 100
scope.adc.offset = 0 #10000
encs = 0

project = cw.create_project("projects/test_bootloader", overwrite=True)

while True:

    for glitch_setting in gc.glitch_values():
    
        scope.glitch.ext_offset = glitch_setting[0]
    
        # optional: you can speed up the loop by checking if the trigger never went low
        #           (the target never called trigger_low();) via scope.adc.state

        if scope.adc.state:
            # can detect crash here (fast) before timing out (slow)
            print("Trigger still high!")
            gc.add("reset")
            reboot_flush()
            target.reset_comms()

        #Do glitch loop
        key, text = ktp.next()
        cpy_text = bytearray(text)
        text.extend([0x00])
        scope.arm()
        target.simpleserial_write("p", text)
        ret = scope.capture()
        val = target.simpleserial_read('e', 1, ack=False)
        #print(val)

        if ret: #here the trigger never went high - sometimes the target is still crashed from a previous glitch
            print("Timeout - no trigger")
            gc.add("reset")

            #Device is slow to boot?
            reboot_flush()
            target.reset_comms()
        else:
            if val is None: # change this to detect an invalid response
                gc.add("reset")
            else:
                # gcnt is the loop counter
                gcnt = val[0]

                if gcnt == 0x11: #normal response
                    gc.add("normal")
                elif gcnt == 0x00: #glitch!!!
                    gc.add("success")
                    print(f"{encs}: {scope.glitch.width} {scope.glitch.offset} {scope.glitch.ext_offset}")
                    x.append(scope.get_last_trace())
                    trace = cw.Trace(scope.get_last_trace(), cpy_text, key, key)
                    project.traces.append(trace)
                    encs += 1
                    
    if encs >= req_enc:
        print("Captured enough traces, exiting")
        break

It scans through a small range of known good ext_offset values based on the authentication bypass results. I’ve also tested hardcoding ext_offset as well.

Recovering the AES key:

import chipwhisperer as cw
project = cw.open_project("projects/test_bootloader")

import chipwhisperer.analyzer as cwa
leak_model = cwa.leakage_models.inverse_sbox_output_alt
attack = cwa.cpa(project, leak_model)
results = attack.run(cwa.get_jupyter_callback(attack))

bytearray(cwa.aes_funcs.key_schedule_rounds(results.key_guess(), 10, 0))
bytearray(b'4\xf6S\xd8M\xf8\xcb\x82\xb2\xb2\xd0\xea\x9c\x00"\xda')

My trace files (test_bootloader project): test_bootloader_project.tgz - Google Drive

Hi,

Thanks for the report on this. Lab 1_4 currently isn’t covered by our notebook tests, so it’s possible a change we made caused it to stop working. I’ll take a look.

Alex

1 Like

Quick update on this - I ended up testing on the Husky, Lite Arm and Lite XMEGA. For the XMEGA, make sure that, for the CPA part, make sure you’re actually capturing the encryption operation. Also, if there’s a lot of jitter, try resynchronizing your traces.

Alex