打印
[STM32L5]

STM32L5 进阶课程 11. OTFDEC,无缝扩大代码的安全存储空间

[复制链接]
1173|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
powerantone|  楼主 | 2023-11-27 15:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

欢迎大家继续关注STM32L5 线上课程第二季。这一集,我们介绍STM32L5上首次集成的安全应用外设:OTFDEC,英文全称是 on the fly decryption。顾名思义它是一个解密模块,并且是on the fly的。这个on the fly怎么理解,我们后面会详细介绍。


OTFDEC模块的集成,可以让客户把大段用户代码加密后放在外部Flash,从而保护敏感代码的机密性。


通过对OTFDEC的正确配置,从外部Flash执行代码,对CPU来说就像是执行片上Flash里存储的明文代码一样。这样,代码安全存储的范围,就可以从片上Flash扩展到安全的片外做存储和执行,突破了STM32L5 512K片上Flash的容量限制。

OTFDEC作为一种加解密引擎,和AES、PKA一样,只在L562系列中,L552系列没有。


所以这一集和下一集介绍PKA,动手环节我们会基于搭载STM32L562的L5-Disco板子,而不是以前使用的STM32L5 Nucleo板,后者搭载的是L552系列。课程用到的板子,都可以在STM32官方天猫旗舰店购买。

说OTFDEC是AHB总线上的外设,是从CPU访问它的寄存器角度来说的,比如配置它的工作模式,比如使用它的加密功能,都要操作它的寄存器。


当TZ=0时,OTFDEC就是一个普通的外设;当TZ=1时,OTFDEC就是一个secure外设,注意,不是securable外设,是secure外设:此时,OTDEC的寄存器只能被安全状态的CPU去配置,或者说只能被安全应用去配置。


从功能角度来说,OTFDEC的初心,就是让CPU可以执行存储在外部memory’的加密代码。以前的STM32,通过FSMC或者SPI外扩的nor flash,也可以存储代码,CPU从外部存储区执行。但是如果外部存储区里放的是密文,需要CPU先使用数据读访问来把二级制代码load到片内,解密后才可以执行。并且,即使外部存储区存放的是明文代码,FSMC和SPI的带宽限制,已经AHB总线矩阵引入的额外延迟,都会使执行代码的速度受到限制。


现在的OTFDEC充分解决了以上两个应用中的痛点:一旦配置完成,它可以对外部Octo-SPI Nor Flash上的密文代码实时解密,对CPU的执行来说可以说是透明的。此时它的逻辑位置,如图所示,是位于OctSPI外设模块和MPCWM功能单元之间。在它的实时翻译下,CPU从外部memory读取密文数据、取指密文指令,就跟CPU在读取和执行片内Flash的明文数据和代码一样,不要去先执行外部flash驱动把数据读出来,再做第二步的解密,因此叫做“on the fly decryption”。另外一方面,在ICACHE的作用下,从外部memory执行指令,可以被缓存,加速了代码的执行。


OTFDEC作为加解密引擎,工作于解密模式时,支持标准AES-128的counter模式。每个数据块的解密是独立的,和前面的数据块没有耦合关系,因此适合在线实时解密。


那么说到这里,大家应该也能猜到,OTFDEC也可以工作在加密模式。没错,OTFDEC也可以工作在加密模式。此时,不仅支持·标准AES 128的counter模式,还支持标准AES之上的ST私有算法。但是,加密操作时,OTFDEC不是on the fly的:此时OTFDEC模块的输出,是和OctoSPI模块断开的。


就是说,OTFDEC的输出密文,是放在用户指定的栈空间的某段区域,不是直接能写到外部存储区的,需要用户代码再调用外部memory的驱动,把密文从栈空间写过去。这是初次使用OTFDEC模块,大家容易混淆的地方。其实,顾名思义,之所以叫做“OTFDEC” ,说明它只能on the fly地dec,而不能on the fly的enc。

接下来看一下OTFDEC模块自身的功能框图,借此理解一下OTFDEC模块实时解密的工作原理。


它对从AHB总线过来的读外部memory请求进行分析,如果请求的地址,位于用户设置的需要OTFDEC管理的四个区域范围之内,控制逻辑就会触发一个该区域对应的密钥流参与的AES counter模式计算,来把OCTO-SPI模块从外部memory读上来密文,转化成明文,返回给CPU。如果请求的地址,不在OTFDEC负责的四个区域之内,加解密模块不参与计算,数据就直接返回给CPU。


