前段時間由於應用需要對產品授權進行限制,所以研究了一下有關STM32 MCU的唯一ID的資料,並最終利用它實現了我們的目標。
1、基本描述
在STM32的全系列MCU中均有一個96位的唯一設備標識符。在ST的相關資料中,對其功能的描述有3各方面:
- 用作序列號(例如 USB 字符串序列號或其它終端應用程序)
- 在對內部 Flash 進行編程前將唯一 ID 與軟件加密原語和協議結合使用時用作安全密鑰以提高 Flash 中代碼的安全性
- 激活安全自舉過程等
在資料中對其特性的描述是:96 位的唯一設備標識符提供了一個對於任何設備和任何上下文都唯一的參考號碼。用戶永遠不能改變這些位。96 位的唯一設備標識符也可以以單字節/半字/字等不同方式讀取,然后使用自定義算法連接起來。
想要讀取唯一ID,就需要知道它的存儲地址,在不同系列的MCU中地址是有差別的,我們查詢了部分MCU的資料並將其總結如下:
2、獲取唯一ID
前面我們對唯一ID做了簡單的描述,並且得到了其存儲地址,接下來我們說以說如何得到這個ID。
前面已經描述過唯一ID可以按字節、半字、字等方式讀取。唯一ID是一個96位的信息串,所以按字讀取就是3個字,按半字讀取就是6個,按字節讀取就是12個。本質上沒有區別,在這里我們按字讀取。
1 /*定義STM32 MCU的類型*/ 2 typedef enum { 3 STM32F0, 4 STM32F1, 5 STM32F2, 6 STM32F3, 7 STM32F4, 8 STM32F7, 9 STM32L0, 10 STM32L1, 11 STM32L4, 12 STM32H7, 13 }MCUTypedef; 14 15 16 uint32_t idAddr[]={0x1FFFF7AC, /*STM32F0唯一ID起始地址*/ 17 0x1FFFF7E8, /*STM32F1唯一ID起始地址*/ 18 0x1FFF7A10, /*STM32F2唯一ID起始地址*/ 19 0x1FFFF7AC, /*STM32F3唯一ID起始地址*/ 20 0x1FFF7A10, /*STM32F4唯一ID起始地址*/ 21 0x1FF0F420, /*STM32F7唯一ID起始地址*/ 22 0x1FF80050, /*STM32L0唯一ID起始地址*/ 23 0x1FF80050, /*STM32L1唯一ID起始地址*/ 24 0x1FFF7590, /*STM32L4唯一ID起始地址*/ 25 0x1FF0F420}; /*STM32H7唯一ID起始地址*/ 26 27 /*獲取MCU的唯一ID*/ 28 void GetSTM32MCUID(uint32_t *id,MCUTypedef type) 29 { 30 if(id!=NULL) 31 { 32 id[0]=*(uint32_t*)(idAddr[type]); 33 id[1]=*(uint32_t*)(idAddr[type]+4); 34 id[2]=*(uint32_t*)(idAddr[type]+8); 35 } 36 }
3、使用唯一ID
我們得到唯一ID當然是為了使用它,前面在ST資料中描述了三個使用方式。我們在這里來使用它實現軟件權限的限制。那么如何用唯一ID來實現軟件運行權限的限制呢?我們說一說思路:
首先,我們需要指定一個Flash地址,至於於地址空間的大小則與我們需要存儲的信息有關,一般都不會太長。例如,我們使用MD5來生成加密信息,則最多需要16個字節的存儲空間;如果我們使用SHA1來作為生成算法,則最多需要20個字節的空間。當然,我們也可以選取其中的一段或幾段。不管選用多大的空間都需要將其清零,即初始化為0xFFFFFFFF。
接下來在程序運行前讀取前面指定的地址並讀取其值,並判斷是否全部為0xFFFFFFFF,即判斷程序是否第一次運行。如果是,那么就獲取唯一ID並作相應的處理,然后將信息寫入前面指定的地址中。
如果不是第一次運行,則讀取指定地址的值,並用同樣的算法處理唯一ID。然后比較存儲的信息與計算的信息是否一致,一致則啟動程序運行,不一致則終止運行。
如果有人使用工具讀出FLASH內容時,因為該指定的地址已經被寫入了信息,所以如果把讀出的文件再燒到其它MCU芯片,因唯一ID不同所以信息完全不符,程序就不會運行。從而實現了對程序權限的限制。
歡迎關注: