VCC Glitching with CW1200 on STM32F3 (CW308)

Since I was not having success with clock glitching (previous post), I decided to move to tutorial F2 for VCC glitching.

Not successful again. However, what bugs me a bit is that I’m not seeing any variation wherever I probe during the glitch process. I tried to monitor VREF, SHUNTL, SHUNTH, VCC3.0 and VCC1.8 and I’m not seeing a single variation there.

I’m running the tutorial as is, without any modification.

Even though there is one part of it that bugs me. It mentions using the LP Mosfet, but the code makes it like it is using the HP one.

Instead of setting the clock source for the target to be the glitch module, we instead set the low power MOSFET’s input to be the glitch module by setting scope.io.glitch_lp to True . The ChipWhisperer-Lite also has a high power MOSFET, but we won’t be using that in this tutorial.

def glitch_on(scope):
scope.io.glitch_lp = False
scope.io.glitch_hp = True
def glitch_off(scope):
scope.gio.glitch_hp = False

But I guess that if it was an issue (Which I don’t see why anyway), someone would have noticed.

Any hint?

Nothing on this one?

I’m currently investigating it, I don’t want to leave you hanging but I’m not having a lot of success either.

If you set:
scope.glitch.trigger_src = “ext_single”
To be
ext_continous

Do you at least get any resets? This will spam glitches out so at least you can verify that the hardware is working as intended.

I’ll be sure to update you if I make any progress. This tutorial has historically worked, it is just way more sensitive than the others.

I assume you mean changing it in block #7 (just before “Glitching a single point”)? Because it is already set to continuous in the following section (Improving Glitch Settings).

Might sound dumb, but how should I tell that I got some resets? I thought the CW does reset the target with reset_target()?

I am getting some “WARNING:root:SAM3U Serial buffers OVERRUN - data loss has occurred.” messages once in a while.

By the way, here’s that other “problem” I got with the progress bars that seem to crash above 51%. I used the following ranges for offset and width

width_range = Range(35, 40, 0.2)
offset_range = Range(-30, -25, 0.2)

The image attached shows the result.

Your assumption is correct, and ideally, it should stay single. If you can scope it, you should see constant glitching attacks and you might be able to get an idea of where the code execution is most sensitive.

I’ve found that the crashing can happen if the loop runs too fast so a quick workaround is this.

At the line:
for j in tnrange(sample_size, leave=False, desc=“Attempt”):
(From the block in your screen shot) Try adding:
time.sleep(1).

This will add a one-second delay. You might be able to tune this value but it should make things a bit more stable.

You will know if a reset occurred if “Target Crashed” appears in the print-out. Python is looking for “hello” on the serial line.

The ext_offset is another value that you can play with. As you’ve probably noticed there are quite a few variables that can be tuned here. I’m playing with some scripts that might take a while to run but should tell you exactly where to look. I’ll be sure to update you if I have any success.

I have never encountered a “Target Crashed” message. But with the “progress bar issue”, it is quite possible that there is a large chunk of offset/width range that is not being attempted.

I assume that I should scope at the SHUNTL pin to monitor for the glitches?

That’s correct. Just be aware that if having a scope on it can have an impedance effect so running it with the same parameters afterwards might not work.

A good “tuning” strategy I had work for me on other boards was by trying to a width wide enough to cause a reset and conversely find one small enough to not cause it. Take the mid point of the two and try that. Repeat back and forth trying to find the new “reset” value and the “non-reset” value. The glitch point will be somewhere in the middle It won’t be perfect, but in my experience I’ve found that the width has the biggest impact. I found it funny that 16.4 would work for me, 16 and 16.8 would not.

Ok. I will try this later today.

Should I try with fixed width to be sure that these values are tested, due to that “progress bar” issue? Otherwise I fear that over half of my range values might not be tested so that I would end up considering these as ineffective while it’s just that they were never actually tested.

I wouldn’t try tuning in that block with the progress bars. Instead try just using the block in section 1.3.3.

I changed my cell around so that the scope values are conveniently close so you don’t have to jump around:

from tqdm import tnrange

reset_target(scope)
target.flush()
time.sleep(1)
scope.arm()
scope.glitch.clk_src = "clkgen"
scope.glitch.output = "glitch_only"
scope.glitch.trigger_src = "ext_single"
#scope.glitch.trigger_src = "ext_continuous"

