你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32 的加密实现

[复制链接]
STMCU小助手 发布时间:2022-1-18 19:37
目的:对运行于STM32的嵌入式代码程序进行加密
编译环境:IAR Embedded System for ARM5.5
一.STM32Flash组织
7 b, i6 T" b: S  J; b, Q1 u6 L
20131110170152250.png

2 L- W7 F. N- r6 `+ g3 c4 @
STM32的Flash包括主存储器(HD版本,512KB)+信息块。信息块包括2KB的系统存储器(用于系统自举启动代码)和16字节的选项字节(8个字节数据+8个字节数据的反码)。
二、STM32读保护
STM32读保护是通过设置RDP选项字节,然后在系统重新复位加载了新的RDP选项字节后启动的。当保护字节被写入相应的值以后:
●通过从内置SRAM或FSMC执行代码访问主闪存存储器的操作,通过DMA1、DMA2、JTAG、SWV(串行线观察器)、SWD(串行线调试)、ETM和边界扫描方式对闪存的访问都将被禁止。
●只允许从用户代码中对主闪存存储器的读操作(以非调试方式从主闪存存储器启动)。
●第0~3页(小容量和中容量产品),或第0~1页(大容量和互联型产品)被自动加上了写保护,其它部分的存储器可以通过在主闪存存储器中执行的代码进行编程(实现IAP或数据存储等功能),但不允许在调试模式下或在从内部SRAM启动后执行写或擦除操作(整片擦除除外)。
●所有通过JTAG/SWD向内置SRAM装载代码并执行代码的功能依然有效,亦可以通过JTAG/SWD从内置SRAM启动,这个功能可以用来解除读保护。当读保护的选项字节转变为存储器未保护的数值时,将会执行整片擦除过程。
●可以使用系统启动程序解除读保护(此时只需执行系统复位即可重新加载选项字节),芯片自动擦除Flash所有内容。
三.STM32的加密
1.使用系统启动程序STM32 Flash Loader demonstrator将Flash设置为读保护。
所有以调试工具、内置SRAM或FSMC执行代码等方式对主存储器访问的操作将被禁止,只允许用户代码对主Flash存储器的读操作和编程操作(除了Flash开始的4KB区域不能编程)。用户代码允许自主编程可以实现IAP或者数据存储等功能。
这样破解者将不能用调试工具、内置SRAM或者FSMC执行代码等方式读出Flash中的代码。破解者也不能使用系统启动程序读取代码,因为要解除读保护,将执行整个芯片的擦除操作。
2.主程序中使用设备ID保护
    即使将Flash设置为读保护,破解者也可以通过IAP下载自己的一段小程序,从而读出Flash中的内容。因此,还需要利用设备的唯一ID进行加密保护。在主程序中,加入对设备唯一ID的检测,这样即使破解者读出了芯片中的二进制码,也不能用这个二进制码去复制新的器件。具体实现方法:
    (1)在应用程序中定义1个(32位甚至更多)const变量,变量值全为0xFF。每次启动程序时,检查const变量值如果全为0xFF,就读器件的唯一ID,通过Flash编程写入该const变量中(因为全是0xFF,所以可以编程写入)。
    (2)在程序中多个地方检查const变量,如果变量值不为0xFF并且与设备ID不一致,就执行与功能无关代码(比如自擦除)。
    这样,即使破解者读出了芯片中的二进制码,因为这份二进制码包含了设备唯一ID,具有唯一性,所以不能复制到其他芯片中。
    为了避免破解者利用反汇编,根据芯片ID数据在二进制文件中查找对应相同数据的位置从而破解,可以将ID拆散成不同的组合,并且写到不同且不连续的地方。更进一步,可在程序中检测多份这样的分散ID,以增加反汇编的难度。或者将CPUID进行加密,Flash中存储加密后的结果。
四.程序加密的实现

+ N, |% e! i: c4 n1 G1 _9 p% R0 s

+ d. w3 Q0 {% d. A$ C$ B! B
  1. //加密后的CPUID  $ ?, Z4 l  V: ^% {% u- z% V
  2. volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;  ( M2 r/ V0 y; e9 g( c
  3.   
    , x+ G; N  g8 X2 Q6 P6 {# D  Q
  4. //写入加密数据  
    3 H* W$ U5 k- q3 F2 h" m. f( X% M, V
  5. void WriteEncrypt(void)  6 p* E7 f0 q( a
  6. {   
    6 f) W% a, x' o0 o7 e% v
  7.     //第一次烧写:将UID写入到Flash中  0 d# \/ v4 ?, W) ^1 m3 w) ^
  8.     if(CPUIDEncrypt==0xFFFFFFFF)  
    9 x2 o3 [# _8 e) x8 U
  9.    {  ) A! l) ~6 n) U) \" K' M1 G3 B
  10.         uint32_t CpuID[3];         
    1 j+ w) q5 w( m2 b
  11.         //获取CPU唯一的ID  ' s3 ~8 S7 ~2 C* r' l- ?
  12.         CpuID[0]=*(vu32*)(UID_BASE);  
    # @6 I5 h3 r4 F8 [5 a1 i* i. ?
  13.         CpuID[1]=*(vu32*)(UID_BASE+4);  
    # h2 [$ y6 i/ v  z* }$ Z6 x
  14.         CpuID[2]=*(vu32*)(UID_BASE+8);         
    " U+ U4 j# ~, U1 L, M" v: ?
  15.   
    ; p- |! X2 x6 ^' p. F( u9 F
  16.         //加密算法,很简单的加密算法  
    9 D! d' W  k: ]1 A! g
  17.         uint32_t EncryptCode=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);     % d0 Q0 ?# k9 ^3 _* D
  18.         FLASH_Unlock();  . C" ]9 |6 t) Q* R6 J
  19.         FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);  
    - h. D' n! O1 [( c5 u6 f/ ^
  20.         FLASH_ProgramWord((uint32_t)&CPUIDEncrypt, EncryptCode);  * b$ s" t0 K) L) }( v0 m4 ^6 _
  21.         FLASH_Lock();  
    ! F, T* R) P5 b
  22.     }  
    2 u: N# K, w* q2 I
  23. }  3 _6 M2 i; t& d
  24. //判断加密  
    - W1 v' ]9 F  @9 o
  25. bool JudgeEncrypt(void)    o: a6 v( N1 Q% X  G" O. D
  26. {         
    - c9 s4 d9 T8 A+ v/ g+ d& ?7 V
  27.     uint32_t CpuID[4];         : j2 G* x# x; R9 q+ ^* N
  28.     //获取CPU唯一的ID  
    5 }3 ]! ~2 s/ g; g
  29.     CpuID[0]=*(vu32*)(UID_BASE);  5 f: A2 s. B" k/ t
  30.     CpuID[1]=*(vu32*)(UID_BASE+4);  6 ~0 x8 R/ D4 E( _8 z" r
  31.     CpuID[2]=*(vu32*)(UID_BASE+8);      
    ! Z. h" L$ o9 `5 c7 @! `
  32.     //加密算法,很简单的加密算法  4 t4 @% v1 o' w' E; u0 }% e4 K8 C
  33.     CpuID[3]=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);     
    0 v9 S/ e( R( q1 c6 G. U
  34.     //检查Flash中的UID是否合法   ' o' F1 J3 k# l
  35.     return (CPUIDEncrypt == CpuID[3]);  2 a8 P5 v) s( A9 k$ `" r: l$ }
  36. }
复制代码
4 O3 c2 d7 @7 @2 y; F/ e9 k3 [

) I0 w% D4 i6 R/ c) ^
1、将写入加密数据和判断加密两个功能分开。写入加密在PrsCtrlTask开始的地方;而判断加密分布到程序的各个角落。
2、非常重要的是CPUID加密值的定义一定要加“volatile”类型:
volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;
否则按速度优化编译,在判断加密值,不会重新读取加密值,导致判断出错。
3、在工程选项Options->Debugger->Download中选择: use flash loader
否则主程序中对Flash编程将不成功。
% E+ p8 j1 }  H, ^; `8 D
收藏 评论1 发布时间:2022-1-18 19:37

举报

1个回答
立码赚 回答时间:2023-3-14 10:57:00
[md]STMCU小助手

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版