Setup

首先设置硬件对应的平台:

SCOPETYPE可以是’OPENADC’,适用于CWLite/CW1200,或者是’CWNANO’,适用于CWNano。PLATFORM是目标设备,最佳支持选项是’CWLITEARM’/‘CW308_STM32F3’,其次是’CWLITEXMEGA’/‘CW308_XMEGA’,最后是’CWNANO’。例如我的是Chipwhisperer Lite,设置如下:

1
2
SCOPETYPE = 'OPENADC' 
PLATFORM = 'CWLITEARM'

创建一个新目录并将simpleserial-base代码复制到其中:

1
2
3
4
%%bash
cd ../../../hardware/victims/firmware/
mkdir -p simpleserial-base-lab2 && cp -r simpleserial-base/* $_
cd simpleserial-base-lab2

编译固件

1
2
3
%%bash -s "$PLATFORM"
cd ../../../hardware/victims/firmware/simpleserial-base-lab2
make PLATFORM=$1 CRYPTO_TARGET=NONE

输出如下类似说明成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
SS_VER set to SS_VER_1_1
SS_VER set to SS_VER_1_1
SS_VER set to SS_VER_1_1
SS_VER set to SS_VER_1_1
make[1]: '.dep' is up to date.
SS_VER set to SS_VER_1_1
SS_VER set to SS_VER_1_1
.
Welcome to another exciting ChipWhisperer target build!!
arm-none-eabi-gcc (15:12.2.rel1-1) 12.2.1 20221205
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

.
Compiling:
-en simpleserial-base.c ...
-e Done!
.
Compiling:
-en .././simpleserial/simpleserial.c ...
-e Done!
.
Compiling:
-en .././hal/stm32f3/stm32f3_hal.c ...
-e Done!
.
Compiling:
-en .././hal/stm32f3/stm32f3_hal_lowlevel.c ...
-e Done!
.
Compiling:
-en .././hal/stm32f3/stm32f3_sysmem.c ...
-e Done!
.
Assembling: .././hal/stm32f3/stm32f3_startup.S
arm-none-eabi-gcc -c -mcpu=cortex-m4 -I. -x assembler-with-cpp -mthumb -mfloat-abi=soft -fmessage-length=0 -ffunction-sections -DF_CPU=7372800 -Wa,-gstabs,-adhlns=objdir-CWLITEARM/stm32f3_startup.lst -I.././simpleserial/ -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/ .././hal/stm32f3/stm32f3_startup.S -o objdir-CWLITEARM/stm32f3_startup.o
.
LINKING:
-en simpleserial-base-CWLITEARM.elf ...
-e Done!
.
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 Flash: simpleserial-base-CWLITEARM.bin
arm-none-eabi-objcopy -O binary -R .eeprom -R .fuse -R .lock -R .signature simpleserial-base-CWLITEARM.elf simpleserial-base-CWLITEARM.bin
.
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
SS_VER set to SS_VER_1_1
SS_VER set to SS_VER_1_1
Size after:
text data bss dec hex filename
4860 8 1432 6300 189c simpleserial-base-CWLITEARM.elf
+--------------------------------------------------------
+ Default target does full rebuild each time.
+ Specify buildtarget == allquick == to avoid full rebuild
+--------------------------------------------------------
+--------------------------------------------------------
+ Built for platform CW-Lite Arm \(STM32F3\) with:
+ CRYPTO_TARGET = NONE
+ CRYPTO_OPTIONS = AES128C
+--------------------------------------------------------

Connecting to Hardware

找到硬件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import chipwhisperer as cw
try:
if not scope.connectStatus:
scope.con()
except NameError:
scope = cw.scope()

try:
target = cw.target(scope)
except IOError:
print("INFO: Caught exception on reconnecting to target - attempting to reconnect to scope first.")
print("INFO: This is a work-around when USB has died without Python knowing. Ignore errors above this line.")
scope = cw.scope()
target = cw.target(scope)

print("INFO: Found ChipWhisperer😍")

if "STM" in PLATFORM or PLATFORM == "CWLITEARM" or PLATFORM == "CWNANO":
prog = cw.programmers.STM32FProgrammer
elif PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
prog = cw.programmers.XMEGAProgrammer
elif "neorv32" in PLATFORM.lower():
prog = cw.programmers.NEORV32Programmer
elif PLATFORM == "CW308_SAM4S":
prog = cw.programmers.SAM4SProgrammer
else:
prog = None

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

if PLATFORM == "CW308_SAM4S":
scope.io.target_pwr = 0
time.sleep(0.2)
scope.io.target_pwr = 1
time.sleep(0.2)
def reset_target(scope):
if PLATFORM == "CW303" or PLATFORM == "CWLITEXMEGA":
scope.io.pdic = 'low'
time.sleep(0.1)
scope.io.pdic = 'high_z' #XMEGA doesn't like pdic driven high
time.sleep(0.1) #xmega needs more startup time
elif "neorv32" in PLATFORM.lower():
raise IOError("Default iCE40 neorv32 build does not have external reset - reprogram device to reset")
elif PLATFORM == "CW308_SAM4S":
scope.io.nrst = 'low'
time.sleep(0.25)
scope.io.nrst = 'high_z'
time.sleep(0.25)
else:
scope.io.nrst = 'low'
time.sleep(0.05)
scope.io.nrst = 'high_z'
time.sleep(0.05)

以下输出说明成功,我的固件版本偏低(不要紧)

1
2
3
(ChipWhisperer NAEUSB WARNING|File naeusb.py:743) Your firmware (0.64) is outdated - latest is 0.65 See https://chipwhisperer.readthedocs.io/en/latest/firmware.html for more information

INFO: Found ChipWhisperer😍

Uploading Firmware

把lab2的固件写入到板子

1
cw.program_target(scope, prog, "../../../hardware/victims/firmware/simpleserial-base-lab2/simpleserial-base-{}.hex".format(PLATFORM))

输出如下说明成功

1
2
3
4
5
6
Detected known STMF32: STM32F302xB(C)/303xB(C)
Extended erase (0x44), this can take ten seconds or more
Attempting to program 4867 bytes at 0x8000000
STM32F Programming flash...
STM32F Reading flash...
Verified flash OK, 4867 bytes

此时也发现板子上的绿灯闪烁(没连上是只有一个蓝灯)

image-20230523033149612

以下是一个用于捕获功耗跟踪的简短函数。使用了cw.capture_trace()。可以查阅readthedocs页面以获取API文档:https://chipwhisperer.readthedocs.io/

1
2
3
4
def capture_trace(_ignored=None):
ktp = cw.ktp.Basic()
key, text = ktp.next()
return cw.capture_trace(scope, target, text).wave
1
2
wave = capture_trace()
print("✔️ OK to continue!")

Output:

1
✔️ OK to continue!

Simple Instruction

simpleserial-base固件会将我们发送给它的内容回显出来。对于本实验,对简单的指令进行实验,而不是串行通信。打开simpleserial-base-lab2文件夹中的simpleserial-base.c,在get_pt()函数中导航并删除simpleserial_put()调用。

image-20230523014641623

重新构建固件并将其上传到目标设备(上面有编译上传的命令,不变的,重新运行一次就行)。这里直接展示结果,捕获一个track,并可以使用以下代码绘制出来:

cw.plot(wave)

image-20230523015055403

接下来插入一些简单的指令,以查看它们是否在功耗跟踪中可见。我们主要寻找执行在单个周期内的指令,加入20个乘法运算,此处将A标记为volatile是很重要的,以防止编译器优化掉所有这些指令。有人会纳闷为啥不用循环去做乘法,请继续往下看。

image-20230523021120763

能耗输出图如下:

image-20230523021246537

Comparing Power Consumption

仔细比较上面两个图,就会发现,有变化!!!后VS前。明显乘法运算让能耗有所变化。

image-20230523022310827

Simple Instruction Loop

接下来就是分析用for循环带来的能耗。变量依旧要用volatile,包括for里面也是,防止编译器优化。

image-20230523022559110

能耗结果如下:

image-20230523022657197

哈哈,能耗相比前者增加更多更多了,而且可以看到这个能量峰前面还挺均匀的。之后的实验就是来寻找指令对应的能耗具体位置。这里解释一下为啥用for循环会更耗能,在微控制器中,循环比简单的复制粘贴代码需要更多的处理步骤,例如比较大小、执行循环体以及递增循环计数器。如果不使用volatile修饰变量i,编译器通常会将循环展开,即将循环优化为重复的代码块。然而,使用volatile修饰变量i可以避免编译器进行这种优化。需要注意的是,循环展开会增加代码块的大小,因此编译器有时会避免展开循环以优化代码大小。

image-20230523024324766

Summary

CPU/微控制器执行不同的指令会有不同的能量消耗和时间消耗。

Reference

Chipwhisperer-Jupyter