scope.glitch.width =-45.3
scope.glitch.offset = 10

scope.glitch.repeat = 9
scope.glitch.ext_offset = 2186

for j in tnrange(20):
    line = ""
    
    while "\n" not in line:
        time.sleep(0.1)
        line += target.read()
    lines = line.split("\n") 
    if len(lines) > 1:
        line = lines[-1]
    else:
        line = ""
    
    while "\n" not in line:
        time.sleep(0.1)
        line += target.read()
        
    if "hello" in line:
        print("Target crashed")
    nums = line.split(" ")
    try:
        if int(nums[0]) != 40000:
            print(line)
        print(line)
    except ValueError as e:
        continue

if SCOPETYPE == "OPENADC":
    scope.glitch.trigger_src = "ext_single"

Ok so you would try it only in the loop that attempts just 20 glitches for now?

I have tried your code and still get nothing. At most, I (think?) I’m getting effects on the transmission because sometimes the display of the response is incomplete (e.g. I’m getting 40000 200 200 and no value for the last counter). However, I’m getting similiar results even with the sma cable unplugged so…

I’m not seeing much happening on the SHUNTL pin. However, I have a rather crappy USB oscilloscope (Digilent Analog Discovery 2), limited at 100MHz and I have to admit I’m not sure it is 100% reliable. Might try to borrow a better one to double check.

Still with the crappy scope, it seems like I am seeing some very very narrow short pulses on the SHUNTL pin. In ext_single mode, I’ve seen only 1 of them over the whole 20 series. In ext_continuous, I’ve seen more (like … 34 ?!).

Ok so I managed to borrow a Picoscope to perform better measurements.

I ran the code you posted, both in single and continuous modes.

In single, I’m seeing only one glitch. I guess this is what single is all about, but I expected to see one on every 20 iteration of the loop, so I am a bit surprised.

As you’ll see on the screenshot, the glitch looks quite “bouncy” and does not seem to go under 1.0V. This was measured at the SHUNTL pin.

In continuous, I’m seeing more like 43-44 pulses. Here’s a wide view and a closeup view.

Not bouncing as much as the single shot, but again, not going below 1.0V.

Hopefully this gives you a clue or a hint.

Since I have not got a feedback on the signals capture, I had another idea. I have a colleague who has a CWLite, so I thought I could borrow it and try it, so I could compare and maybe figure out if the problem is on the CW1200 side or the target side.

However, when trying to run the tutorial, I got the following error message.

However, his unit is rather old, like 2014-2015, so I guess it’s possible that there might need some kind of firmware update for it to work with the up-to-date tools?

Anyway, am stuck again.

Hi,

So to look into this a bit better myself, I came up with a new script that would walk through the requested ranges. It will also output a CSV log (saved in the active Jupyter directory) for you so that if it crashes you can skip data points on your next go, however, it should be stable for you, as it will attempt to catch crashes and not lose your spot. At the end, it will make you a rejection map to show where you had successes/resets/expected outputs.

I have made the ext-offset a single range but changing that will have some effect. Obviously this is a very time-consuming test so I’d suggest running it overnight.

If it seems setup funny it’s because I was running it outside of Jupyter. I’ve attached the files in case you want to do the same. Note that if you want to cancel it with keyboard interrupts, you might have to try a few times as the error handling is aggressive.

To integrate this into Jupyter do the following:

Underneath the first cell (SCOPETYPE, etc.) insert a new cell with another cell from later in the tutorial:

%%bash -s "$PLATFORM"

cd ../hardware/victims/firmware/glitch-simple

make PLATFORM=$1 CRYPTO_TARGET=NONE FUNC_SEL=GLITCH_INF

Then insert another new cell and paste this in:

from enum import Enum     
from tqdm import tnrange
import matplotlib
import matplotlib.pyplot as plt
from collections import namedtuple
import time
import chipwhisperer as cw
import csv
import re 
from datetime import datetime

SCOPETYPE = 'OPENADC'
PLATFORM = 'CWLITEARM'
sample_size = 5

