1. 程式人生 > >基於Unique ID的微控制器程式加密系統 微控制器唯一ID程式加密

基於Unique ID的微控制器程式加密系統 微控制器唯一ID程式加密

文章原始地址:http://feotech.com/?p=25

基於Unique ID的微控制器程式加密系統 微控制器唯一ID程式加密

微控制器一般作為一個產品的邏輯中心,工作時一直在進行著邏輯判斷與執行操作,相當於人類的大腦。微控制器可以通過修改程式來控制外圍電路的工作狀態,從而改變產品的功能。如果一個產品具有微控制器,那麼它往往是這個產品的核心。而開發一款功能複雜且成熟的產品所需要的費用不低並且研發週期較長,一些個人為了某些原因,為了快速仿造競爭對手的產品,一般就原樣照抄對方的硬體電路,但由於微控制器內部有針對產品功能單獨設計的程式,不能直接再市面上購買,所以就只能想辦法通過特殊的解密方法將微控制器內部的程式讀取出來。將解密後讀取出來的程式燒錄在新的晶片中從而完成產品功能的抄襲。通過專用的裝置和工具,利用微控制器晶片設計上的硬體漏洞或軟體缺陷,通過多種技術手段獲取微控制器內程式這叫做微控制器解密或微控制器破解。以不正當方式獲得其他公司或個人的商業祕密,是一種常見的不正當競爭行為。微控制器加密技術是對產品智慧財產權保護的一種技術手段。

Unique ID加密原理

當前市面上的微控制器資源中大多數具有Unique ID,即每一個晶片內部均具有唯一的晶片ID號。不同的晶片廠家實現該功能的方式不同,一些用生產線的流水號,另一些是用晶圓的特性來生成ID。 利用Unique ID加密的方法流程如下:

微控制器一般作為一個產品的邏輯中心,工作時一直在進行著邏輯判斷與執行操作,相當於人類的大腦。微控制器可以通過修改程式來控制外圍電路的工作狀態,從而改變產品的功能。如果一個產品具有微控制器,那麼它往往是這個產品的核心。而開發一款功能複雜且成熟的產品所需要的費用不低並且研發週期較長,一些個人為了某些原因,為了快速仿造競爭對手的產品,一般就原樣照抄對方的硬體電路,但由於微控制器內部有針對產品功能單獨設計的程式,不能直接再市面上購買,所以就只能想辦法通過特殊的解密方法將微控制器內部的程式讀取出來。將解密後讀取出來的程式燒錄在新的晶片中從而完成產品功能的抄襲。通過專用的裝置和工具,利用微控制器晶片設計上的硬體漏洞或軟體缺陷,通過多種技術手段獲取微控制器內程式這叫做微控制器解密或微控制器破解。以不正當方式獲得其他公司或個人的商業祕密,是一種常見的不正當競爭行為。微控制器加密技術是對產品智慧財產權保護的一種技術手段。

Unique ID加密原理
當前市面上的微控制器資源中大多數具有Unique ID,即每一個晶片內部均具有唯一的晶片ID號。不同的晶片廠家實現該功能的方式不同,一些用生產線的流水號,另一些是用晶圓的特性來生成ID。 利用Unique ID加密的方法流程如下:

A. 將微控制器燒錄程式A後上電執行程式,完成加密操作。
B. 將微控制器燒錄程式最終程式B,該程式包含ID識別部分。 加密流程圖如下:
這裡寫圖片描述

  • 程式A負責讀取晶片內部的Unique ID,並進行加密運算。將運算的結果寫入晶片內部的EEPROM。
  • 程式B是實現產品最終功能的程式,該程式其中加入了產品身份識別功能。該程式首次上電後將首先讀取EEPROM資料,並進行與加密演算法相同的逆向演算法,將加密後的資料進行解密獲得晶片Unique ID。將解密後的ID與當前晶片的ID進行比對,如果資料不同則判斷為非法程式。

加密演算法

為了防止破解者通過模擬的方式找到晶片ID資訊,一般不宜直接存放ID號。而是經過相應的加密處理後寫入儲存器中。校驗方式也不宜採用常見、簡單的校驗規則,應儘可能採用某些特殊的檢驗方式,使破解者不能迅速確定校驗演算法。
加密的演算法類似數學公式 Y=F(X) 其中Y為加密以後的資料,X為原始資料,而F則為加密演算法。
加密演算法有很多種,本實驗中採用簡單的位移後取反的方式來進行資料加密。