OTFDEC可以管理外部Octo-SPI flash上多达4个区域。每个区域,以4M字节为粒度,OTFDEC可以使用独立的密钥对其管理,由用户配置。密钥寄存器具有只写,而不可读属性。并且当检测到入侵事件或者RDP回退事件,硬件会自动把密钥寄存器全部擦除。每个区域密文解密时使用的nounce、存储的固件版本信息,也是由OTFDEC独立管理。


OTFDEC工作在加密还是解密模式,属于一个全局属性,因为OTFDEC就一个加解密硬件引擎;当加密或者解密工作模式确定后,OTFDEC管理的四个区域,又可以有独立的“区域工作模式”,它和模块的工作模式是两个概念。


模块工作模式,属于全局控制,在CR寄存器宏的ENC位域来管理。复位缺省值0,表示OTFDEC工作在解密模式。


在胶片中我们用黄色来标注。区域的工作模式,是局部控制,在RxCFGR,region configuration register中由MODE位域来管理,表示当前使用的加解密算法是标注AES-128, counter模式,还是基于此的ST私有对称加密模式。


模块工作模式,和区域工作模式,是正交的。


由此可以产生四种组合。


ENC缺省状态下,ok处于解密模式,可以实时对Octo-SPI memory上来的密文进行解密。该工作模式下,用户需要把外部memory配置成memory‘ map’模式。当MODE=10,使用标准AES算法解密,CPU可以直接读取外部memory上的密文数据,也可以直接取指外部memory上的密文指令。我们在后面的第一个动手操作环节来体验。 当MODE=11,使用ST私有AES算法,就不支持CPU对外部memory上的密文数据直接读取,仅支持指令执行。


ENC=1时,模块工作于加密模式。加密得到的数据不会被自动写到外部memory,而是写到内部RAM。只是不同的区域工作模式MODE下,模块会使用不同的加密算法而已。


以胶片中的示意图来理解,如果我要使用OTFDEC的加密功能,需要把ENC置为1,通过AHB写操作把明文,以及该数据对应的密文要放置在外部memory的位置,一起喂给OTFDEC,然后生成的密文,会被输出到芯片内部RAM由用户指定的地方。这个密文,是和目标地址绑定的。就是说同样一段明文,放在不同地方,它的密文是不一样的。密文有了后,再由用户调用外面flash的驱动,去把密文数据写进去,就是图中虚线表示的操作。


假设外部memory现在已经有一段密文区域,一段明文区域。我现在要使用这些内容,无论是数据还是指令。我要把ENC复位,让模块工作于在线解密模式。还要记得把memory配置成memory map。然后我就可以使用地址来直接使用这些外部memory上的密文了。如果我读取的是普通区域,不受OTFDEC管辖的区域,其数据会直接返回,就像中间这条蓝色的线一样;如果我读的是受OTFDEC管辖的区域,里面的内容会经过OTFDEC的解密引擎,输出明文给到CPU,就是图中下面红色的线条。


刚才说,同一段明文,放在外部memory上的不同位置,对应的密文还是不一样的。这是由OTFDEC里的AES加解密硬件引擎决定的。从上图可以看到,一段16字节的输入,是如何转变成密文的。左边的AES_DIN(cipher text 0 )看做第一个16位明文,它要放在外部memory某个受OTFDEC管辖的区域首地址,address0。按照标准AES的操作流程,密钥key先和初始化向量做块加密。初始化向量,有该区域的nounce、该区域存储固件的版本号,以及此次明文要放置的外部memory的地址组成。计算得到keystream,大概需要11个时钟周期,然后再和明文进行异或,生成密文。



使用特权

评论回复
沙发
powerantone|  楼主 | 2023-11-27 15:56 | 只看该作者

结合下面的时序图来看。当第一个地址address0出现在HADDR信号线时,黄色的keystream0就开始进入计算周期了,经过11个周期后,keystream计算完成就绪,可参与和输入明文的异或,那么一个时钟周期后,异或的结果,就是密文就一个word一个word的出现在HRDATA线上了。可见,从读、写访问里的地址信号,到实际数据结果就绪,需要差不多12个时钟周期的延迟,这段时间内HREADY信号是被OTFDEC拉低的,因为OTFDEC模块没有数据可以传输。对下一个16字节数据块的加密,由于将要存放的地址不同,address_1,需要的keystream也不同,需要重新计算。


但是由于我们有keystream buffer,在第一批16字节数据产生并输出的时间内,OTFDEC可以开始产生下一个keystream了,就是图中绿色的部分。这样,当第一批数据输出后,keystream1也计算完毕,那么第二批密文,也可以一个word一个word地出来了。