if "STM" in PLATFORM or PLATFORM == "CWLITEARM" or PLATFORM == "CWNANO":
    prog = cw.programmers.STM32FProgrammer
elif PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
    prog = cw.programmers.XMEGAProgrammer
else:
    prog = None
    
try:
    if not scope.connectStatus:
        scope.con()
except NameError:
    scope = cw.scope()
    
target = cw.target(scope)

try:
    if not scope.connectStatus:
        scope.con()
except NameError:
    scope = cw.scope()
    
target = cw.target(scope)

SCOPETYPE = 'OPENADC'
PLATFORM = 'CWLITEARM'
sample_size = 5

import time
time.sleep(0.05)
scope.default_setup()

def reset_target(scope):
    if PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
        scope.io.pdic = 'low'
        time.sleep(0.05)
        scope.io.pdic = 'high_z' #XMEGA doesn't like pdic driven high
        time.sleep(0.05)
    else:  
        scope.io.nrst = 'low'
        time.sleep(0.05)
        scope.io.nrst = 'high'
        time.sleep(0.05)    
    
def setup():
    fw_path = "../hardware/victims/firmware/glitch-simple/glitchsimple-{}.hex".format(PLATFORM)
    
    prog = cw.programmers.STM32FProgrammer
    scope = cw.scope()
    
    time.sleep(0.05)
    scope.default_setup()
    reset_target(scope)

    print(fw_path)
    cw.program_target(scope, prog, fw_path)
    
def rejection_builder():
    Range = namedtuple('Range', ['min', 'max', 'step'])

    step_size = (1/512)*100
    #step_size = 1

    min_value = -49
    max_value = min_value*-1
    
    #change the values here:
    width_range = Range(min_value, max_value, step_size)
    offset_range = Range(min_value, max_value, step_size)
    
    loop_ext_offset = 2185 
    scope.glitch.ext_offset = loop_ext_offset    
    loop_ext_max = 2186  
    
    dataReset = [[],[]]
    dataSuccess = [[],[]]
    dataExpected = [[],[]]
    
    print("Starting loop: ")
    
    #starting points
    loop_offset = offset_range.min
    loop_width = width_range.min  
    
    counter = 0
    
    timestr = time.strftime("%Y-%m-%d__%H%M%S") 
    csv_file_name = 'rejection_builder_log' + timestr + ".csv"
    f = open(csv_file_name,'w')
    f.write("Time[s],EXT_Offset, Offset, Width, Result, Raw Line \n")
    
    starting_time = datetime.utcnow()

    while loop_ext_offset < loop_ext_max: 
        loop_offset = offset_range.min

        while loop_offset < offset_range.max:
            loop_width = width_range.min
    
            while loop_width < width_range.max:

                time_now = datetime.utcnow()
            
                print("Last run at: {}".format(time_now.strftime("%H:%M:%S")))
                date_time_delta = (time_now - starting_time)
                
                seconds_elapsed = str(date_time_delta.total_seconds())

                scope.glitch.width = loop_width
                scope.glitch.offset = loop_offset
                scope.glitch.trigger_src = "ext_single"
                scope.glitch.repeat = 9
                
                counter += 1
            
                loop_width += width_range.step
                
                try:
                    result, line = test_for_success(3)
                except: 
                    setup()
                    
                if result == Results.Success:
                #if counter % 3:
                    dataSuccess[0].append(loop_offset)
                    dataSuccess[1].append(loop_width)
                    print("Loop width: {}, Loop offset: {} Loop ext_offset: {} Result: {} Raw Line: {}" .format(loop_width, loop_offset, loop_ext_offset, result, line))
                    print("success")
                elif result == Results.Expected:
                #elif counter % 2:
                    dataExpected[0].append(loop_offset)
                    dataExpected[1].append(loop_width)
                elif result == Results.Reset:
                #else:
                    dataReset[0].append(loop_offset)
                    dataReset[1].append(loop_width)
                
                line_list =  list(map(str.strip,line))
                
                line = ''.join(line_list) 
                result_string = str(result).strip("Result.")
                f.write("{},{},{},{},{},{}\n".format(seconds_elapsed, loop_ext_max, loop_offset, loop_width, result_string, line))
                        
                #print("Loop width: {}, Loop offset: {} Loop ext_offset: {} Result: {}" .format(loop_width, loop_offset, loop_ext_offset, result))
        
            loop_offset += offset_range.step
        loop_ext_offset += 1
        
    f.close()
    
    plt.scatter(dataReset[0], dataReset[1], marker='o')
    plt.scatter(dataSuccess[0], dataSuccess[1], marker='x')
    plt.scatter(dataExpected[0], dataExpected[1], marker='v')


    #plt.scatter(dataSuccess[0], dataSuccess[1], 'r--', dataReset[0], dataReset[1], 'bs', dataExpected[0], dataExpected[1], 'g^')

    plt.show()

