VCC Glitching with CW1200 on STM32F3 (CW308)

Here’s a way to get the firmware version out. If this doesn’t work it means the driver or bootloader isn’t right. (Run this in a Python console)

import chipwhisperer.hardware.naeusb.naeusb as naeusb
​
usb = naeusb.NAEUSB()​

usb.con()​

print(usb.readFwVersion())

Good luck!

Well sadly that will not work since the device is no longer detected as a CW :slight_smile: “Failed to find USB device”.

I have tried to reprogram it, now disconnecting it for 30 seconds between operations. BOSSA write and verify works. Results are the same :frowning: Erasing it always works, so I guess that this is good news.

Also, every BOSSA feature seems to work, including Read and Info.

The CWLite is the one with the XMega target. P/N is NPCB-CWLITE-03. In case it helps somehow.

I have just noticed a difference from this image.

https://wiki.newae.com/File:Lights_prog.jpg

Led D9 on my board is much farther from JP1 than the one on the image. It is actually higher than R57, unlike the image that shows it under the resistance.

In case it might be a clue… As I said, I know this version was acquired around 2014.

By the way, about the signals, let me know when you get to check because I am still confused by 3 things:

1 - Single glitch in “single mode”. That sounds dumb, but since it loops over 20 iterations, I expected 20
2 - The fact that the voltage does not seem to go down to 0
3 - The fact that the shape of the glitches seem different between single and continuous.

CWLite fixed! Now that is weird.

For some reason, the firmware version I downloaded from github was 66kb. Then I noticed the one I had included in my installation was actually 57kb, which obviously got my attention.

So I pushed the 57kb one and now everything works. I redownloaded the one from github and now it is also 57kb.

So in short, I was trying to push a file that got messed up somehow, not sure how, but that is why it was not working. :roll_eyes: Odd that BOSSA did not complain about anything.

So much energy wasted…

Anyway, back to VCC glitching. To make it an even better day, my CW1200 tests stopped after 30 minutes last night… You know, sleep after 30 minutes…

Well… Closer, but not there yet:

I’m not a python guru so I’m having a rough time with the script you posted. Wherever I include it in the Jupyter tutorial, I always end up with the same error message:

Traceback (most recent call last):
File “/home/pafortin/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py”, line 295, in txrx
response = self.open(serial_number=payload)
File “/home/pafortin/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py”, line 345, in open
dev.set_configuration(0)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/core.py”, line 869, in set_configuration
self._ctx.managed_set_configuration(self, configuration)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/core.py”, line 102, in wrapper
return f(self, *args, **kwargs)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/core.py”, line 148, in managed_set_configuration
self.backend.set_configuration(self.handle, cfg.bConfigurationValue)
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/backend/libusb0.py”, line 493, in set_configuration
_check(_lib.usb_set_configuration(dev_handle, config_value))
File “/home/pafortin/.local/lib/python3.7/site-packages/usb/backend/libusb0.py”, line 431, in _check
raise USBError(errmsg, ret)
usb.core.USBError: [Errno None] b’could not set config 0: Device or resource busy’
/home/pafortin/chipwhisperer/software/chipwhisperer/common/utils/util.py:474: UserWarning: getName function is deprecated use get_name instead.
warnings.warn(’{} function is deprecated use {} instead.’.format(cc_func, func.name))

The other “cells” of the tutorial are working, so I guess there is something in the script that just does not match… Like a double open-connection maybe?

Additional information: when running the scripts as standalone (the files you attached) and I get the same problem, so it does not seem to be some kind of “interference” from other code in the Jupyter tutorial.

Update. I was finally able to get the script running with the CW1200. I’ll paste the code below. It’s probably bad Python, but since it works, might end up being useful for someone else.

Now the bad news: it’s been running for over 30 hours now. I am a measurement #62767 right now and every single line of the CSV is an “Expected” one so far…

So here’s the code.

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

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

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)

target = cw.target(scope)


#setup()
rejection_builder()

Now at 92000. All “Expected”. :thinking:

Additional information: I am getting the buffer overrun warning on every iteration. Don’t know if it really is a problem or not.

157k. If my calculations are correct, I’m 60% through. Still nothing.

@aross : Now at 200k. All “Expected”. Any point on letting it run? Any idea of what could be the problem?

I mean, if it was packaged as a tutorial/example, I guess it should be working somehow? Unless there is something wrong with my setup?

Hmm, should have found something. I made an edit that puts the scope into continuous mode just for the duration of the attack so make sure you have that. I’m glad to see that script doesn’t crash at least.

I have some parameters working with my Chip Whisperer Lite in the single point glitch attack. Is the CW that you have with the STM32 or the MEGA?

Try this in the single point:

scope.glitch.width = 27.90
scope.glitch.ext_offset = 1000
scope.glitch.offset = -19.0
scope.glitch.repeat = 9

Once we’ve got it working with the CWLITEARM, we should be able to use that script to make sure it actually works. Then we can apply the same strategy to the CW308.

Ok, I’ll edit the script and get it running again.

I have the ChipWhisperer Pro, along with the CW308 with two targets boards: STM32F3 and XMega. I’m currently trying with the STM32.

I also have the CW Lite of my colleague (the one I had issues with the firmware programming). I got the firmware issue figure out, but not the one from this pane:

Okay try this on the CW308. There were some settings that weren’t being set by default. As you can see I put my parameters in already (the ones I mentioned above). This script does work very well for CWLITEARM now. Sorry for the confusion.

from enum import Enum     
from tqdm import tnrange
%matplotlib inline    
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):
    scope.glitch.output = "glitch_only"
    scope.glitch.clk_src = "clkgen"
    scope.glitch.repeat = 9
    
    scope.io.glitch_hp = True
    scope.io.glitch_lp = False
    
    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
    
    width_range = Range(27, 28, step_size)
    offset_range = Range(-20, -19, step_size)
    
    loop_ext_offset = 1000 
    scope.glitch.ext_offset = loop_ext_offset    
    loop_ext_max = 1001  
    
    dataReset = [[],[]]
    dataSuccess = [[],[]]
    dataExpected = [[],[]]
    
    result = Results.Expected
    
    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[ms],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:

                date_time_delta = (datetime.utcnow() - starting_time)
                
                seconds_elapsed = str(date_time_delta.total_seconds())

                scope.glitch.width = loop_width
                scope.glitch.ext_offset = loop_ext_offset
                scope.glitch.offset = loop_offset
                
                counter += 1
            
                loop_width += width_range.step
                
                try:
                    result, line = test_for_success(20)
                except: 
                    setup()
                    
                if result == Results.Success:
                    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:
                    dataExpected[0].append(loop_offset)
                    dataExpected[1].append(loop_width)
                elif result == Results.Reset:
                    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()
    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()

Ok thanks, will try it tonight.

Shall I expect the same connection issues I had with the previous script? (Ref: VCC Glitching with CW1200 on STM32F3 (CW308))

I’m not quite sure what is causing that error. Are you putting in the script like this?

I’ve tried to make it quick to paste in. My only other thought is that you have something else using the device at the same time. It might be worth it to restart your VM, power cycle the CW, etc.

Yes, that’s exactly how I put it up. I’m running in Linux, so no VM.

Before you run my script can you go Kernel > Restart and Clear Output? Do all of the other cells work or (at least run) without exceptions raised?

Did that. Unplugged the CW, rebooted/restarted everything. I’m just running those 3 cells and I get the same error message. Then I try to run the Fault 2 tutorial and everything works (well, from a Python point of view of course).

So there’s something my setup does not like about your script. And it seems to have something to do with the actual connection to the CW (?!).

USBError Traceback (most recent call last)
~/chipwhisperer/software/chipwhisperer/capture/scopes/openadc_interface/naeusbchip.py in con(self, sn)
86 #sn = None
—> 87 found_id = self.dev.con(idProduct=nae_products, serial_number=sn)
88 except (IOError, ValueError):

~/chipwhisperer/software/chipwhisperer/capture/scopes/cwhardware/ChipWhispererLite.py in con(self, *args, **kwargs)
49 def con(self, *args, **kwargs):
—> 50 return self._cwusb.con(*args, **kwargs)
51

~/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in con(self, idProduct, connect_to_first, serial_number)
584
–> 585 self.usbseralizer.open(dev[‘sn’])
586 foundId = dev[‘pid’]

~/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in open(self, serial_number)
157 cmdpacket = self.make_cmd(self.OPEN, serial_number)
–> 158 return self.process_rx(self.txrx(tx=cmdpacket))
159

~/chipwhisperer/software/chipwhisperer/hardware/naeusb/naeusb.py in process_rx(self, inp)
150 if resp == self.ERROR:
–> 151 raise payload
152

USBError: [Errno None] None

During handling of the above exception, another exception occurred:

Warning Traceback (most recent call last)
in
229 return result, line
230
–> 231 setup()
232 rejection_builder()

in setup()
69
70 prog = cw.programmers.STM32FProgrammer
—> 71 scope = cw.scope()
72
73 time.sleep(0.05)

~/chipwhisperer/software/chipwhisperer/init.py in scope(scope_type, sn)
209 scope_type = get_cw_type(sn)
210 scope = scope_type()
–> 211 scope.con(sn)
212 return scope
213

~/chipwhisperer/software/chipwhisperer/capture/scopes/base.py in con(self, sn)
56
57 def con(self, sn=None):
—> 58 if self._con(sn):
59 self.connectStatus = True
60

~/chipwhisperer/software/chipwhisperer/capture/scopes/OpenADC.py in _con(self, sn)
201 def _con(self, sn=None):
202 if self.scopetype is not None:
–> 203 self.scopetype.con(sn)
204
205 self.qtadc.sc.usbcon = self.scopetype.ser._usbdev

~/chipwhisperer/software/chipwhisperer/capture/scopes/openadc_interface/naeusbchip.py in con(self, sn)
87 found_id = self.dev.con(idProduct=nae_products, serial_number=sn)
88 except (IOError, ValueError):
—> 89 raise Warning(‘Could not connect to “%s”. It may have been disconnected, is in an error state, or is being used by another tool.’ % self.getName())
90
91 if found_id != self.last_id:

Warning: Could not connect to “NewAE USB (CWLite/CW1200)”. It may have been disconnected, is in an error state, or is being used by another tool.