有了关于OTFDEC初步的一些理论知识,我们在继续深入下去之前,先来运行第一个示例代码,体会一下OTFDEC最基本的一个功能:对存储在外部memory的加密数据和加密代码,实时的在线解密使用,体会一下怎么个“on the fly”法。


我们使用STM32CubeL5固件包里,L562-DK板子下的两个例子。DataDecrypt,是对外部密文数据直接使用;


ExecutingCryptedInstruction,是对外部密文代码直接执行。


在这两个例子中,都是先把预先准备好的密文,使用普通的方式,调用外部memory驱动写进去。然后OTFDEC粉墨登场,我们对它做适当的配置。配置好了以后,CPU就可以直接使用外部的这些数据和代码了,就跟使用片内Flash的明文数据和明文代码一样。


我们先来运行一下例程。


接下来我们再看看,OTFDEC在TrustZone环境下的使用。


TZ=0时,OTFDEC就是一个普通的外设;当TZ=1时,OTFDEC是一个secure外设,它的寄存器只能被安全世界代码访问,因此它只能被安全世界代码来配置。但是,一旦配置完成,无论是安全世界代码,还是非安全世界代码,访问Octo-SPI片外Flash时,如果目标地址是在被OTFDEC管辖的区域里,都可以享受OTFDEC模块的实时on the fl地y解密服务。


在TrustZone环境下,对存储区进行访问,访问规则是一直要特别需要注意的。Octo-SPI片外Flash区域的安全属性由MPCWM来控制,缺省状态片外memory都是安全的,只能由secure trasanction访问;用户可通过选项字节的MPCWM以water mark的方式,划分出部分非安全区域,来被non secure transaction访问。所以,当非安全代码要想访问到外部Flash的安全区域,必须通过安全世界通过NSC区域暴露出来的API调用,切换到安全世界,发出secure transaction,才能完成。


一旦访问请求通过了内核的IDAU/SAU第一级检查,也通过了GTZC模块中MPCWM子模块的第二级检查,对片外Flash的密文访问,就可以享受OTFDEC的实时解密服务,无论此时这个访问是一条secure transaction,还是一条non secure transaction。

之前我们一直在讲OTFDEC模块的缺省全局工作模式,解密功能,这是它的初心不假。OTFDEC也是一个斜杠青年,它也可以工作在加密模式。AES属于”对称“加密技术,加密操作和解密操作是对称的,因此对于OTFDEC模块的加解密硬件引擎来说,这两种操作完全一样。但是我们作为用户有一点一定要注意的就是,前面也提过多次,当OTFDEC模块工作于加密模式,它的输出和Octo-SPI是断开的,就是说经过它加密后的密文,并不是直接被写到了外部memory里,而只是输出到RAM中由用户指定的地方。


密文生成后,用户要自己调用Octo-SPI flash的驱动来把密文数据写到外面flash中。整个过程,凡是涉及到对OTFDEC寄存器的操作,在TZ=1环境下,必须都得由安全代码来执行。


至于从用户角度如何来使用OTFDEC的加密功能,设置了模块全局工作模式,ENC=1,之后需要把明文数据喂到哪里去,再从哪里得到加密后的密文呢?从胶片左边的流程图我们可以看到两个关键的操作步骤:写明文,读出密文。那么,到底是往哪里写?从哪里读呢?

STM32L5的参考手册上是怎么写的呢?请看胶片里下面这一段话:应用代码,把明文数据,32位32位地写到期望被保护的区域,当然这里是指的0x9000 0000开头的Octo-SPI Flash上的地址,然后从相同的地址读出来放到RAM中。那么RAM中读出来的32位数据就是加密后的密文了。


这个操作不是非常常规,L5的HAL库函数对其进行了封装,就是胶片里的HAL_OTFDEC_Cipher()。


调用这个函数做加密,用户需要提供5个参数;首先是使用的OTDEC句柄,这个没啥好说的,和任何一个外设模块的使用都是一样的;第二个参数,指定使用OTFDEC管理的哪个region。一个4个region,不同region使用的密钥是不同的;第三个和第四个参数就是明文指针,和密文将输出在RAM中的位置指针;第五个参数,这段密文拟放在外部区域的地址。我们前面在介绍AES加解密硬件引擎工作原理时就展现过胶片右边这张框图。每次16字节数据块做加密或者解密运算时,初始化向量的低位包含的就是密文所在的外部区域地址信息。


这个HAL API里的实现,就是对前一页胶片两个节点方块的解释:写明文,读出密文。往哪里写?从哪里读?就是往外部memory的地址写,再从那里读,这样一写一读,读到RAM里数据,就是加密后的密文了。

