Tutorial A2 Introduction to Glitch Attacks (including Glitch Explorer)
This tutorial has been updated for ChipWhisperer 4.0.0 release. If you are using 3.x.x see the "V3" link in the sidebar.
A2: Introduction to Glitch Attacks (including Glitch Explorer) | |
---|---|
Target Architecture | XMEGA/Arm |
Hardware Crypto | No |
Software Release | V3 / V4 / V5 |
This advanced tutorial will demonstrate clock glitch attacks using the ChipWhisperer system. This will introduce you to many required features of the ChipWhisperer system when it comes to glitching. This will be built on in later tutorials to generate voltage glitching attacks, or when you wish to attack other targets.
If you're working on an STM32F3/CW303 Arm target, it's recommended that you have the latest updates from the develop branch. Recent firmware changes have made glitching far more reliable.
Background on Clock Glitching
Digital hardware devices almost always expect some form of reliable clock. We can manipulate the clock being presented to the device to cause unintended behaviour. We'll be concentrating on microcontrollers here, however other digital devices (e.g. hardware encryption accelerators) can also have faults injected using this technique.
Consider a microcontroller first. The following figure is an excerpt the Atmel AVR ATMega328P datasheet:
Rather than loading each instruction from FLASH and performing the entire execution, the system has a pipeline to speed up the execution process. This means that an instruction is being decoded while the next one is being retrieved, as the following diagram shows:
But if we modify the clock, we could have a situation where the system doesn't have enough time to actually perform an instruction. Consider the following, where Execute #1 is effectively skipped. Before the system has time to actually execute it another clock edge comes, causing the microcontroller to start execution of the next instruction:
This causes the microcontroller to skip an instruction. Such attacks can be immensely powerful in practice. Consider for example the following code from `linux-util-2.24`:
/* * auth.c -- PAM authorization code, common between chsh and chfn * (c) 2012 by Cody Maloney <cmaloney@theoreticalchaos.com> * * this program is free software. you can redistribute it and * modify it under the terms of the gnu general public license. * there is no warranty. * */ #include "auth.h" #include "pamfail.h" int auth_pam(const char *service_name, uid_t uid, const char *username) { if (uid != 0) { pam_handle_t *pamh = NULL; struct pam_conv conv = { misc_conv, NULL }; int retcode; retcode = pam_start(service_name, username, &conv, &pamh); if (pam_fail_check(pamh, retcode)) return FALSE; retcode = pam_authenticate(pamh, 0); if (pam_fail_check(pamh, retcode)) return FALSE; retcode = pam_acct_mgmt(pamh, 0); if (retcode == PAM_NEW_AUTHTOK_REQD) retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); if (pam_fail_check(pamh, retcode)) return FALSE; retcode = pam_setcred(pamh, 0); if (pam_fail_check(pamh, retcode)) return FALSE; pam_end(pamh, 0); /* no need to establish a session; this isn't a * session-oriented activity... */ } return TRUE; }
This is the login code for the Linux OS. Note that if we could skip the check of if (uid != 0)
and simply branch to the end, we could avoid having to enter a password. This is the power of glitch attacks - not that we are breaking encryption, but simply bypassing the entire authentication module!
Glitch Hardware
The ChipWhisperer Glitch system uses the same synchronous methodology as it's Side Channel Analysis (SCA) capture. A system clock (which can come from either the ChipWhisperer or the Device Under Test (DUT)) is used to generate the glitches. These glitches are then inserted back into the clock, although it's possible to use the glitches alone for other purposes (i.e. for voltage glitching, EM glitching).
The generation of glitches is done with two variable phase shift modules, configured as follows:
The enable line is used to determine when glitches are inserted. Glitches can be inserted continuously (useful for development) or triggered by some event. The following figure shows how the glitch can be muxd to output to the Device Under Test (DUT).
Hardware Support
The phase shift blocks use the Digital Clock Manager (DCM) blocks within the FPGA. These blocks have limited support for run-time configuration of parameters such as phase delay and frequency generation, and for maximum performance the configuration must be fixed at design time. The Xilinx-provided run-time adjustment can shift the phase only by about +/- 5nS in 30pS increments (exact values vary with operating conditions).
For most operating conditions this is insufficient - if attacking a target at 7.37MHz the clock cycle would have a period of 136nS. In order to provide a larger adjustment range, an advanced FPGA feature called Partial Reconfiguration (PR) is used. The PR system requires special partial bitstreams which contain modifications to the FPGA bitstream. These are stored as two files inside a "firmware" zip which contains both the FPGA bitstream along with a file called glitchwidth.p
and a file called glitchoffset.p
. If a lone bitstream is being loaded into the FPGA (i.e. not from the zip-file), the partial reconfiguration system is disabled, as loading incorrect partial reconfiguration files could damage the FPGA. This damage is mostly theoretical, more likely the FPGA will fail to function correctly.
If in the course of following this tutorial you find the FPGA appears to stop responding (i.e. certain features no longer work correctly), it could be the partial reconfiguration data is incorrect.
Python GUI Interface
The portion of the GUI of interest to us is primarily located in this section:
If the Partial Reconfiguration system has been disabled (due to missing PR files or files differing from the FPGA bitstream) the two fields marked that say (as % of period) will be disabled. Only the fields labeled (fine adjust) will be available.
Setting up Glitch Example
Firmware Setup
For this example, we'll be using the glitch-simple
firmware.
Building for CWLite with XMEGA Target
You'll need to have installed avr-gcc and avr-libc. You may have already done this by following the installation guide, or if using the ChipWhisperer-VM it comes prepared with avr-gcc already setup. See the Installing_ChipWhisperer guide for details.
Once you have a working compiler (check by typing 'avr-gcc' at the command line - if using Windows you may need to setup a special batch file to provide you with a avr-gcc command prompt).
- We want to use the existing SimpleSerial firmware as a base for our project, but we don't want to edit the existing firmware. Instead, we'll make a new project with a copy of this firmware. Copy the directory of the firmware you want to modify in the
chipwhisperer/hardware/vicitims/firmware
to a new folder. The folder you copy will depend on what tutorial you're doing. Typically, the firmware you want to use is listed above the "Building for ..." drop down menus in this wiki. The name is arbitrary, but for this example, we'll call itsimpleserial-LAB-SPECIFIC-FOLDER
(though depending on what firmware and tutorial you're working off of, you may want to call it something different). You must keep it in the same directory, as it will reference other files within that directory for the build process. - Open a terminal with avr-gcc in the path. If using Windows the sidebar on the Installing_ChipWhisperer page - you can either add WinAVR to your system path, or you can run the 'winavr.bat' file suggested.
Change the terminal to the newly copied directory. For example:
Windows:cd c:\chipwhisperer\hardware\victims\firmware\simpleserial-LAB-SPECIFIC-FOLDER
Linux/macOS:cd chipwhisperer/hardware/victims/firmware/simpleserial-LAB-SPECIFIC-FOLDER
Then, run
make
to build the system. Make sure you specify which platform you're using as your target. For example, for the ChipWhisperer Lite target, runmake PLATFORM=CW303
Which should have the following output:
...Bunch of lines removed... Creating Extended Listing: simpleserial-base.lss avr-objdump -h -S -z simpleserial-base.elf > simpleserial-base.lss Creating Symbol Table: simpleserial-base.sym avr-nm -n simpleserial-base.elf > simpleserial-base.sym Size after: AVR Memory Usage ---------------- Device: atxmega128d3 Program: 1524 bytes (1.1% Full) (.text + .data + .bootloader) Data: 224 bytes (2.7% Full) (.data + .bss + .noinit) Built for platform CW-Lite XMEGA -------- end --------
Ensure that the "Built for platform ___" matches your target device.
==== Building for CWLite with XMEGA Target ==== You'll need to have installed avr-gcc and avr-libc. You may have already done this by following the installation guide, or if using the ChipWhisperer-VM it comes prepared with avr-gcc already setup. See the Installing_ChipWhisperer guide for details.
Once you have a working compiler (check by typing 'avr-gcc' at the command line - if using Windows you may need to setup a special batch file to provide you with a avr-gcc command prompt).
- We want to use the existing SimpleSerial firmware as a base for our project, but we don't want to edit the existing firmware. Instead, we'll make a new project with a copy of this firmware. Copy the directory of the firmware you want to modify in the
chipwhisperer/hardware/vicitims/firmware
to a new folder. The folder you copy will depend on what tutorial you're doing. Typically, the firmware you want to use is listed above the "Building for ..." drop down menus in this wiki. The name is arbitrary, but for this example, we'll call itsimpleserial-LAB-SPECIFIC-FOLDER
(though depending on what firmware and tutorial you're working off of, you may want to call it something different). You must keep it in the same directory, as it will reference other files within that directory for the build process. - Open a terminal with avr-gcc in the path. If using Windows the sidebar on the Installing_ChipWhisperer page - you can either add WinAVR to your system path, or you can run the 'winavr.bat' file suggested.
Change the terminal to the newly copied directory. For example:
Windows:cd c:\chipwhisperer\hardware\victims\firmware\simpleserial-LAB-SPECIFIC-FOLDER
Linux/macOS:cd chipwhisperer/hardware/victims/firmware/simpleserial-LAB-SPECIFIC-FOLDER
Then, run
make
to build the system. Make sure you specify which platform you're using as your target. For example, for the ChipWhisperer Lite target, runmake PLATFORM=CW303
Which should have the following output:
...Bunch of lines removed... Creating Extended Listing: simpleserial-base.lss avr-objdump -h -S -z simpleserial-base.elf > simpleserial-base.lss Creating Symbol Table: simpleserial-base.sym avr-nm -n simpleserial-base.elf > simpleserial-base.sym Size after: AVR Memory Usage ---------------- Device: atxmega128d3 Program: 1524 bytes (1.1% Full) (.text + .data + .bootloader) Data: 224 bytes (2.7% Full) (.data + .bss + .noinit) Built for platform CW-Lite XMEGA -------- end --------
Ensure that the "Built for platform ___" matches your target device.
Building for CWLite with Arm Target
You'll need to have installed the GNU Embedded Toolchain for ARM. If you haven't yet, see the Installing_ChipWhisperer guide, specifically the Installing ARM Toolchain section, for details.
Once you have a working compiler (check by typing 'arm-none-eabi-gcc' at the command line).
- We want to use the existing SimpleSerial firmware as a base for our project, but we don't want to edit the existing firmware. Instead, we'll make a new project with a copy of this firmware. Copy the directory of the firmware you want to modify in the
chipwhisperer/hardware/vicitims/firmware
to a new folder. The folder you copy will depend on what tutorial you're doing. Typically, the firmware you want to use is listed above the "Building for ..." drop down menus in this tutorial. The name is arbitrary, but for this example, we'll call itsimpleserial-LAB-SPECIFIC-FOLDER
(though depending on what firmware and tutorial you're working off of, you may want to call it something different). You must keep it in the same directory, as it will reference other files within that directory for the build process. - Open a terminal with arm-none-eabi-gcc in the path. If using Windows the sidebar on the Installing_ChipWhisperer page
Change the terminal to the newly copied directory. For example:
Windows:cd c:\chipwhisperer\hardware\victims\firmware\simpleserial-LAB-SPECIFIC-FOLDER
Linux/macOS:cd chipwhisperer/hardware/victims/firmware/simpleserial-LAB-SPECIFIC-FOLDER
Then, run
make
to build the system. Make sure you specify which platform you're using as your target. For example, for the ChipWhisperer Lite target, runmake PLATFORM=CWLITEARM CRYPTO_TARGET=TINYAES128C
Which should have the following output:
...Bunch of lines removed... Linking: simpleserial-base-CWLITEARM.elf arm-none-eabi-gcc -mcpu=cortex-m4 -I. -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections -gdwarf-2 -DSS_VER=SS_VER_1_1 -DSTM32F303xC -DSTM32F3 -DSTM32 -DDEBUG -DHAL_TYPE=HAL_stm32f3 -DPLATFORM=CWLITEARM -DTINYAES128C -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-base.o -I.././simpleserial/ -I.././hal -I.././hal/stm32f3 -I.././hal/stm32f3/CMSIS -I.././hal/stm32f3/CMSIS/core -I.././hal/stm32f3/CMSIS/device -I.././hal/stm32f4/Legacy -I.././crypto/ -I.././crypto/tiny-AES128-C -std=gnu99 -MMD -MP -MF .dep/simpleserial-base-CWLITEARM.elf.d objdir/simpleserial-base.o objdir/simpleserial.o objdir/stm32f3_hal.o objdir/stm32f3_hal_lowlevel.o objdir/stm32f3_sysmem.o objdir/aes.o objdir/aes-independant.o objdir/stm32f3_startup.o --output simpleserial-base-CWLITEARM.elf --specs=nano.specs -T .././hal/stm32f3/LinkerScript.ld -Wl,--gc-sections -lm -Wl,-Map=simpleserial-base-CWLITEARM.map,--cref -lm . Creating load file for Flash: simpleserial-base-CWLITEARM.hex arm-none-eabi-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature simpleserial-base-CWLITEARM.elf simpleserial-base-CWLITEARM.hex . Creating load file for EEPROM: simpleserial-base-CWLITEARM.eep arm-none-eabi-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-base-CWLITEARM.elf simpleserial-base-CWLITEARM.eep || exit 0 . Creating Extended Listing: simpleserial-base-CWLITEARM.lss arm-none-eabi-objdump -h -S -z simpleserial-base-CWLITEARM.elf > simpleserial-base-CWLITEARM.lss . Creating Symbol Table: simpleserial-base-CWLITEARM.sym arm-none-eabi-nm -n simpleserial-base-CWLITEARM.elf > simpleserial-base-CWLITEARM.sym Size after: text data bss dec hex filename 4588 8 1296 5892 1704 simpleserial-base-CWLITEARM.elf +-------------------------------------------------------- + Built for platform CW-Lite Arm (STM32F3) +--------------------------------------------------------
Ensure that the "Built for platform ___" matches your target device.
==== Building for CWLite with Arm Target ==== You'll need to have installed the GNU Embedded Toolchain for ARM. If you haven't yet, see the Installing_ChipWhisperer guide, specifically the Installing ARM Toolchain section, for details.
Once you have a working compiler (check by typing 'arm-none-eabi-gcc' at the command line).
- We want to use the existing SimpleSerial firmware as a base for our project, but we don't want to edit the existing firmware. Instead, we'll make a new project with a copy of this firmware. Copy the directory of the firmware you want to modify in the
chipwhisperer/hardware/vicitims/firmware
to a new folder. The folder you copy will depend on what tutorial you're doing. Typically, the firmware you want to use is listed above the "Building for ..." drop down menus in this tutorial. The name is arbitrary, but for this example, we'll call itsimpleserial-LAB-SPECIFIC-FOLDER
(though depending on what firmware and tutorial you're working off of, you may want to call it something different). You must keep it in the same directory, as it will reference other files within that directory for the build process. - Open a terminal with arm-none-eabi-gcc in the path. If using Windows the sidebar on the Installing_ChipWhisperer page
Change the terminal to the newly copied directory. For example:
Windows:cd c:\chipwhisperer\hardware\victims\firmware\simpleserial-LAB-SPECIFIC-FOLDER
Linux/macOS:cd chipwhisperer/hardware/victims/firmware/simpleserial-LAB-SPECIFIC-FOLDER
Then, run
make
to build the system. Make sure you specify which platform you're using as your target. For example, for the ChipWhisperer Lite target, runmake PLATFORM=CWLITEARM CRYPTO_TARGET=TINYAES128C
Which should have the following output:
...Bunch of lines removed... Linking: simpleserial-base-CWLITEARM.elf arm-none-eabi-gcc -mcpu=cortex-m4 -I. -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fmessage-length=0 -ffunction-sections -gdwarf-2 -DSS_VER=SS_VER_1_1 -DSTM32F303xC -DSTM32F3 -DSTM32 -DDEBUG -DHAL_TYPE=HAL_stm32f3 -DPLATFORM=CWLITEARM -DTINYAES128C -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-base.o -I.././simpleserial/ -I.././hal -I.././hal/stm32f3 -I.././hal/stm32f3/CMSIS -I.././hal/stm32f3/CMSIS/core -I.././hal/stm32f3/CMSIS/device -I.././hal/stm32f4/Legacy -I.././crypto/ -I.././crypto/tiny-AES128-C -std=gnu99 -MMD -MP -MF .dep/simpleserial-base-CWLITEARM.elf.d objdir/simpleserial-base.o objdir/simpleserial.o objdir/stm32f3_hal.o objdir/stm32f3_hal_lowlevel.o objdir/stm32f3_sysmem.o objdir/aes.o objdir/aes-independant.o objdir/stm32f3_startup.o --output simpleserial-base-CWLITEARM.elf --specs=nano.specs -T .././hal/stm32f3/LinkerScript.ld -Wl,--gc-sections -lm -Wl,-Map=simpleserial-base-CWLITEARM.map,--cref -lm . Creating load file for Flash: simpleserial-base-CWLITEARM.hex arm-none-eabi-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature simpleserial-base-CWLITEARM.elf simpleserial-base-CWLITEARM.hex . Creating load file for EEPROM: simpleserial-base-CWLITEARM.eep arm-none-eabi-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-base-CWLITEARM.elf simpleserial-base-CWLITEARM.eep || exit 0 . Creating Extended Listing: simpleserial-base-CWLITEARM.lss arm-none-eabi-objdump -h -S -z simpleserial-base-CWLITEARM.elf > simpleserial-base-CWLITEARM.lss . Creating Symbol Table: simpleserial-base-CWLITEARM.sym arm-none-eabi-nm -n simpleserial-base-CWLITEARM.elf > simpleserial-base-CWLITEARM.sym Size after: text data bss dec hex filename 4588 8 1296 5892 1704 simpleserial-base-CWLITEARM.elf +-------------------------------------------------------- + Built for platform CW-Lite Arm (STM32F3) +--------------------------------------------------------
Ensure that the "Built for platform ___" matches your target device.
Building for Other Targets
Building for other targets typically requires additional programs and tools. Additionally, some targets may have a unique build process, meaning the instructions here will not apply to them. Please see the page for the specific target you want to build for before following these instructions, which can be found under the Hardware Documentation section of the Main Page.
Once you have a working compiler:
- We want to use the existing SimpleSerial firmware as a base for our project, but we don't want to edit the existing firmware. Instead, we'll make a new project with a copy of this firmware. Copy the directory of the firmware you want to modify in the
chipwhisperer/hardware/vicitims/firmware
to a new folder. The folder you copy will depend on what tutorial you're doing. Typically, the firmware you want to use is listed above the "Building for ..." drop down menus. The name is arbitrary, but for this example, we'll call itsimpleserial-base-lab1
(though depending on what firmware and tutorial you're working off of, you may want to call it something different). You must keep it in the same directory, as it will reference other files within that directory for the build process. Change the terminal to the newly copied directory. For example:
Windows:cd c:\chipwhisperer\hardware\victims\firmware\simpleserial-base-lab1
Linux/macOS:cd chipwhisperer/hardware/victims/firmware/simpleserial-base-lab1
Then, run
make
to build the system. Make sure you specify which platform you're using as your target. You can see a list of supported targets by typingmake PLATFORM=
. You'll also need to specify aCRYPTO_TARGET
. Most targets and tutorials work withTINYAES128C
, so if you're unsure, this is usually a reliable option. For example, for the NXP Kinetis K24F target, run:make PLATFORM=CW308_K24F CRYPTO_TARGET=TINYAES128C
Which should have the following output:
...Bunch of lines removed... Linking: simpleserial-base-CW308_K24F.elf arm-none-eabi-gcc -I. -O0 -g -DDEBUG -DCPU_MK24FN1M0VLL12 -DFRDM_K64F -DFREEDOM -w -fno-common -ffunction-sections -fdata-sections -ffreestanding -fno-builtin -mthumb -mapcs -std=gnu99 -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MMD -MP -static -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_k24f -DPLATFORM=CW308_K24F -DTINYAES128C -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-base.o -I.././simpleserial/ -I.././hal -I.././hal/k24f -I.././hal/k24f/CMSIS -I.././hal/k24f/Drivers -I.././crypto/ -I.././crypto/tiny-AES128-C -std=gnu99 -MMD -MP -MF .dep/simpleserial-base-CW308_K24F.elf.d objdir/simpleserial-base.o objdir/simpleserial.o objdir/clock_config.o objdir/fsl_adc16.o objdir/fsl_clock.o objdir/fsl_cmp.o objdir/fsl_cmt.o objdir/fsl_common.o objdir/fsl_crc.o objdir/fsl_dac.o objdir/fsl_dmamux.o objdir/fsl_dspi.o objdir/fsl_dspi_edma.o objdir/fsl_edma.o objdir/fsl_ewm.o objdir/fsl_flash.o objdir/fsl_flexbus.o objdir/fsl_flexcan.o objdir/fsl_ftm.o objdir/fsl_gpio.o objdir/fsl_i2c.o objdir/fsl_i2c_edma.o objdir/fsl_llwu.o objdir/fsl_lptmr.o objdir/fsl_mmcau.o objdir/fsl_pdb.o objdir/fsl_pit.o objdir/fsl_pmc.o objdir/fsl_rcm.o objdir/fsl_rnga.o objdir/fsl_rtc.o objdir/fsl_sai.o objdir/fsl_sai_edma.o objdir/fsl_sdhc.o objdir/fsl_sim.o objdir/fsl_smc.o objdir/fsl_sysmpu.o objdir/fsl_uart.o objdir/fsl_uart_edma.o objdir/fsl_vref.o objdir/fsl_wdog.o objdir/k24f_hal.o objdir/system_MK24F12.o objdir/aes.o objdir/aes-independant.o objdir/startup_MK24F12.o --output simpleserial-base-CW308_K24F.elf -Xlinker --gc-sections -Xlinker -static -Xlinker -z -Xlinker muldefs -T .././hal/k24f/MK24FN1M0xxx12_flash.ld --specs=nano.specs --specs=nosys.specs -Wl,--start-group -L .././hal/k24f/ -l:lib_mmcau.a -lm -lc -lgcc -lnosys -Wl,--end-group -Wl,-Map=simpleserial-base-CW308_K24F.map,--cref -lm . Creating load file for Flash: simpleserial-base-CW308_K24F.hex arm-none-eabi-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature simpleserial-base-CW308_K24F.elf simpleserial-base-CW308_K24F.hex . Creating load file for EEPROM: simpleserial-base-CW308_K24F.eep arm-none-eabi-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-base-CW308_K24F.elf simpleserial-base-CW308_K24F.eep || exit 0 . Creating Extended Listing: simpleserial-base-CW308_K24F.lss arm-none-eabi-objdump -h -S -z simpleserial-base-CW308_K24F.elf > simpleserial-base-CW308_K24F.lss . Creating Symbol Table: simpleserial-base-CW308_K24F.sym arm-none-eabi-nm -n simpleserial-base-CW308_K24F.elf > simpleserial-base-CW308_K24F.sym Size after: text data bss dec hex filename 11600 120 2388 14108 371c simpleserial-base-CW308_K24F.elf +-------------------------------------------------------- + Built for platform k24f Target +--------------------------------------------------------
Ensure that the "Built for platform ___" matches your target device.
==== Building for Other Targets ==== Building for other targets typically requires additional programs and tools. Additionally, some targets may have a unique build process, meaning the instructions here will not apply to them. Please see the page for the specific target you want to build for before following these instructions, which can be found under the Hardware Documentation section of the Main Page.
Once you have a working compiler:
- We want to use the existing SimpleSerial firmware as a base for our project, but we don't want to edit the existing firmware. Instead, we'll make a new project with a copy of this firmware. Copy the directory of the firmware you want to modify in the
chipwhisperer/hardware/vicitims/firmware
to a new folder. The folder you copy will depend on what tutorial you're doing. Typically, the firmware you want to use is listed above the "Building for ..." drop down menus. The name is arbitrary, but for this example, we'll call itsimpleserial-base-lab1
(though depending on what firmware and tutorial you're working off of, you may want to call it something different). You must keep it in the same directory, as it will reference other files within that directory for the build process. Change the terminal to the newly copied directory. For example:
Windows:cd c:\chipwhisperer\hardware\victims\firmware\simpleserial-base-lab1
Linux/macOS:cd chipwhisperer/hardware/victims/firmware/simpleserial-base-lab1
Then, run
make
to build the system. Make sure you specify which platform you're using as your target. You can see a list of supported targets by typingmake PLATFORM=
. You'll also need to specify aCRYPTO_TARGET
. Most targets and tutorials work withTINYAES128C
, so if you're unsure, this is usually a reliable option. For example, for the NXP Kinetis K24F target, run:make PLATFORM=CW308_K24F CRYPTO_TARGET=TINYAES128C
Which should have the following output:
...Bunch of lines removed... Linking: simpleserial-base-CW308_K24F.elf arm-none-eabi-gcc -I. -O0 -g -DDEBUG -DCPU_MK24FN1M0VLL12 -DFRDM_K64F -DFREEDOM -w -fno-common -ffunction-sections -fdata-sections -ffreestanding -fno-builtin -mthumb -mapcs -std=gnu99 -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -MMD -MP -static -gdwarf-2 -DSS_VER=SS_VER_1_1 -DHAL_TYPE=HAL_k24f -DPLATFORM=CW308_K24F -DTINYAES128C -DF_CPU=7372800UL -Os -funsigned-char -funsigned-bitfields -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=objdir/simpleserial-base.o -I.././simpleserial/ -I.././hal -I.././hal/k24f -I.././hal/k24f/CMSIS -I.././hal/k24f/Drivers -I.././crypto/ -I.././crypto/tiny-AES128-C -std=gnu99 -MMD -MP -MF .dep/simpleserial-base-CW308_K24F.elf.d objdir/simpleserial-base.o objdir/simpleserial.o objdir/clock_config.o objdir/fsl_adc16.o objdir/fsl_clock.o objdir/fsl_cmp.o objdir/fsl_cmt.o objdir/fsl_common.o objdir/fsl_crc.o objdir/fsl_dac.o objdir/fsl_dmamux.o objdir/fsl_dspi.o objdir/fsl_dspi_edma.o objdir/fsl_edma.o objdir/fsl_ewm.o objdir/fsl_flash.o objdir/fsl_flexbus.o objdir/fsl_flexcan.o objdir/fsl_ftm.o objdir/fsl_gpio.o objdir/fsl_i2c.o objdir/fsl_i2c_edma.o objdir/fsl_llwu.o objdir/fsl_lptmr.o objdir/fsl_mmcau.o objdir/fsl_pdb.o objdir/fsl_pit.o objdir/fsl_pmc.o objdir/fsl_rcm.o objdir/fsl_rnga.o objdir/fsl_rtc.o objdir/fsl_sai.o objdir/fsl_sai_edma.o objdir/fsl_sdhc.o objdir/fsl_sim.o objdir/fsl_smc.o objdir/fsl_sysmpu.o objdir/fsl_uart.o objdir/fsl_uart_edma.o objdir/fsl_vref.o objdir/fsl_wdog.o objdir/k24f_hal.o objdir/system_MK24F12.o objdir/aes.o objdir/aes-independant.o objdir/startup_MK24F12.o --output simpleserial-base-CW308_K24F.elf -Xlinker --gc-sections -Xlinker -static -Xlinker -z -Xlinker muldefs -T .././hal/k24f/MK24FN1M0xxx12_flash.ld --specs=nano.specs --specs=nosys.specs -Wl,--start-group -L .././hal/k24f/ -l:lib_mmcau.a -lm -lc -lgcc -lnosys -Wl,--end-group -Wl,-Map=simpleserial-base-CW308_K24F.map,--cref -lm . Creating load file for Flash: simpleserial-base-CW308_K24F.hex arm-none-eabi-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature simpleserial-base-CW308_K24F.elf simpleserial-base-CW308_K24F.hex . Creating load file for EEPROM: simpleserial-base-CW308_K24F.eep arm-none-eabi-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ --change-section-lma .eeprom=0 --no-change-warnings -O ihex simpleserial-base-CW308_K24F.elf simpleserial-base-CW308_K24F.eep || exit 0 . Creating Extended Listing: simpleserial-base-CW308_K24F.lss arm-none-eabi-objdump -h -S -z simpleserial-base-CW308_K24F.elf > simpleserial-base-CW308_K24F.lss . Creating Symbol Table: simpleserial-base-CW308_K24F.sym arm-none-eabi-nm -n simpleserial-base-CW308_K24F.elf > simpleserial-base-CW308_K24F.sym Size after: text data bss dec hex filename 11600 120 2388 14108 371c simpleserial-base-CW308_K24F.elf +-------------------------------------------------------- + Built for platform k24f Target +--------------------------------------------------------
Ensure that the "Built for platform ___" matches your target device.
You should also open the file glitchsimple.c
which is the source code. The subroutine being glitched in this example looks like this:
void glitch_infinite(void) { char str[64]; //Declared volatile to avoid optimizing away loop. //This also adds lots of SRAM access volatile uint16_t i, j; volatile uint32_t cnt; while(1){ cnt = 0; for(i=0; i<500; i++){ for(j=0; j<500; j++){ cnt++; } } sprintf(str, "%lu %d %d\n", cnt, i, j); uart_puts(str); } }
You should confirm that glitch_infinite()
is actually called from the main subroutine. There are several glitch examples and it's possible the wrong subroutine has been setup previously:
int main(void){ platform_init(); init_uart(); trigger_setup(); /* Uncomment this to get a HELLO message for debug */ putch('h'); putch('e'); putch('l'); putch('l'); putch('o'); putch('\n'); _delay_ms(20); while(1){ glitch_infinite(); } return 1; }
Hardware Setup
CW1173 (Lite) Hardware Setup
This tutorial uses the CW1173_ChipWhisperer-Lite hardware. No hardware setup is required normally, simply plug in the USB cable:
Note that under no circumstances as part of the setup should you use the CW1173 device to hold up furniture:
==== CW1173 (Lite) Hardware Setup ==== This tutorial uses the CW1173_ChipWhisperer-Lite hardware. No hardware setup is required normally, simply plug in the USB cable:
Note that under no circumstances as part of the setup should you use the CW1173 device to hold up furniture:
CW1200 (Pro) Hardware Setup
This tutorial uses the CW1200_ChipWhisperer-Pro hardware.
- Remove the ChipWhisperer-Pro main capture hardware, UFO Board, and SMA cable from the ChipWhisperer-Pro case.
- Attached the UFO board to the ChipWhisperer-Pro with the 20-pin cable, and connect the VOUT SMA connector to the MEASURE input.
- Power up the ChipWhisperer-Pro with the 5V DC power adapter, and connect the USB cable to the computer.
- If this the first time powering up, you will need to install the drivers (see CW1200_ChipWhisperer-Pro).
Note if you have modified the UFO board the jumpers may no longer be at default locations. The jumper settings required are:
- XMEGA Target board mounted
- J3 routes HS2/OUT to CLKIN
- J1 set to "J5-VREF" (right two pins shorted)
- J14 set to "FILT" (left two pins shorted)
- "3.3V SRC" switch set to "J1/CW"
==== CW1200 (Pro) Hardware Setup ==== This tutorial uses the CW1200_ChipWhisperer-Pro hardware.
- Remove the ChipWhisperer-Pro main capture hardware, UFO Board, and SMA cable from the ChipWhisperer-Pro case.
- Attached the UFO board to the ChipWhisperer-Pro with the 20-pin cable, and connect the VOUT SMA connector to the MEASURE input.
- Power up the ChipWhisperer-Pro with the 5V DC power adapter, and connect the USB cable to the computer.
- If this the first time powering up, you will need to install the drivers (see CW1200_ChipWhisperer-Pro).
Note if you have modified the UFO board the jumpers may no longer be at default locations. The jumper settings required are:
- XMEGA Target board mounted
- J3 routes HS2/OUT to CLKIN
- J1 set to "J5-VREF" (right two pins shorted)
- J14 set to "FILT" (left two pins shorted)
- "3.3V SRC" switch set to "J1/CW"
CW308 (UFO) Hardware Setup
Coming soon!
==== CW308 (UFO) Hardware Setup ==== Coming soon!
Programming the Target
Programming the XMEGA Target
It is assumed that you've already followed the guide in Installing_ChipWhisperer. Thus it is assumed you are able to communicate with the ChipWhisperer CW1173 hardware (or whatever capture hardware you are using). Note in particular you must have configured the FPGA bitstream in the ChipWhisperer-Capture software, all part of the description in the Installing_ChipWhisperer guide.
Assuming this setup is complete, you can confirm you are able to communicate with the hardware by running the example capture of traces given in the CW1173_ChipWhisperer-Lite quick-start.
Programming the Example
Note with the XMEGA target, you need to configure a clock before programming of the device will succeed. Programming of the target device will be done as part of the CW-Capture software setup, discussed next.
Communicating from CW-Capture Software
Next, open the CW-Capture software. Then perform the following steps:
- Switch to the Python Console tab.
- The script selection window (2) lists available example scripts. Scroll down to "connect_cwlite_simpleserial.py" and click on it.
- You will see the script contents appear in the "Script Preview" window (3). You can either hit the "Run" button or double-click the filename of the script to execute it. Do either of those now.
The window should change to indicate the connect succeeded:
- The console lists the exact script that is executed. Note you could have manually executed the script commands line-by-line in this console.
- The "Scope" and "Target" buttons will show as connected.
- The Status Bar will show a connection.
Note in previous software versions, this tutorial took you through manual setup. This can still be done (using the GUI), but instead now the API has been made more powerful, so the example configuration script will be used instead.
To do so, simply scroll down and select the "setup_cwlite_xmega_aes.py" file:
You'll notice the contents of the script contain the following setup: 1 scope.gain.gain = 45
2 scope.adc.samples = 3000
3 scope.adc.offset = 1250
4 scope.adc.basic_mode = "rising_edge"
5 scope.clock.clkgen_freq = 7370000
6 scope.clock.adc_src = "clkgen_x4"
7 scope.trigger.triggers = "tio4"
8 scope.io.tio1 = "serial_rx"
9 scope.io.tio2 = "serial_tx"
10 scope.io.hs2 = "clkgen"
Line 1: Sets the input ADC gain
Line 2: Sets the number of samples to record as 3000 samples long (this is normally used for the AES algorithm).
Line 3: Sets an offset of 1250 samples from the trigger to when we start recording samples.
Line 4: Sets the trigger as being a "rising edge" trigger.
Line 5: Sets the internal clock generator to 7.37MHz
Line 6: Sets the ADC as running at 4x that clock (so 29.48MHz)
Line 7: Sets the trigger pin as GPIO4 (we previously set the trigger condition as rising edge, so this pin will be the one a rising edge is expected on).
Line 8: Configures GPIO1 as the RX (Input). This is what the XMEGA target expects.
Line 9: Configures GPIO2 as the TX (Output). This is what the XMEGA target expects.
Line 10: Sets the "High-Speed 2" (HS2) pin as having the 7.37MHz clock output.
You can now program the XMEGA device! To do so, open the XMEGA Programmer from the Tools menu:
Hit the Check Signature button and confirm the device is detected. If not you may have issues with the clock setup.
Using the Find button, navigate to the
simpleserial-base-cw303.hex
(or whatever your hex file is called), which you built earlier with themake
command. You can then press the Erase/Program/Verify button, and confirm the file is programmed into the XMEGA device:Note the programmer dialog not only shows the successful programming status, but also shows when the
.hex
file was last modified. Always confirm this matches with when you last remember compiling the program -- if it is widely different this suggests you have selected the wrong file!
- You can now close the programming dialog if you'd like. If you're frequently reprogramming the target, you may want to leave this open.
=== Programming the XMEGA Target === It is assumed that you've already followed the guide in Installing_ChipWhisperer. Thus it is assumed you are able to communicate with the ChipWhisperer CW1173 hardware (or whatever capture hardware you are using). Note in particular you must have configured the FPGA bitstream in the ChipWhisperer-Capture software, all part of the description in the Installing_ChipWhisperer guide.
Assuming this setup is complete, you can confirm you are able to communicate with the hardware by running the example capture of traces given in the CW1173_ChipWhisperer-Lite quick-start.
Programming the Example
Note with the XMEGA target, you need to configure a clock before programming of the device will succeed. Programming of the target device will be done as part of the CW-Capture software setup, discussed next.
Communicating from CW-Capture Software
Next, open the CW-Capture software. Then perform the following steps:
- Switch to the Python Console tab.
- The script selection window (2) lists available example scripts. Scroll down to "connect_cwlite_simpleserial.py" and click on it.
- You will see the script contents appear in the "Script Preview" window (3). You can either hit the "Run" button or double-click the filename of the script to execute it. Do either of those now.
The window should change to indicate the connect succeeded:
- The console lists the exact script that is executed. Note you could have manually executed the script commands line-by-line in this console.
- The "Scope" and "Target" buttons will show as connected.
- The Status Bar will show a connection.
Note in previous software versions, this tutorial took you through manual setup. This can still be done (using the GUI), but instead now the API has been made more powerful, so the example configuration script will be used instead.
To do so, simply scroll down and select the "setup_cwlite_xmega_aes.py" file:
You'll notice the contents of the script contain the following setup: 1 scope.gain.gain = 45
2 scope.adc.samples = 3000
3 scope.adc.offset = 1250
4 scope.adc.basic_mode = "rising_edge"
5 scope.clock.clkgen_freq = 7370000
6 scope.clock.adc_src = "clkgen_x4"
7 scope.trigger.triggers = "tio4"
8 scope.io.tio1 = "serial_rx"
9 scope.io.tio2 = "serial_tx"
10 scope.io.hs2 = "clkgen"
Line 1: Sets the input ADC gain
Line 2: Sets the number of samples to record as 3000 samples long (this is normally used for the AES algorithm).
Line 3: Sets an offset of 1250 samples from the trigger to when we start recording samples.
Line 4: Sets the trigger as being a "rising edge" trigger.
Line 5: Sets the internal clock generator to 7.37MHz
Line 6: Sets the ADC as running at 4x that clock (so 29.48MHz)
Line 7: Sets the trigger pin as GPIO4 (we previously set the trigger condition as rising edge, so this pin will be the one a rising edge is expected on).
Line 8: Configures GPIO1 as the RX (Input). This is what the XMEGA target expects.
Line 9: Configures GPIO2 as the TX (Output). This is what the XMEGA target expects.
Line 10: Sets the "High-Speed 2" (HS2) pin as having the 7.37MHz clock output.
You can now program the XMEGA device! To do so, open the XMEGA Programmer from the Tools menu:
Hit the Check Signature button and confirm the device is detected. If not you may have issues with the clock setup.
Using the Find button, navigate to the
simpleserial-base-cw303.hex
(or whatever your hex file is called), which you built earlier with themake
command. You can then press the Erase/Program/Verify button, and confirm the file is programmed into the XMEGA device:Note the programmer dialog not only shows the successful programming status, but also shows when the
.hex
file was last modified. Always confirm this matches with when you last remember compiling the program -- if it is widely different this suggests you have selected the wrong file!
- You can now close the programming dialog if you'd like. If you're frequently reprogramming the target, you may want to leave this open.
Programming the Arm Target
It is assumed that you've already followed the guide in Installing_ChipWhisperer. Thus it is assumed you are able to communicate with the ChipWhisperer CW1173 hardware (or whatever capture hardware you are using). Note in particular you must have configured the FPGA bitstream in the ChipWhisperer-Capture software, all part of the description in the Installing_ChipWhisperer guide.
Assuming this setup is complete, you can confirm you are able to communicate with the hardware by running the example capture of traces given in the CW1173_ChipWhisperer-Lite quick-start.
Programming the Example
Note with the CW303 Arm target, you need to configure a clock before programming of the device will succeed. Programming of the target device will be done as part of the CW-Capture software setup, discussed next.
Communicating from CW-Capture Software
Next, open the CW-Capture software. Then perform the following steps:
- Switch to the Python Console tab.
- The script selection window (2) lists available example scripts. Scroll down to "connect_cwlite_simpleserial.py" and click on it.
- You will see the script contents appear in the "Script Preview" window (3). You can either hit the "Run" button or double-click the filename of the script to execute it. Do either of those now.
The window should change to indicate the connect succeeded:
- The console lists the exact script that is executed. Note you could have manually executed the script commands line-by-line in this console.
- The "Scope" and "Target" buttons will show as connected.
- The Status Bar will show a connection.
Note in previous software versions, this tutorial took you through manual setup. This can still be done (using the GUI), but instead now the API has been made more powerful, so the example configuration script will be used instead.
To do so, simply scroll down and select the "setup_cwlite_stm32f_aes.py" file:
You'll notice the contents of the script contain the following setup: 1 scope.gain.gain = 45
2 scope.adc.samples = 5000
3 scope.adc.offset = 0
4 scope.adc.basic_mode = "rising_edge"
5 scope.clock.clkgen_freq = 7370000
6 scope.clock.adc_src = "clkgen_x4"
7 scope.trigger.triggers = "tio4"
8 scope.io.tio1 = "serial_rx"
9 scope.io.tio2 = "serial_tx"
10 scope.io.hs2 = "clkgen"
11
12 target.baud=38400
Line 1: Sets the input ADC gain
Line 2: Sets the number of samples to record as 5000 samples long (this is normally used for the AES algorithm).
Line 3: Sets an offset of 0 samples from the trigger to when we start recording samples.
Line 4: Sets the trigger as being a "rising edge" trigger.
Line 5: Sets the internal clock generator to 7.37MHz
Line 6: Sets the ADC as running at 4x that clock (so 29.48MHz)
Line 7: Sets the trigger pin as GPIO4 (we previously set the trigger condition as rising edge, so this pin will be the one a rising edge is expected on).
Line 8: Configures GPIO1 as the RX (Input). This is what the ARM target expects.
Line 9: Configures GPIO2 as the TX (Output). This is what the ARM target expects.
Line 10: Sets the "High-Speed 2" (HS2) pin as having the 7.37MHz clock output.
Line 12: Sets the serial communication speed with the target at 38400 baud.You can now program the ARM device! To do so, open the STM32F Programmer from the Tools menu:
Hit the Check Signature button and confirm the device is detected. If not you may have issues with the clock setup.
Using the Find button, navigate to the
simpleserial-base-CWLITEARM.hex
(or whatever your binary is called), which you built earlier with themake
command. You can then press the Erase/Program/Verify button, and confirm the file is programmed into the XMEGA device:If the software freezes and the verification fails after a long period of time, set the Read Block Size to 64 instead of 256.
Note the programmer dialog not only shows the successful programming status, but also shows when the
.hex
file was last modified. Always confirm this matches with when you last remember compiling the program -- if it is widely different this suggests you have selected the wrong file!If you'd like, you can close the STM32F programmer dialog. If you frequently reprogram the target, you may want to leave it open.
=== Programming the Arm Target === It is assumed that you've already followed the guide in Installing_ChipWhisperer. Thus it is assumed you are able to communicate with the ChipWhisperer CW1173 hardware (or whatever capture hardware you are using). Note in particular you must have configured the FPGA bitstream in the ChipWhisperer-Capture software, all part of the description in the Installing_ChipWhisperer guide.
Assuming this setup is complete, you can confirm you are able to communicate with the hardware by running the example capture of traces given in the CW1173_ChipWhisperer-Lite quick-start.
Programming the Example
Note with the CW303 Arm target, you need to configure a clock before programming of the device will succeed. Programming of the target device will be done as part of the CW-Capture software setup, discussed next.
Communicating from CW-Capture Software
Next, open the CW-Capture software. Then perform the following steps:
- Switch to the Python Console tab.
- The script selection window (2) lists available example scripts. Scroll down to "connect_cwlite_simpleserial.py" and click on it.
- You will see the script contents appear in the "Script Preview" window (3). You can either hit the "Run" button or double-click the filename of the script to execute it. Do either of those now.
The window should change to indicate the connect succeeded:
- The console lists the exact script that is executed. Note you could have manually executed the script commands line-by-line in this console.
- The "Scope" and "Target" buttons will show as connected.
- The Status Bar will show a connection.
Note in previous software versions, this tutorial took you through manual setup. This can still be done (using the GUI), but instead now the API has been made more powerful, so the example configuration script will be used instead.
To do so, simply scroll down and select the "setup_cwlite_stm32f_aes.py" file:
You'll notice the contents of the script contain the following setup: 1 scope.gain.gain = 45
2 scope.adc.samples = 5000
3 scope.adc.offset = 0
4 scope.adc.basic_mode = "rising_edge"
5 scope.clock.clkgen_freq = 7370000
6 scope.clock.adc_src = "clkgen_x4"
7 scope.trigger.triggers = "tio4"
8 scope.io.tio1 = "serial_rx"
9 scope.io.tio2 = "serial_tx"
10 scope.io.hs2 = "clkgen"
11
12 target.baud=38400
Line 1: Sets the input ADC gain
Line 2: Sets the number of samples to record as 5000 samples long (this is normally used for the AES algorithm).
Line 3: Sets an offset of 0 samples from the trigger to when we start recording samples.
Line 4: Sets the trigger as being a "rising edge" trigger.
Line 5: Sets the internal clock generator to 7.37MHz
Line 6: Sets the ADC as running at 4x that clock (so 29.48MHz)
Line 7: Sets the trigger pin as GPIO4 (we previously set the trigger condition as rising edge, so this pin will be the one a rising edge is expected on).
Line 8: Configures GPIO1 as the RX (Input). This is what the ARM target expects.
Line 9: Configures GPIO2 as the TX (Output). This is what the ARM target expects.
Line 10: Sets the "High-Speed 2" (HS2) pin as having the 7.37MHz clock output.
Line 12: Sets the serial communication speed with the target at 38400 baud.You can now program the ARM device! To do so, open the STM32F Programmer from the Tools menu:
Hit the Check Signature button and confirm the device is detected. If not you may have issues with the clock setup.
Using the Find button, navigate to the
simpleserial-base-CWLITEARM.hex
(or whatever your binary is called), which you built earlier with themake
command. You can then press the Erase/Program/Verify button, and confirm the file is programmed into the XMEGA device:If the software freezes and the verification fails after a long period of time, set the Read Block Size to 64 instead of 256.
Note the programmer dialog not only shows the successful programming status, but also shows when the
.hex
file was last modified. Always confirm this matches with when you last remember compiling the program -- if it is widely different this suggests you have selected the wrong file!If you'd like, you can close the STM32F programmer dialog. If you frequently reprogram the target, you may want to leave it open.
Programming Other Targets
Programming other targets typically requires additional tools, such as a target specific programmer or debugger. Please see the wiki page for your target for additional details. Additionally, you should run connect_simpleserial.py and the associated setup_*.py script before moving on to the rest of the tutorial.
=== Programming Other Targets === Programming other targets typically requires additional tools, such as a target specific programmer or debugger. Please see the wiki page for your target for additional details. Additionally, you should run connect_simpleserial.py and the associated setup_*.py script before moving on to the rest of the tutorial.
Software Setup
Assuming you still have ChipWhisperer setup as described in the programming step (aka have run connect_simpleserial.py and the setup script for your target), there's only a few modifications we need to make to be able to glitch:Under Scope Settings, change CW Extra Settings>Target HS IO-Out to Glitch Module and Glitch Module>Clock Source to CLKGEN. This routes the clock source for the microcontroller through the glitch module.
From the Tools menu, select Open Terminal, and press Connect on the terminal. This will allow us to see what's being sent to and from the microcontroller:
Reset the device. You can do this by going to Scope Settings and switching CW Extra Settings>Target IOn GPIO Mode> nRST: GPIO (or PDIC: GPIO, for the XMEGA target) to Low, then back to Default. If you're using a target that can be programmed from ChipWhisperer, running Check Signature from the programming window will also reset the device.
You should see text populate the terminal:
We'll now look at glitching this routine. You should inspect the source code to determine that a simple series of calculations are performed:
void glitch_infinite(void) { char str[64]; //Declared volatile to avoid optimizing away loop. //This also adds lots of SRAM access volatile uint16_t i, j; volatile uint32_t cnt; while(1){ cnt = 0; for(i=0; i<500; i++){ for(j=0; j<500; j++){ cnt++; } } sprintf(str, "%lu %d %d\n", cnt, i, j); uart_puts(str); } }
If the routine works as expected, we would expect it to print 250000 500 500
. If a glitch interrupts the program flow, we would expect some of those values to be incorrect. This could be because a loop was skipped, an addition done incorrectly, or the program flow was exited unexpectedly.
Manual Glitch Trigger
To begin with, you'll simply use the manual glitch triggering. This works well in the examples where we have a simple loop we are breaking out of. Doing so requires modifying the glitch width and glitch offset experimentally. The exact values will vary for every device and setup.
It is recommended to only use the glitch width (as % of period) option, as the fine adjust is too small of a change for this lower-speed example. Other hardware may need the precision added by the fine adjust however!
The following figure shows several different settings for a 7.37 MHz clock. The width is set to 10%, which for the 136nS clock period of the 7.37 MHz clock means the glitch width is about 13.6 nS. When the offset is negative, the glitch is placed in-front of the clock. The glitch is XORd with the clock, meaning this becomes a small positive-going glitch in-front of the regular clock pulse.
If the offset is positive, the glitch occurs after the rising edge of the clock pulse. Because this glitch pulse is XORd with the clock, it becomes a negative-going glitch inserted in the 'middle' of the regular clock pulse.
With some background, let's now check some glitches. Assuming you've setup the example as before, do the following:
Adjust the settings for Glitch Width (as % of period) , Glitch Offset (as % of period), and Repeat based on your target and the following table for different targets:
Parameter AVR on Multi-Target (CW301) CW-Lite XMEGA Board CW-Lite Arm Board Glitch Width (as % of period) 7.5 9.5 -10 Glitch Offset (as % of period) -10 -2 -40 Repeat 5 105 105 - Ensure Glitch Trigger is Manual
- Hit the Manual Trigger button
- See if you end up with either the target resetting (reprints
hello\n
), or if the loop count becomes wrong. You may need to press the Manual Trigger button several times quickly. The objective is to have an incorrect loop count, meaning you caused a glitch! - To force a reset of the target, use the Signature Read option on the programmer.
- Adjust the glith width & offset as needed.
- You may also adjust the Repeat option, or cause it to glitch several instructions.
Be aware that you may crash the target! In the previous examples the target could have reset after each glitch. It may simply go into another infinite loop however, or even enter invalid states. Again force a hardware reset of the target in these cases. It may appear like the target was never glitched, whereas in reality it was glitched into some invalid state.
The boards are extremely sensitive to the glitch width and offset. You may have trouble finding settings that cause a glitch. Don't get too hung up on this; the following sections provide a more reliable method of glitching a target by determining the appropriate parameter settings.
Automatically Resetting Target
If we are going to start with the target at a pre-determined state, we need to reset the target. There are two ways of automatically performing this. The method used here will use the existing programmer interface to reset the device by performing that "read signature" operation we have already been using. The other method is to toggle a GPIO pin, which is more generic for future use.
This was introduced in Tutorial_B3-1_Timing_Analysis_with_Power_for_Password_Bypass#Reset_via_Auxiliary_Module.
To setup the automatic reset, perform the following:
- Scroll down the list of scripts, and you'll find one labeled "aux_reset_cw1173.py". Depending on your target, you may have to modify this script to change the reset pin. Most targets (except for the XMEGA) use nrst, so if you're unsure, this is usually the correct choice . This script sets up the aux module that attempts to reset the target device. Note: The aux module is only executed after capture is executed.
- Hit the "Run" button. If you switch to the "Auxilary Module" tab, you'll see it's been added to the list of modules at the specified location.:
- Looking at the code of the script, you can see how this script is using an external module & linking it to a specific auxilary module trigger:
from chipwhisperer.capture.auxiliary.ResetCW1173Read import ResetCW1173 # GUI compatibility try: aux_list = self.aux_list except NameError: pass # Delay between arming and resetting, in ms delay_ms = 1500 # Reset XMEGA device Resetter = ResetCW1173(pin='pdic', delay_ms=delay_ms) # Reset STM32Fx device #Resetter = ResetCW1173(pin='nrst', delay_ms=delay_ms) # Reset AVR #Resetter = ResetCW1173(pin='nrst', delay_ms=delay_ms) # Reset before arming # avoids possibility of false triggers # need delay in target firmware to avoid race condition #aux_list.register(Resetter.resetThenDelay, "before_trace") # Reset after arming # scope can catch entire reset # avoids race condition # target reset can cause false triggers (usually not an issue) aux_list.register(Resetter.delayThenReset, "after_arm")
- You can edit the values required such as reset time & location by changing the script (using an external editor). But an easier method is to insert it into our attack script itself. As a test we'll see if the default values work. We will later integrate this into a full example script.
We can now confirm the reset works with the "Capture 1" button. This requires us to disable the normal routing of the output data to a file for analysis, as we want to just dump data to the terminal emulator. To do this:
- Switch to the Target Settings tab.
Remove all of the Load Key Command, Go Command, and Output Format options:
- Press the "Capture 1" button a few times, which should confirm on each "capture" the target device is resetting.
Finally, we will switch the glitch target to give us a more realistic target to glitch. To do this open the file
chipwhisperer\hardware\victims\firmware\glitch-simple\glitchsimple.c
and modify the call inmain()
, such that we now call theglitch1()
function. This means the following:while(1){ glitch_infinite(); }
can be changed to:
while(1){ glitch1(); }
After which recompile (with
make
), and reprogram the target device. Note the new function being glitched looks like this:void glitch1(void) { led_ok(1); led_error(0); //Some fake variable volatile uint8_t a = 0; putch('A'); //External trigger logic trigger_high(); trigger_low(); //Should be an infinite loop while(a != 2){ ; } led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); uart_puts("1234"); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); led_error(1); //Several loops in order to try and prevent restarting while(1){ ; } while(1){ ; } while(1){ ; } while(1){ ; } while(1){ ; } }
When you perform a Capture 1, the terminal should print
hello\nA
, based on the above source code. Note the objective will be to glitch past the infinite loop, such that1234
is printed. If using the CW303 board, this will also light the red LED on the board up.hint
If the startup message isn't visible, it may be related to issues with the Capture software not being fast enough after reset to display the serial port contents on the terminal emulator. This happens often on the virtual machine environment, as can be seen in the demo video. You can ignore this error for now.
Automatically Triggering Glitch
The manual trigger used previously is suitable when the embedded system is waiting for further input. For example if the embedded system is waiting for a password, you could insert glitches without requiring accurate timing. We'll explore the use of the capture trigger for glitching here, which also improves the repeatability of your glitch attempts.
To use this system, you must first understand the routing of the trigger to the glitch module. The following figure shows the trigger routing, which is more basic than the power capture trigger:
Note in particular that if using an external IO pin, you only have a rising edge trigger. The example glitch program includes a line which is set 'High' at critical moments, allowing you to experiment with this basic IO trigger.
Based on the source code loaded, we currently have a trigger to time the glitch. This is very useful during the characterization phase, where we wish to determine what sort of glitch affects this specific hardware. Once we know that, we can move onto glitching a more "realistic" routine.
Before doing that, we will actually enable the power analysis capture. To do this:
Press Capture 1, confirm some waveform is displayed. For example with the XMEGA Target on the ChipWhisperer-Lite, the waveform looks like this:
- If this does't work: check the trigger in use is the Target IO4 pin.
If this also does not work, and there are timeout issues, causing the trigger to be forced: create a copy of the "aux_reset_cw1173.py" script and change the
# Reset before arming - more stable aux_list.register(Resetter.resetThenDelay, "before_trace") # Reset after arming - scope can catch entire reset #aux_list.register(Resetter.delayThenReset, "after_arm")
to
# Reset before arming - more stable #aux_list.register(Resetter.resetThenDelay, "before_trace") # Reset after arming - scope can catch entire reset aux_list.register(Resetter.delayThenReset, "after_arm")
by commenting out the second line and un-commenting out the fourth line changing the chronological position of the reset to after the scope is armed. This should remove the timeout issue as the scope can now detect the trigger as it is armed before the trigger line is activated. Use this copy of the script instead of the original version by running the edited script once and disabling the aux module of the original script in Aux Settings under Before Trace.
Finally, we can enable the trigger of the glitch to occur based on this external trigger pin. This can be accomplished by:
Switch the Glitch Trigger mode to Ext Trigger:Single-Shot:
Performing a Capture 1, you'll notice that the waveform is now perturbed. This is due to the clock glitches causing odd power consumption behavior:
- Play around a bit with the glitch width, offset, and repeat. You should see different effects in the power consumption traces.
Using the Glitch Explorer
Now that we can automatically perform the glitching, we can use the glitch explorer to automatically vary glitch parameters while recording what the target device is doing. Before continuing with the tutorial, we'll go through an overview of the the glitch explorer.
Glitch Explorer
We'll first introduce the Glitch Monitor ("Glitch Explorer") before we go ahead and show you how to use it. The main window of the glitch explorer looks like this:
Where you can see the following parts
- The top part is the output of the system combined with the parameters of the glitch is displayed (the 'output window').
- In the bottom part you can adjust general parameters of the glitching system, such as what counts as a successful glitch or not.
We'll be looking at each of these sections in more detail next.
The Output Window
The output window highlights different types of output. In this example we have an output |1| highlighted in green, which is flagged as a successful glitch. This example code was waiting for the rrrr sequence.
Glitches can also be flagged as 'normal', in which case there is no highlight as in |2|. Finally the glitch could be flagged as an error, in which case it will be highlighted in red.
In order for the glitch explorer to receive the output value, you must insert the special code $GLITCH$
into the Target Settings --> Output Format settings. Data is still sent to the terminal emulator so you can monitor what is happening, but if you don't set the $GLITCH$ special string you won't see it in glitch explorer.
The Main Settings
Details of the main settings:
The response of the system during normal operation is set at Normal response. This defines what happens when no glitching or unexpected behavior happened.
The desired response of the system if the glitch was successful is set at Successful response.
The expected and desired responses are expected to be Python expressions, where s
is a str-type variable which contains the response of the system. The expression must evaulate to True
or False
. For example, the following shows examples of what you could use as possible expressions:
Desired Behavior | Parameter Expression |
---|---|
Check for "hello\n" exactly. | s == "hello\n" |
Check for "hello\n" at end of string. | s.endswith("hello\n") |
Check for hex 0xAF in last byte position. | ord(s[-1]) == 0xAF |
Note that there is sometimes garbage in the first position. This occurs because if the target device is being reset before the glitch, you may see the serial lines floating. These floating lines may cause invalid characters to be recorded.
Parameter Settings
The actual parameters to change are set via a simple Python script. You will register this script to an appropriate section in the system using the "auxiliary module". Using a script makes it easy to define all sorts of various settings you might find of interest.
For example the following script would insert code to cycle through width and offset settings:
class IterateGlitchWidthOffset(object):
def __init__(self, ge_window):
self._starting_offset = -40
self._starting_width = 5
self.ge_window = ge_window
def reset_glitch_to_default(self, scope, target, project):
""" Set glitch settings to defaults. """
self.offset = self._starting_offset
self.width = self._starting_width
def change_glitch_parameters(self, scope, target, project):
""" Example of simple glitch parameter modification function. """
# This value is minimum clock offset/width increment
self.offset += 0.390625
if self.offset > 40:
self.offset = self._starting_offset
self.width += 0.390625
if self.width > 40:
self.width = self._starting_width
# Write data to scope
scope.glitch.width = self.width
scope.glitch.offset = self.offset
#You MUST tell the glitch explorer about the updated settings
if self.ge_window:
self.ge_window.add_data("Glitch Width", scope.glitch.width)
self.ge_window.add_data("Glitch Offset",scope.glitch.offset)
glitch_iterator = IterateGlitchWidthOffset(self.glitch_explorer)
self.aux_list.register(glitch_iterator.change_glitch_parameters, "before_trace")
self.aux_list.register(glitch_iterator.reset_glitch_to_default, "before_capture")
Note you can quickly cause very long captures to occur! To run the glitch explorer, you need to set the appropriate number of traces on the General Settings tab, and use the Capture Multi to run the glitch explorer.
The ChipWhisperer system has no idea how many iterations are required with your code - it still uses a fixed number of captures by default. Later versions of the API will support an exit signal.
Example Running the Glitch Explorer
XMEGA
This example will attempt to break out the loop in glitch1()
. Moving ahead from where you were in #Automatically Triggering Glitch, we will see how we can view the output of the target device in the glitch explorer.
Switch to the Target Settings tab, and set the Output Format to be
$GLITCH$
:- From the Tools menu select Glitch Monitor to open the glitch explorer.
Press the Capture 1 button a few times, and you should see the table populated with outputs:
We want to mark them as "normal" or "glitch successful" to get the color-coding working appropriately.
- Double-click on a normal response, and copy the text. In the Normal Response field, we need to compare the magic variable
s
with that copied text. Do this by setting the Normal Response to be:s == '\x00hello\nA'
. - We want to mark a string ending with
1234
as a pass. Thus in the Successful Response field, set the test to bes.endswith('1234')
(remember in Python both'
and"
are valid for string start/end characters). Press Capture 1 a few more times, and check the color-coding has changed:
The next step is to tune the glitch offset to attempt to get a successful clock glitch. These steps are listed as follows:
- Make a new file called 'ge_adjustment.py with these contents:
class IterateGlitchParameters(object): def __init__(self, ge_window): self._starting_offset = -10 self.ge_window = ge_window def reset_glitch_to_default(self, scope, target, project): """ Set glitch settings to defaults. """ self.offset = self._starting_offset def change_glitch_parameters(self, scope, target, project): """ Example of simple glitch parameter modification function. """ # This value is minimum clock offset/width increment self.offset += 0.390625 if self.offset > 40: self.offset = self._starting_offset # Write data to scope scope.glitch.offset = self.offset #You MUST tell the glitch explorer about the updated settings if self.ge_window: self.ge_window.add_data("Glitch Offset",scope.glitch.offset) glitch_iterator = IterateGlitchParameters(self.glitch_explorer) self.aux_list.register(glitch_iterator.change_glitch_parameters, "before_trace") self.aux_list.register(glitch_iterator.reset_glitch_to_default, "before_capture")
Assuming you still have the "Capture" working, you can simply find where you stored that script and hit Run. You should see it execute successfully on the command line.:
Confirm you see the modules loaded in the Aux Settings tab:
On the main GUI in the Scope Settings tab, change the following values for the Glitch Module:
- Repeat set to 105.
- Glitch Width (as % of period) set to 8.0.
These values will be used during the glitch explorer run. We have not specified anything for the tuning, so they will not be changed from whatever is already in the GUI.
On the General Settings tab:
- Set the Number of Traces to 121.
With any luck, at least one of the glitches will be successful:
If you get a reset (prints 'hello' again), you might need to reduce the "repeat" value. If you have no successful glitches, double-check all settings. You can continue to the next step anyway, as in that step we will also tune the "glitch width".
We may also need to tune the "Glitch Width". We can use knowledge of the successful glitch from the previous step to reduce our search space. In this case, assume we had a successful glitch with a width of 8.0 and offset of -2. We'll search around those values to see if we can achieve a more successful glitch performance.
Arm
This example will attempt to break out the loop inglitch1()
. Moving ahead from where you were in #Automatically Triggering Glitch, we will see how we can view the output of the target device in the glitch explorer.Switch to the Target Settings tab, and set the Output Format to be
$GLITCH$
:- From the Tools menu select Glitch Monitor to open the glitch explorer.
Press the Capture 1 button a few times, and you should see the table populated with outputs:
We want to mark them as "normal" or "glitch successful" to get the color-coding working appropriately.
- Double-click on a normal response, and copy the text. In the Normal Response field, we need to compare the magic variable
s
with that copied text. Do this by setting the Normal Response to be:s == '\x00hello\nA'
. - We want to mark a string ending with
1234
as a pass. Thus in the Successful Response field, set the test to bes.endswith('1234')
(remember in Python both'
and"
are valid for string start/end characters). Press Capture 1 a few more times, and check the color-coding has changed:
The next step is to tune the glitch offset to attempt to get a successful clock glitch. These steps are listed as follows:
- Make a new file called 'ge_adjustment.py with these contents:
class IterateGlitchParameters(object): def __init__(self, ge_window): self._starting_offset = -45 self.ge_window = ge_window def reset_glitch_to_default(self, scope, target, project): """ Set glitch settings to defaults. """ self.offset = self._starting_offset def change_glitch_parameters(self, scope, target, project): """ Example of simple glitch parameter modification function. """ # This value is minimum clock offset/width increment self.offset += 0.390625 if self.offset > 40: self.offset = self._starting_offset # Write data to scope scope.glitch.offset = self.offset #You MUST tell the glitch explorer about the updated settings if self.ge_window: self.ge_window.add_data("Glitch Offset",scope.glitch.offset) glitch_iterator = IterateGlitchParameters(self.glitch_explorer) self.aux_list.register(glitch_iterator.change_glitch_parameters, "before_trace") self.aux_list.register(glitch_iterator.reset_glitch_to_default, "before_capture")
Assuming you still have the "Capture" working, you can simply find where you stored that script and hit Run. You should see it execute successfully on the command line.:
Confirm you see the modules loaded in the Aux Settings tab:
On the main GUI in the Scope Settings tab, change the following values for the Glitch Module:
- Repeat set to 1.
- Glitch Width (as % of period) set to -10.
These values will be used during the glitch explorer run. We have not specified anything for the tuning, so they will not be changed from whatever is already in the GUI.
On the General Settings tab:
- Set the Number of Traces to 121.
With any luck, at least one of the glitches will be successful:
If you start getting ADC timeouts and the device stops responding, you may have to reduce Glitch Width (as % of period) to be closer to 0.
Finishing the Tutorial
We may also need to tune the "Glitch Width". We can use knowledge of the successful glitch from the previous step to reduce our search space. In this case, assume we had a successful glitch with a width of 8.0 and offset of -2. We'll search around those values to see if we can achieve a more successful glitch performance.
To continue the tutorial, the following steps will be taken:
- Modify the glitch parameter script to also loop through the Glitch Width. If you get stuck you can look at the example script earlier (in section #Parameter_Settings).
- To make glitching more likely, you'll also want to change the range of Glitch Offset to use values around successful ones. For example, positive glitch offsets typically work well for the XMEGA target, while negative ones work better for the CW303 Arm target.
- On the main GUI in the Scope Settings tab, adjust the Glitch Module repeat parameter to be 1. We are now attempting to achieve success with a single clock cycle being glitched.
- Still in the main GUI, adjust the number of traces per capture to be 1000. This reflects the number of iterations required to run through both loops (20 x 50).
- Hit the Capture Multi button and cross your fingers! Hopefully you will see a successful glitch for some combination of glitch width and offset. We aren't quite done yet, as you will also need to do some fine-tuning to achieve high reliability on the glitch.
Record some of the useful parameters by scrolling through the window (WARNING: changing parameters will clear the table, so record useful values now). In this example there was a success at Offset = 8.5%, and Width = 7.5%. Let's see how to fine-tune those values:
- Plug those values into the main GUI Glitch Module setting. If we use the Capture 1 button values are taken from the main GUI, instead of the glitch explorer.
- Press the Capture 1 button a few times. You'll note it records the output of the device, which may not be generating successful glitches (NB: the "offset" and "width" recorded in the table may be wrong when using the Capture 1 button, as the glitch explorer is not recording values from the main GUI correctly. This is a bug in the display only, the correct values are being sent to the device).
Using arrow keys, nudge the Glitch Offset (fine adjust) up and down. Try performing a Capture 1 to see if you are able to achieve a reliable glitch. In this example setting the fine adjust to 44 resulted in a very reliable glitch:
You might want to try seeing if there is an upper limit to this setting, and putting it mid-way between the lower and upper limits for generating a glitch.
Congrats! You've now performed some tuning to achieve a reliable glitch on the target device. The next step is to glitch something more fun - like a password check
Glitching a Password Check
This assumes you now have a set of parameters which caused a reliable glitch. We'll now glitch past a password check, initially using our trigger as a crutch. The function of interest compares a received password to some known password. The glitch3()
function looks as follows:
void glitch3(void) { char inp[16]; char c = 'A'; unsigned char cnt = 0; uart_puts("Password:"); while((c != '\n') & (cnt < 16)){ c = getch(); inp[cnt] = c; cnt++; } char passwd[] = "touch"; char passok = 1; trigger_high(); trigger_low(); //Simple test - doesn't check for too-long password! for(cnt = 0; cnt < 5; cnt++){ if (inp[cnt] != passwd[cnt]){ passok = 0; } } if (!passok){ uart_puts("Denied\n"); } else { uart_puts("Welcome\n"); } }
The following assumes you have already completed the previous steps:
- Close the glitch explorer.
- Modify the file
glitchexample.c
to callglitch3()
instead ofglitch1()
, which is to say simply change the main function called frommain()
toglitch3()
. - R
ebuild the firmware
. - Program the target device with your
.hex
file. - On the Target Settings tab, clear the Output Format field. That is remove the
$GLITCH$
text, as we are no longer using the glitch explorer. If you don't do this, you will not see any output of the device on the terminal emulator. - Open the terminal emulator, and connect to it again (if you closed it).
Reset the device, it should prompt you for a password. The correct password is
touch
, try both correct and incorrect passwords. The program as designed loops after a password try to prompt you again. You should see both correct and incorrect responses:- On the Scope Settings tab, adjust the Timeout(s) to a larger value such as 20. We need a longer timeout to work with the serial terminal.
Let's try a glitch insertion! Perform the following:
- Press the Capture 1 button. This will reset the target and arm the glitch.
- Before the timeout, enter a wrong password such as
test
in the terminal and hit enter. - See if you can get the wrong password accepted. If not, let's use the Glitch Explorer to automate the parameter adjustments.
Switching to the Auxiliary Settings tab, adjust the delay on the reset such that you have a 150 mS delay. This will mean once the device resets there is a delay while it prints the startup message.
Switch to the Target Settings tab:
- In the Go Command field, put the bad password such as
test\n
. - In the Output Format field, put
$GLITCH$
to route the output to the glitch explorer.
- In the Go Command field, put the bad password such as
- Open the Glitch Explorer, and press Capture 1. You should see the Denied message come across.
- Generate a script to modify the 'offset' parameter in the glitch generator. You can always dump the scope parameters with scope at the command line in the ChipWhisperer-Capture to see all the fields.
- Set the number of traces on the General Settings tab to 200.
- On the main GUI, in the Scope Settings tab, ensure that you have the number of repeats on the Glitch Module set to 1. We will start with a single clock cycle glitched.
Press Capture Multi. Monitor the glitch outputs, you may see some errors or a successful glitch. Note that sometimes the errors are useful - here is an example where the glitched code actually dumped the password:
More likely you might see a "Welcome" message indicating the password check was glitched:
If the previous step isn't successful, increase the "repeat" count on the Glitch Module section of the Scope Settings tab, and try again. In this example I actually needed a repeat count of "3" to get the successful "Welcome" message printed above.
You can also increase the repeat count in the glitch explorer, which simply tries the same settings multiple times. You will likely find that the successful glitch does not have 100% success rate, so using a repeat count of 2 or 3 is helpful to increase your chances of success.
Glitching Onward
This basic tutorial has introduced you to glitch attacks. They are a powerful tool for bypassing authentication in embedded hardware devices. There are many ways to expand your knowledge with additional practice, such as:
- Use manual glitches to try simply glitching past the prompt in
glitch3()
. - Completing Tutorial A3 VCC Glitch Attacks, which introduces glitching via voltage instead of the clock.
- Using the ChipWhisperer Python API to make GUI-less scripts. For examples of using scripting, see Making Scripts.
- Download some example source code (bootloaders, login prompts, etc) and port them to the AVR. See how you can glitch past security checks.
- Use one of the IO triggers discussed in Tutorial_A1_Synchronization_to_Communication_Lines.