STM32 应用程序加密的一种设计方案

0、前言

STM32编译后的代码存在FLASH中,通过外部工具可以读出来全部数据,一旦硬件抄板一样,再将FLASH数据全部拷贝至抄板单片机中,既可以完全实现硬件和软件功能抄袭。因此,需要对自己的应用程序加密,即使被抄板和读取FLASH数据,拷贝过后仍然无法执行相应的功能。【ps:没有解不开的单片机,主要看解密的经济效益】

主要思路:利用每个芯片的96位唯一ID,进行一定的计算和单向加密,得到唯一的应用AppKey并保存至FLASH,运行APP时读取该FLASH位置的AppKey,并与计算得到的AppKey比较是否相同,如果相同则正常运行,不相同则退出。

因此,在正确运行APP之前,需要保证FLASH保存有AppKey,可以在设备出厂前提前通过代码方式写入FLASH,再烧写正常的APP代码。为了减小代码烧写的工作量,采用IAP的方式实现自动出厂配置,方案包括三个工程:BootLoader,Encrypt,APP。三个工程在FLASH中的内存分配与OTA-IAP相同。

一、计算AppKey

step1 :为避免出现UID_BASE的明文,在读取UID时,对其地址进行一定的简单运算,再读取UID。

#define    ADDRSEED      (0x20170620)
#define    METHORDADDR   (ADDRSEED^1+1)
#define    METHORDEUID   (ADDRSEED|0x12345678)

volatile const uint32_t uidaddr[3] = {UID_BASE+METHORDADDR,UID_BASE+4-METHORDADDR,UID_BASE+8+METHORDADDR};

//get uid, by calc uidbase
//uid: ptr, 96byte length
static void Getuid(volatile uint32_t *uid)
{
    volatile uint32_t addrtemp;
    addrtemp = uidaddr[0] - METHORDADDR;
    uid[0] = *(volatile uint32_t*)(addrtemp);
    addrtemp = uidaddr[1] + METHORDADDR;
    uid[1] = *(volatile uint32_t*)(addrtemp);
    addrtemp = uidaddr[2] - METHORDADDR;
    uid[2] = *(volatile uint32_t*)(addrtemp);
}

step2 :对UID进一步简单加密。

//encrypt uid
//euid: ptr, 96byte length
static void Encryptuid(volatile uint32_t *euid)
{
    uint32_t uid[3];
    Getuid(uid);
    euid[0] = uid[0] + METHORDEUID;
    euid[0] ^= ADDRSEED;
    euid[1] = uid[1] + METHORDEUID;
    euid[1] ^= ADDRSEED;
    euid[2] = uid[2] + METHORDEUID;
    euid[2] ^= ADDRSEED;
}

step3 :对EncryptUID计算MD5,计算128bit单向散列值。

//generate md5 by euid
//key: ptr, 16byte length
void GenerateMD5(uint8_t *md5)
{
    uint32_t *euid;
    Encryptuid(euid);
    MD5_Init(&Context);
    MD5_Update(&Context,(uint8_t *)euid,96);
    MD5_Final(&Context,md5);
}

step4 :根据FLASH页容量大小,将MD5扩充至1024Byte,采用随机数扩充。

//generate key
//key: ptr, 1024 length, md5 extend to 1024
void GenerateKey(uint8_t *key)
{
    uint16_t i,j;
    uint8_t md5val[16];
    GenerateMD5(md5val);
    j = 0;
    for(i = 0; i < 1024; i++)
    {
        if(i%64 == 0)
        {
            key[i] = md5val[j++];
        }
        else
        {
            srand1(HAL_GetTick());
            key[i] = randr(0,0xFF);
        }
    }
}
二、自动配置流程

Encrypt工程代码只在出厂时运行一次,目的是利用UID产生AppKey,并将其提前写入指定FLASH中,因此,该段代码执行一次后将擦除。可设置Encrypt在APPA区中运行,利用IAP功能,将APPB区的APP固件在执行完Encrypt固件后,搬移至APPA区。

具体地,出厂自动配置密钥流程如下:

Step1:上电启动单片机,首先执行BootLoader程序。
Step2:BootLoader读取Parameter参数区,此时参数区设置为无升级任务,BootLoader执行APPA区的代码,进入 Step3 。存在升级任务时,执行 Step6Step7
Step3:BootLoader跳转至APPA,执行Encrypt代码,根据UID计算AppKey,执行 Step4Step5
Step4:将计算的AppKey存入Parameter区指定的位置,并写入升级标志和APPB区相关固件参数。
Step5:重启单片机,进入BootLoader。
Step6:清除升级任务标志。
Step7:拷贝APPB代码至APPA区,即擦除Encrypt代码,最后执行重启进入 Step5 ,重启后运行真正的APP代码。

三、出厂固件合并

出厂前需要在STM32中烧写BootLoader、Encrypt和APP三份Hex固件,加大了时间开销,三份Hex固件存在FlASH的不同位置,地址容易出错。因此,可将三份Hex进行合并成一个Hex,进行一次烧写,按照自动配置流程完成加密和代码搬运工作。

BootLoader工程在程序一开始运行,其地址和空间大小分配仍然按照0x08000000和20kB分配,编译生成boot.hex。Encrypt工程和APP都在APPA区运行,因此,两者地址和空间大小分配为相同的0x08005000和50kB。APP.Hex只是保存在APPB区,带加密执行完成后通知Bootloader进行搬移。

出厂固件按照boot.Hex,encrypt.Hex,app.Hex的顺序合并,打开Hex文件,分别用后一个文件的全部内容替换前一个文件的最后一行,保存为hex格式就可以。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值