class Results(Enum):
    Reset = 0
    Expected = 1
    Success = 2

# Looks for a gltiched output
# If a success is detected it will break regardless of attempts left 
# in order to reduce to a single data point of parameters 
def test_for_success(attempts):    
    
    reset_target(scope)
    
    target.flush()
    time.sleep(1)
    scope.arm()
    if SCOPETYPE == "OPENADC":
         scope.glitch.trigger_src = "ext_continuous"
    
    result = Results.Expected

    line = ""
    for j in range(attempts):
        
        line = ""
                
        while "\n" not in line:
            time.sleep(0.1)
            line += target.read()
        lines = line.split("\n") 
        if len(lines) > 1:
            line = lines[-1]
        else:
            line = ""
        
        while "\n" not in line:
            time.sleep(0.1)
            line += target.read()
            
        if "hello" in line:
            result = Results.Reset         
        nums = line.split(" ")
        try:
            if (int(nums[0]) != 40000 or int(nums[1]) != 200 or int(nums[2]) != 200 ) and nums[0] != '':        
                result = Results.Success  
                break      
        except ValueError as e:
            if(result != Results.Success):
                continue
            else:
                break
    if SCOPETYPE == "OPENADC":
         scope.glitch.trigger_src = "ext_single"
    return result, line  

setup()
rejection_builder()

Edit: Added last run on output so you can see if it’s stalled. Also trying in continuous mode
rejection_builder.zip (10.8 KB)

This to me seems a bit more like a driver issue, they do use different sets of drivers so check your device manager and see if it’s being detected.

If that’s not the issue, you can attempt a firmware upgrade as discussed here:
https://wiki.newae.com/CW1173_ChipWhisperer-Lite/Upgrading_SAM3U_Firmware

It is detected, both under windows and linux.

Bus 001 Device 005: ID 2b3e:ace2 NewAE Technology Inc. ChipWhisperer Lite

So I will try to update the firmware and see what happens.

I will also run your other test, hopefully tonight. Have you noticed anything fishy in the scope captures?

Also, since the instructions seem to relate to the older version of CW, is there a way to check the firmware version while using CW5? I guess I should use the “Manual update” instructions?

Ok. More fun.

I tried to reprogram the firmware of the CWLite using the manual SAM3U procedure. Everything seemed to work until I unplugged and replugged the device, at which point I was supposed to have a ChipWhisperer again.

But it is not the case. Red and blue lights remain dim, just like they were after the “Erase” and the device is not detected as a CW.

I used the firmware located here: https://github.com/newaetech/chipwhisperer/blob/develop/hardware/capture/chipwhisperer-lite/sam3u_fw/SAM3U_VendorExample/Debug/SAM3U_CW1173.bin

So on top of everything now I have bricked the CWLite of a colleague. I’m on a good streak :slight_smile:

That’s no good!

This was a link posted on that wiki I posted above:

https://wiki.newae.com/Manual_SAM3U_Firmware_Update

Did you follow the instructions there? I believe if you’re still seeing LEDs turn on there is hope that you haven’t bricked the board.

Yes, that’s the instructions I have followed. And I downloaded the firmware binary from the GitHub link pasted above.

Everything seemed to work fine until I reached step 4 (“Unplug & Replug the Micro-USB and you’ve got a working ChipWhisperer-Lite again, with the latest SAM3U firmware!”). At that point, the red and blue lights remained dim, and the board was not detected as a CW.

But up to that point, everything worked fine. On shorting the reset pins, the blue light remained on, unplug/replug got the red and blue leds dim, write and verify with Bossa seemed to work fine.

So my first fear was that I did not use the right firmware file.