上位机使用指南
上位机使用Python语言开发,通过TCP协议与设备进行通信。
推荐在Jupyter环境下使用上位机对设备进行操作,这样可以利用上位机提供的设备控制面板减少代码编辑量,并且能够通过示波器面板
实时查看到设备参数配置的效果。
上位机总体架构如下图:
对于上位机SDK的API说明,可访问https://cracknuts.readthedocs.io/zh-cn/stable/了解。
上位机中Cracker
代表设备,Acquisition
代表采集流程,围绕这两个模块上位机可以实现对设备的控制、数据的采集。
命令行工具
安装完CrackNuts
后,在控制台中提供cracknuts
命令,提供以下Jupyter
快捷命令:
- 启动
Jupyter lab
cracknuts lab
- 打开教程
cracknuts tutorials
- 创建新笔记文件
cracknuts create -t [template name] -n [new notebook name]
- 全局配置
cracknuts config set lab.workspace # 配置 cracknuts lab 打开的默认工作目录
上位机基本使用
上位机安装成功后,可以通过Python对设备进行控制。如下,通过Python控制台直接访问设备并进行配置:
-
启动
Python
环境:
通过快速安装
方式安装的CrackNuts
,可以通过快捷图标启动CrackNuts
环境,其他方式安装的可以根据自己的情况选择合适的方式进入有CrackNuts
依赖的Python
环境 -
连接设备并对Nut配置电压
以上代码解释如下:
# 引入 cracknuts
>>> import cracknuts as cn
# 通过快速入口函数创建一个Cracker对象
>>> cracker = cn.new_cracker('192.168.0.211')
# 连接设备
>>> cracker.connect()
# 获取设备ID,此处仅用于验证连接状态,这是一个验证设备正确连接的简单有效方法
>>> cracker.get_id()
(0, '74332025379485') # 此处为 CrackNuts 上位机 API 的返回格式:元组第一位为函数执行状态位,0 表示成功,其他表示失败; 第二位位返回数据位,此处获取设备ID(S/N)即在此处,对于没有返回数据需求的接口则为None
# 配置Nut设备电压为3.2V
>>> cracker.nut_voltage(3.2)
(0, None)
# 对Nut进行使能操作,此时默认的stm32 103的Nut板上应该亮灯
>>> cracker.nut_voltage_enable()
(0, None)
>>>以上就完成了最简单的上位机的控制,其他更丰富的配置可阅读API文档了解。
采集流程
在“快速开始”章节中,您可能已经注意到,使用 CrackNuts
进行波形采集时,仅需控制 Nut
的动作,即可完成能量波形的采集。这是因为 CrackNuts
设计了一套简化的采集流程,旨在降低操作复杂度,使用户能够专注于 Nut
的加密等核心流程控制。
该采集流程由 Acquisition
类负责管理,即使用控制面板前创建的 acq
对象。该对象实现了指令发送、加密数据保存、能量轨迹保存等关键步骤,并预留了 init
和 do
两个阶段,供用户插入自定义逻辑。通过该流程,用户可以实现以下功能:
- 使用图形界面配置参数,支持波形实时展示,便于调整设备设置;
- 自动保存配置参数,方便实验流程复现;
- 自动保存采集到的曲线数据,便于后续的数据分析。
采集流程的结构如下图所示:
与这个流程对应的Cracker及Nut的流程图如下图:
图中,CrackNuts
表示上位机软件,Cracker
是测试设备,Nut
为被测对象,下发的 Wave
则代表侧信道信号。
用户需实现两个函数:init()
和 do()
,其中 init()
函数仅在采集流程开始时执行一次,而 do()
函数则会被循环调用。
在这两个函数中,用户可编写具体的指令逻辑,通过 Cracker
下发给 Nut
,并接收 Nut
返回的数据,由 Cracker
再转发回 CrackNuts
上位机程序。
当 init()
函数执行完成后,CrackNuts
会自动向 Cracker
下发 osc_single()
命令,将其设置为“准备采集曲线”模式。具体的触发条件可通过上位机界面或命令进行配置,支持的参数包括:信号源(A/B 通道)、触发对象(如 Nut
)、通信协议等。
在 do()
函数执行期间,Cracker
会实时检测触发条件,一旦条件满足,即刻采集波形数据。
待 do()
函数执行完毕后,CrackNuts
会自动判断是否成功触发采集:如触发成功,则从 Cracker
中读取采集到的数据并进行保存。
在快速开始章节中的创建Acquisition
,就是这个采集流程:
import random
import time
from cracknuts.cracker import serial
cmd_set_aes_enc_key = "01 00 00 00 00 00 00 10"
cmd_aes_enc = "01 02 00 00 00 00 00 10"
aes_key = "11 22 33 44 55 66 77 88 99 00 aa bb cc dd ee ff"
aes_data_len = 16
sample_length = 1024 * 20
def init(c):
cracker.nut_voltage_enable()
cracker.nut_voltage(3.4)
cracker.nut_clock_enable()
cracker.nut_clock_freq('8M')
cracker.uart_enable()
cracker.osc_sample_clock('48m')
cracker.osc_sample_length(sample_length)
cracker.osc_trigger_source('N')
cracker.osc_analog_gain('B', 10)
cracker.osc_trigger_level(0)
cracker.osc_trigger_mode('E')
cracker.osc_trigger_edge('U')
cracker.uart_config(baudrate=serial.Baudrate.BAUDRATE_115200, bytesize=serial.Bytesize.EIGHTBITS, parity=serial.Parity.PARITY_NONE, stopbits=serial.Stopbits.STOPBITS_ONE)
time.sleep(2)
cmd = cmd_set_aes_enc_key + aes_key
status, ret = cracker.uart_transmit_receive(cmd, timeout=1000, rx_count=6)
def do(c):
plaintext_data = random.randbytes(aes_data_len)
tx_data = bytes.fromhex(cmd_aes_enc.replace(' ', '')) + plaintext_data
status, ret = cracker.uart_transmit_receive(tx_data, rx_count= 6 + aes_data_len, is_trigger=True)
return {
"plaintext": plaintext_data,
"ciphertext": ret[-aes_data_len:],
"key": bytes.fromhex(aes_key)
}
acq = cn.new_acquisition(cracker, do=do, init=init)
这其中new_acquisition
必须传入的参数中含义如下,其他更:
- cracker: Acquisiton 流程要管理的
Cracker
目标 - do: 用户具体的加密逻辑函数, 并且回需返回要保存到波形文件中的数据
- init: 能量轨迹采集开始前的准备工作,如一些基础的配置
同样的,在控制面板中(关于控制面板的介绍在后续在Jupyter中使用CrackNuts上位机中有介绍),有着更丰富的流程控制参数可以配置:
其含义如下(参考上面的流程图可更好的理解)这些参数如果对整体流程不了解的情况下不建议修改:
- 触发判断等待时长:每次
is_trigger
判断之间的间隔 - 触发判断超时:经过该时常后设备依然没有判定到触发状态,则认为该轮采集失败
- 采集频率:在测试模式下每隔多长时间对设备进行一次加密数据操作
- do异常最大次数:用户do函数中的代码允许出现错误的次数,默认-1不允许出现错误
除了上面的流程控制参数外,控制面板的流程管理区域其他功能如下:
- 流程状态控制:
- 测试:仅进行数据加密、能量轨迹操作不保存波形文件
- 运行:进行完整的数据加密、能量采集、文件保存操作
- 暂停:暂停当前的测试或运行流程
- 停止:停止当前的测试或运行流程
- 采集轮数:采集的曲线数量,即执行多少次do函数的内容
- 保存格式:曲线文件的保存格式,默认是
scarr
格式,可选numpy
格式 - 保存路径:曲线文件的保存文件夹,曲线文件会以时间戳格式命名保存到这个目录下
CrackNuts
面 板的其他功能可参考后续章节的介绍。
在Jupyter中使用CrackNuts上位机
除了可以在Python
控制台和Python
脚本文件中使用CrackNuts
外,还可以使用Jupyter
环境,也是我们推荐的方式。在Jupyter
中我们提供了更为简洁的GUI
控制面板方式实现对设备的控制、数据的展现。
并且还提供了cracknuts lab
这个简洁命令来启动一个Jupyter
环境。
通过以上命令可以启动一个Jupyter lab
环境,之后就可以创建一个Jupyter Notebook
来开始控制设备
在新建的Notebook
中分两个单元格输入如下内容,即可打开设备控制面板:
import cracknuts as cn
cracker = cn.new_cracker('192.168.0.10')
cracker.connect()
cracker.get_id()
cracker.nut_voltage(3.1)
cracker.nut_voltage_enable()
每一个单元格填写完成代码后,执行代码即可完成代码的执行,效果如下图。(可以使用Ctrl+Enter
来执行,也可使用Shift+Ctrl
执行,后者执行完成后下一个单元将自动激活)
按照以上步骤执行后,可以同样完成对Nut的电压配置和使能配置。
Jupyter控制面板组件
在Jupyter
中还可以使用设备控制面板对设备进行控制,执行如下代码开启设备控制面板
# 创建一个空采集流程控制对象,
acq = cn.new_acquisition(cracker)
# 展示面板
cn.panel(acq)
设备控制面板集成了采集流程管理、NUT
管理、SCOPE
管理、模型展现四个大功能模块,分别实现能量轨迹的采集管理、NUT
目标板控制、Cracker
采集板控制、波形展现这四类功能。
Jupyter Notebook 配置
在Jupyter
中使用控制面板后,可以使用配置功能,该功能可以将当前面板中的配置进行保存、导出、导入、写入设备操作,也可以读取设备的当前配置到面板。
保存配置
与导出配置
的区别是,其把当前配置保存到与Jupyter Notebook
文件关联的配置文件中,下次打开该Jupyter Notebook
中的设备控制面板时自动加载该配置。、
而导出配置则导出到一个配置文件,用户可以在需要的时候通过加载配置
加载该配置。
默认情况下,通过代码对Cracker
的配置会同步到控制面板中,但是如果控制面中加载了配置文件中配置(无论是加载的关联Jupyter Notebook
还是通过加载配置
配置加载的外部配置)
并且其与设备中的配置不一致,控制面板将通过写入配置
这 个按钮变成红色进行提示,此时通过代码对设备的配置将不同步到控制面板中,直到通过写入按钮把配置写入到设备。
语言切换
控制面板在第一次使用时,默认界面展示的是英文,用户可以通过面板右上角的语言切换按钮进行切换,切换后对所有Jupyter Notebooke
生效。
Jupyter默认工作目录配置
通过cracknuts lab
命令启动的Jupter lab
实例,可以通过如下命令配置默认的工作空间,保证用户无论在哪个目录下执行这个命令都能从工作空间启动。
cracknuts config set lab.workspace
日志配置
默认情况下,使用CrackNuts
时,日志会打印到当前控制台,如果是Jupyter
则会打印到运行单元格的下方,这些日志可以方便用户调试程序排查问题。
日志级别配置
CrackNuts
默认的日志是warning
级别,只打印必要的警告和错误信息,如果用户需要更详细的诸如发送的数据等信息可以通过以下方式修改日志级别为info
来实现:
from cracknuts import logger
logger.set_level('info')
或者更加详细,把日志级别改成debug
,但是这样打印信息会非常多,使用时需要注意:
from cracknuts import logger
logger.set_level('debug')
日志打印位置配置
有的时候,尤其是在能量轨迹采集过程中,会有有大量的日志打印,此时日志打印在控制台或者Jupyter Notebook
中,会使得Jupyter
页面变得非常长,难以使用,此时可以通过以下代码把日志重定向到文件,在通过其他工具进行日志的检查。
from cracknuts import logger
logger.handler_to_file(r"d:\a.log")
配置后可以通过任意文本编辑器打开日志文件进行检查:
当前Linux或者MacOS用户可以通过tail -f
的形式实时监控日志打印,Windows 用户可以通过在Powershell
中使用Get-Content "d:\a.log" -Wait
命令实现tail
效果
更改 Cracker IP地址
如果你是将Cracker
接入到已有的以太网中,需要该以太网的IP网络属于192.168.0.0/24
这个网络,如果现有网络不在这个网段,则需要修改Cracker
的IP。您需要先通过直连方式连接到设备在通过上位机SDK进行IP修改。
打开CrackNuts
环境,启动Python
然后在执行如下代码进行IP修改:
import cracknuts as cn
s1 = cn.new_cracker('192.168.0.10')
s1.connect()
s1.get_operator().set_ip('192.168.0.251', '255.255.255.0', '192.168.0.1') # 此处IP地址及掩码、网关等需要修改为您的目标网络的允许的配置
执行成功后,Cracker设备的显示屏上会显示修改后的IP地址。