基于刚才讲的这两点,加密操作,以及OTFDEC在TrustZone环境下的使用要点,我们来运行并分析一下另外一个样例程序。


我们使用STM32CubeL5固件包里,L562-DK板子下的第三个例子。OTFDEC_Ciphering_TZ。

在实际运行之前,先简要介绍一下这个例程。中间灰色框里是上一个例程,在普通运行环境下,即TZ=0情况下,OTFDEC工作于解密模式下的操作流程。放在这里,做一个参照,看看在工作于加密模式时,用户的操作流程会有什么些许不同?并且还可以从普通运行环境和TZ=1这个角度去对比一下。


TZ环境下的应用,上电先运行安全世界里的代码:系统初始化,这次多加了一个ICACHE的使用,然后分配一个GPIO引脚到NS世界,共non secure的应用操控。然后马上把OTFDEC设置到加密模式


。这是hands on1没有的。在hands on 1里,由于已经预先准备好了密文,所以第二步是蓝色框里的,调用Octo SPI flash驱动把密文写进去。但是在我们现在这个例程中,密文需要先靠自己产生。那么就是绿色框里的,配置OTFDEC管理的某个区域,使用标准AES加解密算法,配置密钥以及其他加密需要的上下文数据。然后,就可以调用前页介绍的OTFDEC cipher API,对明文Plain[]数组内里的内容加密,并输出到Ciphered[]数组中。


加密完成后,把OTFDEC工作模式切换回默认的解密模式。然后才是蓝色方框里,调用Octo SPI flash驱动把密文写到外部flash中去。到此为止,配置OTFDEC的某个region,使用它来加密,并将密文写入外部flash,都是有安全应用完成的。接下去,跳转到非安全应用去执行。它将通过对外部memory的地址直接访问,读出明文数据。


我们来实操一下

我们看到了,在NS世界想通过外部地址直接访问,在这个例程里是通过NSC区域暴露出来的安全应用调用接口API完成的。这正是因为要遵循TZ环境下对存储区的访问规则。由于Octo-SPI外部 flash区域在缺省状态下处于Secure状态,例程里并没有通过MPCWM来改变其上某些区域的安全属性,因此Non Secure的代码是无法访问它的数据和指令的。


所以,如图所示,OTFDEC模块on the fly地开始解密时,CPU要读取0x9000 4000地址的数据,到非安全SRAM的数组中,由于源地址处于安全区域,非安全世界的代码无法访问,因此需要通过NSC API,去到安全世界来执行图中箭头表示的拷贝操作。而当切换到安全世界之后,CPU处于安全状态,读取0x9000 4000这个CPU看来的安全地址,是一个secure的transaction,因此可以触碰到这个本来物理区域属性也是安全的源地址;


访问0x2001 8010时,该地址在SAU那里已经被配置成了非安全区,因此即使此时CPU处于安全状态,发出的transaction仍然是non secure的,因此可以触碰到这个物理区域属性也是非安全的地方。所以拷贝操作可以正确执行。

进入NonSecureCallable的API后,第一件事是使用cmse_check来对从NS世界传过来的指针进行检查,传过来两个指针,一个是源地址,一个是需要写入的目的地址。是对目的地址指针进行检查。检查的不仅仅是一个指针变量,而是该指针变量和对应的拷贝长度,涉及到的一整段地址区域。


这个被写入的区域,或者说将被改写内容的区域,只能处在非安全世界,即红色的区域,不能处于安全区域,也不能跨越非安全区域和安全区域。总之一句话就是:不允许非安全应用,通过安全代码,把安全世界的区域给修改了。这是大家自己在写安全应用暴露给非安全应用的API时,一定要注意的地方。


回过头来看,这个例程给我们展现了TZ环境下使用OTFDEC的一个典型用法:密钥放在安全区域,只能由安全应用来配置;非安全世界的应用,无需密钥交换也可以享受解密服务。

经过前面两个hands on环节的三个样例程序的学习,在第三个hands on,我们自己来写一段程序,实现使用ST私有AES算法,对一段明文代码进行加密,写到外部Flash后,再使用OTFDEC的在线解密功能,实时对其取指执行。


我们使用hands-on 1里面现成的一段指令,就是执行R0+R1+15的计算。那个例程里我们可以拿到该段指令的明文,就是08,18,0f,30,70,47这六个字节。


从hands-on 2我们学习了如何使用OTFDEC的加密功能。这两个hands on都是使用标准AES算法


把这两个hands on结合起来,我们现在要做的hands on3,就是让OTFDEC先,后工作于加密模式和解密模式,对明文指令加密,写入flash后,再执行密文代码。并且,我们将改变OTFDEC加解密硬件引擎的算法,从标准AES改到ST私有AES算法。

先列一下流程图:最开始也是系统的初始化,我们可以尽量重用hands-on 1和hands-on 2的代码。使能OTFDEC模块全局工作模式为加密功能。选定一个region,配置region要管理的外部flash的地址范围、该region使用的对称加解密密钥和相关加解密上下文。


调用现成的OTFDEC cipher加密API,对6字节明文指令,转换成密文。密文生成完毕后,把OTFDEC模块的全局工作模式再切换为解密功能,配置Octo-SPI接口,把密文指令写到外部flash对应的地址范围中。通过外部flash的地址,直接做函数指针调用,来执行外部的加密指令。


在执行add15这个存储在外部flash的函数指令时,请从IDE的汇编窗口或者memory窗口去观察。你会看到,窗口里显示的不是想象中的明文二级制代码,而全部都是0。回忆一下前两个hands on环节里,在配置了OTFDEC模块的解密模式,使能了外部memory的memory map,明明都可以从IDE窗口看到明文数据或者明文代码啊?这里为什么都是0,那还能执行正确吗?


首先,在你单步执行完这个add15的函数后,可以验证一下,它确实返回了正确的累加值。然后,请想一想为什么在IDE汇编窗口看到的都是0呢?


原因就在于,我们使用的是ST私有AES算法,它的宏的名称就叫做 “instruction access only”,在L5参考手册,对应寄存器的描述之处,也写明了“只对指令访问解密”。而我们的IDE窗口去读取时,显然是数据访问,因此无法得到解密后的明文数据。

最后,我们再总结一下,OTFDEC它实际作为一个加解密硬件引擎,系统对其密钥、和所保护外部flash区域的一些系统级别保护。


首先,OTFDEC管理的每个region所使用的AES对称密钥寄存器,是只写不可读,从而保证key的机密性;为了用户确保key被正确写到寄存器里,通过密钥CRC值位域,来保证key的完整性。


当系统检测到tamper入侵事件,或者OTFDEC所管理的region的工作模式改变,密钥都会被硬件擦除。RDP降级,无论是否有TZEN,也都会把密钥擦除。


外部flash存储的密文,如果攻击者想通过调试模式、或者从ram启动注入代码,或者从系统bootloader启动,企图通过OTFDEC的解密引擎来读取,在RDP读保护非0级别下,都无法成功。


并且,系统在检测到tamper入侵事件后,无论从哪里启动,什么访问模式,什么读保护级别,也都无法通过OTFDEC解密外部flash的加密内容。


通过这一集的学习,大家应该了解并体会到:STM32L5上,OTFDEC模块的集成,可以让客户把大段用户代码加密后放在外部Flash,从而保护敏感代码的机密性。通过对OTFDEC的正确配置,从外部Flash执行代码,对CPU来说就像是执行片上Flash里存储的明文代码一样。


这样,代码安全存储的范围,就可以从片上Flash扩展到安全的片外做存储和执行,突破了STM32L5 512K片上Flash的容量限制。


这一集的内容就讲解完毕,谢谢大家观看。


使用特权

评论回复
板凳
童雨竹| | 2024-7-21 07:26 | 只看该作者

给瞬间电流提供低阻抗导通路径

使用特权

评论回复
地板
Wordsworth| | 2024-7-21 08:29 | 只看该作者

最典型的应用就是放大电路中的高低音频控制

使用特权

评论回复
5
Clyde011| | 2024-7-21 09:32 | 只看该作者

器件整合的再紧凑都无法发挥最大的效率

使用特权

评论回复
6
公羊子丹| | 2024-7-21 10:25 | 只看该作者

需要设置电压钳位电路予以保护D3、N3构成的回路

使用特权

评论回复
7
万图| | 2024-7-21 11:28 | 只看该作者

需要串联一个限流电阻在其中

使用特权

评论回复
8
Uriah| | 2024-7-21 12:31 | 只看该作者

当人接触任何东西时,体内的电荷就会放电。

使用特权

评论回复
9
帛灿灿| | 2024-7-21 14:27 | 只看该作者

有不普通的门道

使用特权

评论回复
10
Bblythe| | 2024-7-21 15:30 | 只看该作者

只能处理较小的能量

使用特权

评论回复
11
周半梅| | 2024-7-21 17:26 | 只看该作者

电路正常工作

使用特权

评论回复
12
Pulitzer| | 2024-7-21 18:29 | 只看该作者

灌封前基材外观保持清洁和干燥。将混合好的胶料灌注于需灌封的器件内

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

556

主题

2409

帖子

4

粉丝