OTFDEC硬件模块基于STM32H735G-DK板的验证研发

前言
从stm32h73x系列开始,我们引入了一个新外设模块,otfdec。它的全名叫做on the fly decryption。它的引入,可以帮助大家解决代码保护的痛点。
otfdec简介
大家都知道,代码存储在片内flash,只要做好了jtag调试端口的保护和片上关键代码的隔离,在防止逻辑攻击和直接探测层面,还是相当安全的。但是片上flash毕竟容量有限,在一些应用中我们需要把代码放到片外flash存储甚至直接从片外flash执行。片外flash相比片内flash,在抗攻击方面就脆弱得多。片外flash一般没有什么硬件层面的保护,只要知道了它的料号,它的读写时序都是可以查到的,那么读出来里面的内容就不是什么难事。
所以大家一个自然的想法就是把代码加密后再放到片外flash上,这样即使别人读出里面的密文代码,只要没有密钥,也无法获知代码的有效信息。
就比如胶片中这样的典型拓扑结构:加密代码放在外部的octo-spi flash中。
对这种自然的做法,以往的mcu在执行片外加密代码时,需要先调用ospi驱动,把密文代码读进来,比如放到sram中。然后使用mcu的软件或者硬件解密,把代码明文恢复到sram的另一个区域。最后mcu再从这块sram执行明文代码。
现在我们引入了otfdec这个硬件模块,它位于总线矩阵和octo-spi接口之间。把它配置好之后,内核执行片外flash上的密文代码(在这里octo-spi flash的映射地址是0x9000 0000开始),无需中间再用sram倒一次手,而是在otfdec的作用下,直接把解密后的代码送到总线矩阵上供内核执行了。也就是说,有了otfdec的配合,对于cpu来说,执行外部flash上的加密代码,就和执行片上flash的明文代码是一样的。
为了尽量减少otfdec解密造成的延迟,otfdec被设计工作在aes-128-ctr模式下。不使用aes的链表模式,就是为了尽量缩短对目标地址上密文解密的时间。因此存储在外部octo-spi flash上的加密代码也需要使用同样的aes-128-ctr运算得到。
有一点需要注意的是:为了达到这样的使用效果,octo-spi需要配置到memory map模式。
目前,stm32系列家族中,集成了这个otfdec模块的有stm32h73x系列,stm32l56x系列,和stm32u585系列。
今天我们不是介绍otfdec怎么使用,而是回答前段时间在给客户介绍otfdec的时候,大家一个比较共同的问题:相对于直接执行外部flash上的明文代码,执行外部flash的加密代码,otfdec解密操作引入的延迟有多少?
实验设计
我们接下来设计一个实验,验证在otfdec参与下,内核执行外部flash上的密文代码效率到底如何,用数据说话。
我找了mbedtls中一个自测程序crypto_selftest,验证一下把它加密后放在外部flash,内核执行完整套自测程序需要的时间花销,和执行外部明文代码的差异。为了进一步说明问题,还加了一个场景,就是这个自测程序明文放在片内flash,内核执行它的花销会快多少。
这个crypto自测程序经过最高优化等级编译后,大小差不多在63k作用的样子。
第一个场景就是最普通的,直接把测试程序灌到片上flash运行。
我们先来看一下这个自测程序,主要就是执行selftests这个函数数组里的自测程序。用户可以在mebdtls_conf.h头文件中去选择哪些自测子项被包含进去。现在我选择了6个自测子项。
然后在自测程序开始运行之前,通过检测是否有用户按键按下,来决定是否开启cache。stm32h735集成arm cortex-m7内核,自带32k指令cache和32k数据cache。
因为要测量运行这给自测程序的时间花销,因此我们使能一个内核计数器,然后在每个测试子项的开始复位该计数器,在测试子项结束后把当前计数器的值,记录到全局变量的时间戳数组中。最后在6个测试子项都完成后,根据时间戳数组里记录的值,和当前内核运行频率,转换成时间花销。
由于场景1,是最普通的用法,即程序运行在片上flash,因此它的链接文件就是stm32cube包中的缺省配置。我这里以iar为例,展示了这个测试场景下,code的存放地址,包括复位和中断向量表的存放地址。
第二个场景,自测程序运行在外部flash。而stm32是不能从外部flash启动的,我们按照常规的做法,从片上flash首地址启动,因此在片上flash我们放一个bootloader。它的功能很简单,就是初始化ospi接口,并把它配置到memory-map模式。然后调整堆栈指针sp,以及pc指针,跳到0x9000 0000开始的ospi 外部flash首地址运行。而那里,则是我的crypto自测程序。
在场景2的自测程序工程crypto_selftest_ext_plain中,和之前的工程相比,只需要稍微做两处修改。链接文件,把复位和中断向量表放到0x9000 0000的地方,并且调整内核寄存器的vtor值。这样子,一旦有任何中断或者异常,都是去位于0x9000 0000处的向量表取执行地址。
第三个测试场景,boot loader工程相比第二个测试场景中,需要增加对otfdec的配置。而烧录在0x9000 0000的内容,应该是从场景2下第二个工程生成的project.bin,加密后的密文。这里,左边的bootloader里是otfdec在解密,右边是通过pc端工具预先把代码做加密。
由于是aes是对称加解密算法,因此otfdec的加密参数配置,要和pc端加密工具的参数一致。
我们先来设置otfdec的解密参数,密钥key和初始向量iv。
密钥由用户自己指定,在代码里我们设置在key数组中。按照数组的写法,考虑到arm cortex-m内核是小段对齐,因此这16字节的密钥,在memory中的存储顺序,应该如左下图所示。注意,我这里刻意让16字节的密钥中,每个字节的内容都不一样。为什么?我们接下来看。
otfdec的iv,hal驱动封装了一个结构体给用户来填写。由nounce,otfdec将要作用的外部flash地址范围,以及将要存放在外部flash那个地址范围里代码的版本号。nounce,也是由用户自己设定,我这里仍然刻意让8个字节的内容都不相同。
接下来我们要配置pc端加密工具的参数了。这里我们使用openssl。
在otfdec的解密密钥设置好了之后,我们在openssl中使用的密钥要以字节为单位,在16个字节的范围内,头尾交换一下。但是注意,字节里面的bit顺序不变,也就是每个字节的值不变,只是换了新的位置。这就是为什么我前面故意把otfdec的密钥中,16个字节的内容每个字节值都不一样,就是为了方便比对每个字节的移动位置。
为什么要这样调换,这是因为otfdec电路设计造成的,我们没有必要去追究原因,知道在这样的设计下,我们该怎么做就可以了。
大家注意胶片里贴出来的openssl的命令,-k字符后跟着就是密钥,这是以字节为单位的字节串。也就是说第一个字节是0x9a,接着的字节分别是 0xbc, 0xde,和胶片中下面的表格中字节顺序排列一样的。
然后来看iv。
otfdec的iv,我们在代码中,给hal驱动封装出来的otfdec_regionconfig结构体每个成员赋值好了之后。这个iv在使用openssl的时候,又需要做怎样的调序呢?如图所示:第一个32位的字,来自nounce[1]。这个4字节组成的32位字里面,字节顺序也是依次头尾交换了一下。第二个32位字,来自nounce[0],字节调位顺序也是一样。第三个字的高2位字节来自version,字节调位顺序和前面一样。第四个32位字来自起始地址的移位和regionid的拼接。
大家注意胶片里贴出来的openssl的命令,-iv字符后跟着就是初始向量,这也是以字节为单位的字节串。也就是说第一个字节是0x13,接着的字节分别是 0x57, 0x9b,和胶片中下面的表格中字节顺序排列一样的。
openssl命令的密钥和iv输入的内容确定了,还有一件很重要的需要调整的事情:otfdec将要解密的对象。
它并不是直接的把明文代码project.bin,使用openssl按照前面的参数加密就好了。仍然是由于不同aes运算工具对字节排序的不同,需要做手动调整。这里我们使用pc端的脚本工具,srec_cat先做输入字节流的填充,然后使用xxd工具,对字节顺序做调整。调整的规则和前面的密钥是一样的,即,对每16字节的内容:在16个字节的范围内,头尾交换一下,字节里面的bit顺序不变,也就是每个字节的值不变,只是换了新的位置。经过调序后的字节流再送到openssl做加密,密文同样还要经过一次相同规则的字节调序,才得到最终可以烧写到片外flash(0x9000 0000),由otfdec做实时解密的加密代码。
打开cmd命令窗口,切换到在这个文档配套的参考例程包里的utilities/exttools目录下,依次输入前一页胶片里的命令,得到预处理阶段的最后输出,即project_pad_pre_enc_post.bin。
我们可以使用stm32cubeprogramer来验证otdec配置好了之后,从0x9000 0000的地方看到的就是明文代码的样子。
验证步骤请参照胶片中的指示。
接下来我们让板子脱机运行,把场景3运行起来。从板载的lcd屏幕可以看到自测程序完成后,打印出来的时间花销。
根据我复位的时候是否按下用户按键,可以展现使能cache和不使能cache的效果。
从total time cost这一行可以看出,不是能cache,执行时间要8秒;而使能了cache,执行时间只要0.2秒。
我们再把场景1和场景2下,启动工程和自测工程下载到板子上分别运行,再记录各自的时间花销。
图中红色数字是未开cache的情况,绿色数字是开启cache的情况。
结论
可以得出结论:代码运行在外部flash的时候,运行明文和使用otfdec运行密文,效率相差无几;要提高代码运行在外部flash的效率,主要加速措施是使能内核自动的cache。
文章出处:【微信公众号:stm32单片机】


TXGA混合型D-sub连接器,为超高速轨道列车实现稳定的高质量信号传输
首款消费者版本VR手套即将面世 在VR里随你摸
5G对消费者意味着什么?中国5G通信技术发展阶段总览
电气守护者:揭秘TVS二极管的神奇力量
未来的区块链技术会对电商有怎样的影响
OTFDEC硬件模块基于STM32H735G-DK板的验证研发
OneMO模组说:Cat.1行业市场大有可为!
一位野生程序员的真实经历
多功能全天候歼-16战斗机阵容不断扩大,或将投入战斗
三星发布首款集成5G的处理器Exynos 980,用8nm工艺打造
电池故障集中爆发,整车企业质保服务有何保障?
电动机2地控制电路图
全球万物互联将从Powered by Ayla开始
辟谣4G:规模商用除了牌照还需更成熟网络
我国核电机器人发展现状及未来趋势分析
英创信息技术EM9x60主板串口的RTS硬件方向控制方法
华为高管解读全球策略:以研发消灭批评与谣言
沃尔玛正在利用区块链来跟踪公司供应链中的产品
食品检测实验室仪器设备的产品性能介绍
空调内机发出哒哒声到底怎么回事