這裡寫圖片描述
最後將加密的資料存入EEPROM中,由於晶片的ID廠家不允許更改,這大大增加了破解難度,加強了對產品的保護。

詳細設計過程
使用Unique ID對微控制器程式加密功能的實現需要以下幾點功能:
① 實驗板1用於對程式加密實驗。
② 將從實驗板1中讀取到的資料燒錄到實驗板2中,通過實驗板上的LED狀態驗證程式加密是否成功。
基於Unique ID的微控制器程式加密分為2個程式,這2個程式是不同的。
程式A:用於讀取晶片硬體ID並進行演算法處理,將處理後的資料儲存到EEPROM中。
程式B:用於將EEPROM中的資料讀取出來並使用與加密相同的演算法進行解密獲得晶片ID,將解密後獲得的ID與晶片本身的ID進行比較。比較結果只有2種可能,即為相同與不同,程式根據結果從而執行不同的操作如圖所示;

這裡寫圖片描述
實驗中使用STM8S微控制器作為硬體載體

軟體設計

系統初始化函式選擇了內部16MHz時鐘源,1分頻後系統匯流排時鐘頻率為16MHz。
將GPIO與EEPROM擦寫均進行了初始化配置。 函式程式碼如下:

void SystemInit(void)
{
    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);    //總時鐘源 使用內部時鐘源1分頻 16M/1分頻 =16MHz
    Gpio_Init(); //微控制器系統GPIO初始化 FLASH_DeInit();//儲存資料的EEPROM初始化
    FLASH_SetProgrammingTime(FLASH_PROGRAMTIME_STANDARD);// 預設的EEPROM寫入時間
}

LED驅動程式

根據硬體的電路原理圖可以看出,LED連線到PE5引腳。採用灌電流驅動,當引腳為低電平時LED點亮,引腳為高電平時LED熄滅。上電後LED預設為熄滅狀態,所以引腳初始化配置為高速輸出模式高電平。函式程式碼如下:

/*描述:MCU外圍GPIO初始化*/
/*輸入:無*/
void Gpio_Init(vod)
{
    //功能引腳上電初始化,引腳初始化狀態根據外部功能而定義//
    GPIO_Init(GPIOE, GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_FAST); //LED
}

LED的狀態採用巨集定義方式,直接控制IO管腳電平狀態。 操作程式碼如下:

/*LED操作巨集定義*/
#define LED_ON GPIO_WriteLow(GPIOE, GPIO_PIN_5); //點亮LED
#define LED_OFF GPIO_WriteHigh(GPIOE, GPIO_PIN_5); //熄滅LED

獲取Unique ID程式

STM8S105K4T6資料手冊顯示該晶片具有96bit Unique ID,96bit/8=12byte。存放ID的起始地址為0x48CD,從該地址讀取12次,將晶片ID獲取並存入陣列。 函式程式碼如下:

/*描述:獲取晶片ID*/
/*輸入:存放晶片ID的陣列*/
/*輸出:無*/
/*引數:無*/
void Get_ChipID(unsigned char *p)//Get chip ID
{
    unsigned char i=0; for(i=0; i<12; i++) //讀取12次
    {
        *p = *(u8*)(0X48CD+i); //將資料讀出後進行存放
        p++;
    }

獲取Unique ID程式

STM8S105K4T6資料手冊顯示該晶片具有96bit Unique ID,96bit/8=12byte。存放ID的起始地址為0x48CD,從該地址讀取12次,將晶片ID獲取並存入陣列。
函式程式碼如下:

/*描述:獲取晶片ID*/
/*輸入:存放晶片ID的陣列*/
/*輸出:無*/
/*引數:無*/
void Get_ChipID(unsigned char *p)//Get chip ID
{
    unsigned char i=0;
    for(i=0; i<12; i++) //讀取12次
    {
        *p = *(u8*)(0X48CD+i); //將資料讀出後進行存放
        p++;
    }
}

加密演算法程式

編碼函式執行對Unique ID進行資料演算法處理。實驗中採用的演算法為將存放Unique ID的陣列進行左移三個元素後逐位取反。將編碼後的資料存入另一個數組。
編碼函式程式碼如下:

/*描述:對晶片ID進行編碼處理*/
/*輸入:存放晶片ID的陣列;存放晶片ID編碼後的陣列*/
/*輸出:無*/ /*引數:對輸入陣列左移三次後逐位取反*/
void Encode(unsigned char *DataIn,unsigned char *DataOut)//對資料進行編碼加密
{
    unsigned char i;//陣列資料左移次數 unsigned char j;//資料位移臨時區域性變數
    unsigned char DataSwap;//搬運資料用的臨時變數
    unsigned char TempData[12];//資料處理交換變數陣列
    for(i=0;i<12;i++)//資料陣列交換
    {
        TempData[i] = *DataIn; DataIn++;
    }
    for(i=0;i<3;i++)
    {
        //陣列元素左移操作
        DataSwap = TempData[0];
        for(j=0;j<11;j++) //陣列左移搬運
        {
            TempData[j] = TempData[j+1]; } TempData[11] = DataSwap;
        }
    for(i=0;i<12;i++)
    {
        TempData[i] = ~ TempData[i] ; //對陣列資料進行按位取反
        *DataOut = TempData[i] ; DataOut++;
    }
}

解密演算法程式

解碼函式負責對從EEPROM中讀取的資料進行解碼,是編碼函式的一個逆向演算法處理。演算法為將輸入的陣列(EEPROM資料)進行右移三個元素後按位取反。示意圖如下:
這裡寫圖片描述
函式如下

/*描述:對從EEPROM讀出的資料進行解碼*/
/*輸入:存放編碼資料的陣列,存放解碼資料的陣列*/
/*輸出:無*/
/*引數:資料右移三位後按位取反(演算法)*/
void Decode(unsigned char *DataIn,unsigned char *DataOut)
{
  unsigned char i;//陣列資料左移次數
  unsigned char j;//資料位移臨時區域性變數
  unsigned char DataSwap;//搬運資料用的臨時變數
  unsigned char TempData[12];//資料處理交換變數陣列
  for(i=0;i<12;i++)//資料陣列交換
  {
    TempData[i] = *DataIn; DataIn++;
  }
  for(i=0;i<3;i++)//資料右移三次
  {
    //陣列元素右移操作
    DataSwap = TempData[11]; 
    for(j=10;j>0;j--)//陣列右移搬運
    {
      TempData[j+1] = TempData[j];
    }
    TempData[1] = TempData[0];
    TempData[0] = DataSwap;//最後一次搬運
  }
  for(i=0;i<12;i++)//對陣列資料進行諸位取反
  {
    TempData[i] = ~ TempData[i] ;
    *DataOut = TempData[i];
    DataOut ++;
  }
}

資料寫入EEPROM程式

將編碼處理後的資料寫入EEPROM,儲存器起始地址為0x000040A0,通過單位元組寫入。將12個位元組全部寫入EEPROM。函式程式碼如下:

/*描述:EEPROM資料寫入*/
/*輸入:資料來源的陣列*/
/*輸出:無*/
/*引數:無*/
void EEPROMWrite(unsigned char *p)
{
  unsigned char i;//資料交換用區域性臨時變數
  FLASH_Unlock(FLASH_MEMTYPE_DATA); //解鎖EEPROM,允許寫入資料
  while( !(FLASH_GetFlagStatus(FLASH_FLAG_DUL)) );//等待EEPROM解鎖完成
  for(i=0;i<12;i++)
  {
    FLASH_ProgramByte(0x000040A0+i, *p);//將資料寫入EEPROM,寫入儲存起始地址為0x000040A0
    while( !( FLASH_GetFlagStatus(FLASH_FLAG_EOP)) );//等待EEPROM單次寫入完成
    p++;
  }
  FLASH_Lock(FLASH_MEMTYPE_DATA); //鎖定EEPROM
}

從EEPROM讀出資料程式

程式首先需要從EEPROM中讀取加密後的資料,將資料儲存到陣列EncodeData中。程式程式碼如下:

/*描述:讀取晶片EEPROM資料*/
/*輸入:用於存放EEPROM的陣列*/
/*輸出:無*/
/*引數:*/
void Get_EEPROMData(unsigned char *p)
{
  unsigned char i=0; for(i=0; i<12; i++)
  {
    *p = FLASH_ReadByte(0x40A0 + i);//從EEPROM讀取資料
    p++;
  }
}

資料比對程式

資料比對函式負責將解密後資料與Unique ID兩個陣列的資料進行比對。該函式只有兩個返回結果,資料完全相同與不同,返回不同的值。根據不同的返回值從而判斷程式是否合法。函式程式碼如下:

/*描述:將兩個資料進行比對*/
/*輸入:要比對的資料A,要比對的資料B*/
/*輸出:比對結果 1:資料相同 0:資料不同*/
/*引數:對陣列進行按位元組比對*/
unsigned char IDCheck(unsigned char *a,unsigned char *b)
{
  unsigned char i; unsigned char Flag;//比對結果標誌 1:資料相同 0:資料不同
  Flag = 1; for(i=0;i<12;i++)
  {
    if( (*a) != (*b) ) { Flag = 0; } a++; b++;
  }
  return Flag;//返回值:比對結果標誌 1:資料相同 0:資料不同
}

資料陣列
使用陣列的儲存晶片ID與編碼加密後的資料。程式碼如下:

/*陣列定義*/
unsigned char Chip_IDData[12]; //存放晶片
Unique ID unsigned char EnCodeData[12]; //對晶片Unique ID編碼加密後的資料
unsigned char DecodeData[12]; //對晶片EEPROM解密後的資料

A程式主函式程式碼
本程式主要作用是將資料進行加密編碼處理並將結果寫入EEPROM, 程式的主函式呼叫上方的單元功能函式。

/*描述:主函式*/
/*輸入:無*/
/*輸出:無*/
/*引數:無*/
void main(void)
{
  SystemInit(); //系統初始化
  Get_ChipID(Chip_IDData); //獲取晶片 ID並存儲在陣列
  Encode(Chip_IDData,EnCodeData); //編碼運算處理
  EEPROMWrite(EnCodeData); //將編碼資料寫入
  EEPROM LED_ON; //寫入完成後點亮LED
  while(1); //軟體迴圈
}

執行該程式後,將讀取到的晶片ID資料存入陣列。通過內部編碼演算法函式將ID進行處理並寫入EEPROM。程式執行流程圖如圖所示:
這裡寫圖片描述

B程式主函式程式碼
程式B作用為對EEPROM資料讀取並進行解碼處理後判斷程式合法性。主函式程式碼如下:

/*描述:Main主函式*/
/*輸入:無*/
/*輸出:無*/
/*引數:無*/
void main(void)
{
  SystemInit(); //系統初始化
  Get_ChipID(Chip_IDData);//獲取晶片自身ID Get_EEPROMData(EncodeData);

  //從EEPROM讀取編碼後的資料 
  Decode(EncodeData,DecodeData);//將編碼資料進行解碼 //將解碼後的資料與當前晶片ID進行比對
  if(IDCheck(Chip_IDData,DecodeData))
  {
    //返回1 比對通過,晶片與ID身份識別通過
    LED_ON; //點亮LED
  }
  else
  {//比對失敗 程式非法
    LED_OFF; //熄滅LED
    While(1); //死迴圈
  }
  while(1)
  {
    ; //程式正常執行迴圈
  }
}

解碼程式為最終燒錄到晶片中的程式,產品功能也是在次此結構下開發的。程式執行後會讀取當前晶片自身的Unique ID與儲存在EEPROM中的資料。將EEPROM中的資料進行解碼後與Unique ID進行比對,當資料完全相同時判斷程式合法並執行正常程式功能,當資料比對不相同後判斷程式非法並執行相應操作。解碼程式執行流程圖如圖所示:
這裡寫圖片描述
系統測試
這裡寫圖片描述

將執行B程式後的實驗板1通過通過模擬器與電腦連線,將STVP切換到“Program Memory”選項卡後點擊“Read curren tab of active sectors”按鈕後讀取資料。在選單File->save中選擇儲存程式B。(模擬程式被解密)

將讀取的程式B燒錄到實驗板2中,觀察LED的現象。
燒錄程式B後實驗板1測試LED亮起,實驗板2測試LED未亮起。
這裡寫圖片描述
測試結果
從實驗中可以看到,實驗板二雖然燒錄了程式B,但是之前並沒有執行過程式A的加密演算法,所以程式識別出EEPROM解密後資料與晶片自身ID不匹配從而熄滅LED。
本文所設計的系統已經通過上述過程的測試,可以滿足對微控制器程式加密的功能需求。

當前加密系統中需要完善的部分
程式中僅僅有1處判斷程式合法性,一旦遭到反編譯後容易被破解
程式被判斷為非法後沒有保護操作,應加入強制擦除 Flash進行保護
程式需要燒錄2次來完成整個加密系統的流程. 應在程式中加入啟動加密條件,實現一次程式燒錄即可完成加