Skip to main content

side channels: using the chipwhisperer

This is a post in a series regarding side channels, from the theoretical and pratical point of view; the posts are

  • introduction on the model of computing devices (to be finished)
  • using the Chipwhisperer (this post)
  • power analysis (here)
  • glitching (to be finished)

All the practical experimentations performed in these posts are done using my own Chipwhisperer's board, the CWLITE one, it's an open source, open hardware device that allows to quickly setup and execute side channels related attacks.

This model come along with its own target board attached (named CW303 with an an Atmel's XMEGA128 (datasheet)) and in the official repository of the project are available a couple of firmwares to experiment with.

Installation steps

This part is primarly for me in order to remember what I did to getting started, you can see a more precise (and up to date) procedure in the documentation.

First of all you need to have the board accessible by the user

# bash -c 'printf "SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"2b3e\", ATTRS{idProduct}==\"*\", TAG+=\"uaccess\"\\n" >> /etc/udev/rules.d/50-newae.rules'
# bash -c 'printf "SUBSYSTEM==\"tty\", ATTRS{idVendor}==\"2b3e\",ATTRS{idProduct}==\"*\", TAG+=\"uaccess\", SYMLINK+=\"cw_serial%n\"\\n" >> /etc/udev/rules.d/50-newae.rules'
# bash -c 'printf "SUBSYSTEM==\"tty\", ATTRS{idVendor}==\"03eb\",ATTRS{idProduct}==\"6124\", TAG+=\"uaccess\", SYMLINK += \"cw_bootloader%n\"\\n" >> /etc/udev/rules.d/50-newae.rules'
# udevadm control --reload-rules
# usermod -a -G dialout $USER

(these steps above must be done only once system-wide); then you can install the library

$ git clone && cd chipwhisperer
$ git submodule update --init jupyter                        # To get the jupyter notebook tutorials
$ python3 -m pip install -r jupyter/requirements.txt --user
$ jupyter nbextension enable --py widgetsnbextension         # enable jpyter interactive widgets
$ python3 -m pip install -e . --user                         # use pip to install in develop mode

the jupyter part is related to the tutorials, if you don't need them, only clone and install.

The compilation of the firmware for the target can be done in this way, where the -C flag tells which firmware we want (PLATFORM tells the build sistem that the target is the XMega)

$ make -C hardware/victims/firmware/simpleserial-base PLATFORM=CW303

If instead you want to compile some code "out of the tree" you can use directly the compiler with the right flags:

$ avr-gcc \
    -Wall \
    -mmcu=atxmega128d3 \
    -o <output ELF file \
    <c source file>
$ avr-objcopy -O ihex <ELF file> <HEX file>

the last line generates the HEX file that is the format needed for flashing.

In general is very useful to double check the generated code; you can use avr-objdump

$ avr-objdump -d <ELF file> | less

The ChipWhisperer's library is implemented in python and you can use the REPL to interact with the device, for the example the following is a snippet of a session

Python 3.7.5 (default, Oct 27 2019, 15:43:29)
[GCC 9.2.1 20191022] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import chipwhisperer as cw
>>> scope = cw.scope()
>>> scope
cwlite Device
gain =
    mode = low
    gain = 0
    db   = 5.5
adc =
    state      = False
    basic_mode = low
    timeout    = 2
    offset     = 0
    presamples = 0
    samples    = 24400
    decimate   = 1
    trig_count = 226703590
clock =
    adc_src       = clkgen_x1
    adc_phase     = 0
    adc_freq      = 96000000
    adc_rate      = 96000000.0
    adc_locked    = True
    freq_ctr      = 0
    freq_ctr_src  = extclk
    clkgen_src    = system
    extclk_freq   = 10000000
    clkgen_mul    = 2
    clkgen_div    = 1
    clkgen_freq   = 192000000.0
    clkgen_locked = True
trigger =
    triggers = tio4
    module   = basic
io =
    tio1       = serial_tx
    tio2       = serial_rx
    tio3       = high_z
    tio4       = high_z
    pdid       = high_z
    pdic       = high_z
    nrst       = high_z
    glitch_hp  = False
    glitch_lp  = False
    extclk_src = hs1
    hs2        = None
    target_pwr = True
glitch =
    clk_src     = target
    width       = 10.15625
    width_fine  = 0
    offset      = 10.15625
    offset_fine = 0
    trigger_src = manual
    arm_timing  = after_scope
    ext_offset  = 0
    repeat      = 1
    output      = clock_xor
>>> target =
Serial baud rate = 38400

However you need to call the default_setup() in order to have all configured correctly

class OpenADC(ScopeTemplate, util.DisableNewAttr):
    """OpenADC scope object.  ..."""

    def default_setup(self):
        """Sets up sane capture defaults for this scope

         *  45dB gain
         *  5000 capture samples
         *  0 sample offset
         *  rising edge trigger
         *  7.37MHz clock output on hs2
         *  4*7.37MHz ADC clock
         *  tio1 = serial rx
         *  tio2 = serial tx

        .. versionadded:: 5.1
            Added default setup for OpenADC
        self.gain.db = 25
        self.adc.samples = 5000
        self.adc.offset = 0
        self.adc.basic_mode = "rising_edge"
        self.clock.clkgen_freq = 7.37e6
        self.trigger.triggers = "tio4" = "serial_rx" = "serial_tx" = "clkgen"

        self.clock.adc_src = "clkgen_x4"


If you want to flash the firmware you can do it directly from python

scope = cw.scope()
prog = cw.programmers.XMEGAProgrammer


There is a header with 20 pin at the edge of the board intended to be the interface between the board and the target. This allows to power the board (but only with 3.3 Volts), to provide clock, to interact with the serial and to program it (XMega and AVR protocols).

From the original documentation

Left number number Right
5V (not connected in this model) 1 2 GND
3V3 3 4 HS1/I (clock input)
nRST 5 6 HS2/O (output clock and glitch)
MISO (SPI and AVR programming) 7 8 VREF
MOSI (SPI and AVR programming) 9 10 IO1 (serial RX)
SCK (SPI and AVR programming) 11 12 IO2 (serial TX)
PC (XMega128 programming pin) 13 14 IO3
PD (XMega128 programming pin) 15 16 IO4 (used as a trigger)
GND 17 18 3V3
GND 19 20 5V (not connected in this model)

Firmware updating

It's possible to update the firmware that runs on the ChipWhisperer itself via python: issuing the following

import chipwhisperer as cw
scope = cw.scope()
programmer = cw.SAMFWLoader(scope=scope)
programmer.program('/dev/ttyACM0', hardware_type='cwlite')

you should see a device appearing in the dmesg log.

[1111253.064641] usb 2-10: USB disconnect, device number 27
[1111253.449854] usb 2-10: new high-speed USB device number 28 using xhci_hcd
[1111253.602083] usb 2-10: New USB device found, idVendor=03eb, idProduct=6124, bcdDevice= 1.10
[1111253.602086] usb 2-10: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[1111253.630152] cdc_acm 2-10:1.0: ttyACM0: USB ACM device
[1111253.630322] usbcore: registered new interface driver cdc_acm
[1111253.630324] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters


Comments powered by Disqus