H7-TOOL脱机烧录的UID加密操作方法,支持一键生成目标板C代码,方便大家轻松操作(2024-08-20,已发布)
UID加密使用比较方便,对应的C代码模板已经做好,使用TOOL上位机生成后,直接复制粘贴到自己的工程即可使用。返回1表示解密成功,返回0表示失败。
【UID加密原理】
1、烧录器在烧录芯片时,按照指定的算法将UID码编码为一个加密数据,并写入FLASH指定区域。
2、用户的程序必须增加一段UID校验程序比较UID和加密数据是否满足算法规则,不满足则停止运行或呈现随机错误。
3、用户程序只要进行了UID加密,就可以防止初级盗版者直接复制程序到其他芯片。
4、用户可以自行修改加密算法,以增加保密性。
点击上位机这个按钮可以查看了解:
【UID界面功能介绍】
1、算法公式
当前做了三个
(1)encrypt_001.lua, 这个最安全,对UID做了各种加密,当前支持的一键C文件生成也是基于这个制作,大家配置的时候要选择这个选项
(2)encrypt_copy_uid.lua, 这个最简单,就是单纯的读取UID,未对UID做加密处理。
(3)encrypt_crc32_uid.lua, 这个是对UID做了简单的CRC32方式加密。
本贴的实现是基于第1中UID加密,实际应用也推荐用这种。
2、参数名A1 -A16,每个参数值范围1 - 16
这里默认即可,一般无需修改
3、选择算法随机数
这个的对应关系是这样的, 一个选项对应一个:
4、算法函数用的常量
这里是8bit的hex,推荐配置8个值即可, 每个值范围0x00 - 0xFF
5、随机数
随机数1,随机数2,随机数3,随机数4设置都是一样的
以随机数1为例进行说明,可以设置跟随那个分区一起写入
这里的分区是跟前面这里分区对应的:
长度推荐就设置为默认的4,而写入地址,可以根据自己的需要设置。
6、UID加密启用
可以设置跟随那个分区一起写入,与前面第5步的含义一样
长度推荐就设置为默认的4,而写入地址,可以根据自己的需要设置。
【实际操作举例】
使用H7-TOOL给我们的STM32H7开发板加密为例进行说明
1、选择脱机烧录的芯片型号,优先配置UID,生成UID加密算法的C实现
2、点击这里生成C算法:
#include <stdio.h> #include <stdlib.h> #include "stdint.h" #include <string.h> /* ********************************************************************************************************* * 定义 ********************************************************************************************************* */ typedef struct { uint32_t enable; // 使能位 uint32_t address; // 存储地址 uint32_t length; // 随机数长度 } RNG_TAB_t; uint8_t UidArray[16] = {0}; uint8_t EncryptUidArray[16] = {0}; uint8_t ReEncryptUidArray[16] = {0}; /* ********************************************************************************************************* * 通过上位机更新,与上位机保持一致 ********************************************************************************************************* */ /*--PC_DEFINE_BEGIN--*/ #define A1 1 #define A2 2 #define A3 3 #define A4 4 #define A5 5 #define A6 6 #define A7 7 #define A8 8 #define A9 9 #define A10 10 #define A11 11 #define A12 12 #define A13 13 #define A14 14 #define A15 15 #define A16 16 #define ENCRYPT_ADDR 0x08100000 //UID加密数据存储地址 #define ENCRYPT_LEN 8 //加密结果长度 #define ENCRYPT_RND_IDX 0 //加密用初值选择 0:固定数,1-4是随机数 #define RNG_CONST_DATA = "11 22 33 44 55 66 77 88" //常量值 #define RNG_TAB_t RNG_TAB = { //使能位, 存储地址, 随机数长度 {0, 0x08000000, 4}, {0, 0x08000000, 4}, {0, 0x08000000, 4}, {0, 0x08000000, 4} }; #define UID_ADDR 0x1FF1E800 #define UID_BYTES 12 /*--PC_DEFINE_END--*/ /* ********************************************************************************************************* * UID相关API ********************************************************************************************************* */ static uint8_t stringToHexArray(const char *str, uint8_t *hexArray) { uint32_t index = 0; while (*str != '\0') { while (*str == ' ') { str++; } if (*str == '\0') { break; } sscanf(str, "%2hhx", &hexArray[index++]); str += 2; } return index; } /* ********************************************************************************************************* * 函 数 名: encrypt * 功能说明: 计算UID加密 * 形 参: --- * 返 回 值: 无 ********************************************************************************************************* */ static void encrypt(const uint8_t* _uid, const uint8_t* _rnd, uint8_t _rndsize, uint8_t* out) { uint8_t uid[16] = {0}; uint8_t rnd[16] = {0}; int i, j; if (_uid == NULL) { return; } for (i = 0; i < UID_BYTES; i++) { uid[i] = _uid[i]; } j = 0; for (i = UID_BYTES; i < 16; i++) { uid[i] = uid[j++]; } if (_rnd != NULL) { for (i = 0; i < _rndsize; i++) { rnd[i] = _rnd[i]; } } out[0] = uid[A1 - 1] ^ (uid[A2 - 1] >> 1) ^ (uid[A3 - 1] >> 1); out[1] = uid[A4 - 1] ^ (uid[A5 - 1] >> 0) ^ (uid[A6 - 1] >> 1); out[2] = uid[A7 - 1] ^ (uid[A8 - 1] >> 1) ^ (uid[A9 - 1] >> 3); out[3] = uid[A10 - 1] ^ (uid[A11 - 1] >> 2) ^ (uid[A12 - 1] >> 0); out[4] = uid[A1 - 1] ^ (uid[A10 - 1] << 1) ^ (uid[A2 - 1] >> 0); out[5] = uid[A4 - 1] ^ (uid[A7 - 1] << 1) ^ (uid[A5 - 1] << 2); out[6] = uid[A7 - 1] ^ (uid[A4 - 1] >> 0) ^ (uid[A8 - 1] << 0); out[7] = uid[A10 - 1] ^ (uid[A1 - 1] >> 2) ^ (uid[A11 - 1] << 1); out[8] = uid[A2 - 1] ^ (uid[A10 - 1] >> 1); out[9] = uid[A3 - 1] ^ (uid[A7 - 1] << 1); out[10] = uid[A6 - 1] ^ (uid[A4 - 1] << 1); out[11] = uid[A9 - 1] ^ (uid[A1 - 1] >> 2); out[12] = uid[A1 - 1] ^ (uid[A2 - 1] >> 1); out[13] = uid[A3 - 1] ^ (uid[A5 - 1] >> 0); out[14] = uid[A6 - 1] ^ (uid[A8 - 1] << 2); out[15] = uid[A9 - 1] ^ (uid[A11 - 1] >> 0); for (i = 0; i < 16; i++) { out[i] ^= rnd[i % _rndsize]; } } /* ********************************************************************************************************* * 函 数 名: UidCompare * 功能说明: 比较加密的UID * 形 参: 1表示成功,0表示失败 * 返 回 值: 反 ********************************************************************************************************* */ uint8_t UidCompare(void) { uint8_t tempbuf[16] = {0}; uint16_t i; uint8_t size; uint8_t index; for(i = 0; i < UID_BYTES; i++) { UidArray[i] = *(volatile uint8_t*)(UID_ADDR+i); } for(i = 0; i < ENCRYPT_LEN; i++) { EncryptUidArray[i] = *(volatile uint8_t*)(ENCRYPT_ADDR + i); } if(ENCRYPT_RND_IDX == 0) { size = stringToHexArray((const char *)RNG_CONST_DATA, tempbuf); encrypt(UidArray, tempbuf, size, ReEncryptUidArray); } else { index = (uint8_t)(ENCRYPT_RND_IDX - 1); for(i = 0; i < RNG_TAB[index].length; i++) { tempbuf[i] = *((uint8_t *)(uintptr_t)(RNG_TAB[index].address + i)); } encrypt(UidArray, tempbuf, RNG_TAB[index].length, ReEncryptUidArray); } for (i = 0; i < ENCRYPT_LEN; i++) { if (ReEncryptUidArray[i] != EncryptUidArray[i]) { return 0; } } return 1; }
3、用户仅需调用UidCompare()即可,返回值是1表示验证成功,返回值是0表示验证失败
int main() { uint8_t re; re = UidCompare(); if(re == 1) { printf("验证成功\r\n"); } else { printf("验证失败\r\n"); } while(1); }
4、修改一个bug的地方
特别注意,当前2.26版本生成的C算法这两个写错了:
#define RNG_CONST_DATA = "11 22 33 44 55 66 77 88" //常量值 #define RNG_TAB_t RNG_TAB = { //使能位, 存储地址, 随机数长度 {0, 0x08000000, 4}, {0, 0x08000000, 4}, {0, 0x08000000, 4}, {0, 0x08000000, 4} };
修改为如下即可:
uint8_t RNG_CONST_DATA[] = "11 22 33 44 55 66 77 88"; //常量值 RNG_TAB_t RNG_TAB[] = { //使能位, 存储地址, 随机数长度 {0, 0x08000000, 4}, {0, 0x08000000, 4}, {0, 0x08000000, 4}, {0, 0x08000000, 4} };
然后编译生成hex文件。添加到TOOL上位机进行下载:
为了方便查看验证是否正常,我们这里简单做了个串口答应,成了就提示验证成功:
5、实际验证是没问题的,完整的测试例子如下,方便大家参考:
H7-TOOL UID加密.7z (1.28MB)