STM32 加密思考

本文介绍了如何使用STM32FlashLoaderdemonstrator设置Flash读保护,防止通过调试工具、内置SRAM或FSMC执行代码读取。同时,利用设备ID进行加密,确保代码的唯一性和安全性。在程序中,通过比较加密后的CPUID来验证代码的合法性,并在检测失败时执行自擦除操作。此外,还提到了固件传输和镜像的加密方案,以增强保护措施。

STM32的加密思路

  1. 使用系统启动程序STM32 Flash Loader demonstrator将Flash设置为读保护。
    所有以调试工具、内置SRAM或FSMC执行代码等方式对主存储器访问的操作将被禁止,只允许用户代码对主Flash存储器的读操作和编程操作(除了Flash开始的4KB区域不能编程)。用户代码允许自主编程可以实现IAP或者数据存储等功能。
    这样破解者将不能用调试工具、内置SRAM或者FSMC执行代码等方式读出Flash中的代码。破解者也不能使用系统启动程序读取代码,因为要解除读保护,将执行整个芯片的擦除操作。
  2. 主程序中使用设备ID保护
    即使将Flash设置为读保护,破解者也可以通过IAP下载自己的一段小程序,从而读出Flash中的内容。因此,还需要利用设备的唯一ID进行加密保护。在主程序中,加入对设备唯一ID的检测,这样即使破解者读出了芯片中的二进制码,也不能用这个二进制码去复制新的器件。
    具体实现方法:
    a. 在应用程序中定义1个(32位甚至更多)const变量,变量值全为0xFF。每次启动程序时,检查const变量值如果全为0xFF,就读器件的唯一ID,通过Flash编程写入该const变量中(因为全是0xFF,所以可以编程写入)。
    b. 在程序中多个地方检查const变量,如果变量值不为0xFF并且与设备ID不一致,就执行与功能无关代码(比如自擦除)。
    这样,即使破解者读出了芯片中的二进制码,因为这份二进制码包含了设备唯一ID,具有唯一性,所以不能复制到其他芯片中。
    为了避免破解者利用反汇编,根据芯片ID数据在二进制文件中查找对应相同数据的位置从而破解,可以将ID拆散成不同的组合,并且写到不同且不连续的地方。更进一步,可在程序中检测多份这样的分散ID,以增加反汇编的难度。或者将CPUID进行加密,Flash中存储加密后的结果。
  3. 固件的加密。有两种方案:一是传输过程的加密,另外一种是固件镜像的加密。具体方案待补充。

程序加密的实现

//加密后的CPUID
volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;

//写入加密数据
void WriteEncrypt(void)
{
    //第一次烧写:将UID写入到Flash中
    if(CPUIDEncrypt==0xFFFFFFFF)
   {
        uint32_t CpuID[3];
        //获取CPU唯一的ID
        CpuID[0]=*(vu32*)(UID_BASE);
        CpuID[1]=*(vu32*)(UID_BASE+4);
        CpuID[2]=*(vu32*)(UID_BASE+8);

        //加密算法,很简单的加密算法
        uint32_t EncryptCode=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);
        FLASH_Unlock();
        FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR);
        FLASH_ProgramWord((uint32_t)&CPUIDEncrypt, EncryptCode);
        FLASH_Lock();
    }
}
//判断加密
bool JudgeEncrypt(void)
{
    uint32_t CpuID[4];
    //获取CPU唯一的ID
    CpuID[0]=*(vu32*)(UID_BASE);
    CpuID[1]=*(vu32*)(UID_BASE+4);
    CpuID[2]=*(vu32*)(UID_BASE+8);
    //加密算法,很简单的加密算法
    CpuID[3]=(CpuID[0]>>3)+(CpuID[1]>>1)+(CpuID[2]>>2);
    //检查Flash中的UID是否合法
    return (CPUIDEncrypt == CpuID[3]);
}
  • 将写入加密数据和判断加密两个功能分开。写入加密在PrsCtrlTask开始的地方;而判断加密分布到程序的各个角落。
  • 非常重要的是CPUID加密值的定义一定要加“volatile”类型,否则按速度优化编译,在判断加密值,不会重新读取加密值,导致判断出错。
volatile const static uint32 CPUIDEncrypt = 0xFFFFFFFF;
  • 在工程选项Options->Debugger->Download中选择: use flash loader,否则主程序中对Flash编程将不成功。
    [未完待续]
<think>好的,我现在需要帮助用户解决关于如何通过WiFi将STM32设备连接到OneNet平台的问题。首先,用户提到的是STM32、WiFi、OneNet连接,以及示例代码和配置方法。我需要根据提供的引用内容来组织回答。 首先,我应该检查用户提供的引用内容。引用[1]和引用[2]都提到了STM32与ESP8266通过MQTT协议连接OneNet的教程和代码示例。因此,主要的步骤应该包括硬件连接、固件烧录、OneNet平台配置、STM32代码编写和ESP8266的AT指令配置。 用户需要的是教程和示例代码,所以需要分步骤说明。首先,硬件部分需要明确使用的模块,比如ESP8266,并说明连接方式,比如串口通信。然后,OneNet平台的配置可能需要创建产品、添加设备、获取API密钥等信息。接着,STM32的代码部分需要初始化串口、配置WiFi模块、建立MQTT连接,并处理数据上传。同时,ESP8266可能需要烧录支持MQTT的AT固件,并通过AT指令设置WiFi和MQTT参数。 我需要确保回答的结构清晰,分步骤进行,每个步骤都有具体的操作指导,并包含示例代码片段。同时,要提醒用户注意可能的问题,比如AT指令的响应处理、数据格式的正确性,以及网络稳定性等注意事项。此外,引用文献中的链接可能无效,所以需要建议用户到官方网站查找资料。 还需要生成相关问题,可能涉及优化连接、数据加密、OTA升级等,这些可以从实际应用中的常见需求出发。同时,要确保所有提到的技术术语和步骤都准确,符合引用内容中的信息。 最后,要检查是否符合系统级指令,比如使用正确的中文回答,数学公式格式(虽然这个问题可能不涉及数学公式,但如果有的话需要正确应用),代码块使用正确的格式,以及引用标识的正确添加。在这个问题中,引用[1]和[2]需要适当标注在回答的末尾,例如在提到示例代码或配置步骤时添加引用标记。 现在,我需要将这些思考整理成一个结构化的回答,确保每个步骤都有条理,代码示例正确,并且注意事项和常见问题都涵盖到。同时,生成的相关问题需要与主题相关,帮助用户进一步了解相关内容。</think>### STM32通过WiFi连接OneNet平台教程 #### 一、硬件准备 1. **主控芯片**: STM32F103C8T6(或其他支持UART的STM32型号) 2. **WiFi模块**: ESP8266-01S(需支持AT指令) 3. **连接方式**: STM32的USART2与ESP8266的UART连接,波特率通常为$115200$ - `STM32_TX` → `ESP8266_RX` - `STM32_RX` → `ESP8266_TX` - 共地连接(GND→GND)[^2] #### 二、OneNet平台配置 1. **创建产品** - 登录OneNet平台,进入**控制台** → **产品开发** → **创建产品** - 通信协议选择`MQTT`,其他参数按需填写 2. **添加设备** - 在产品详情页添加设备,记录`设备ID`和`API Key`[^1] #### 三、ESP8266固件烧录 1. 下载支持MQTT的AT固件(如安信可官方固件) 2. 使用USB转TTL工具烧录固件,波特率选择$115200$ #### 四、STM32代码实现(示例) ```c // 初始化USART2(与ESP8266通信) void USART2_Init(void) { // 配置GPIO和USART参数(略) } // 发送AT指令并等待响应 void ESP8266_SendCmd(char *cmd, char *expect_resp, uint32_t timeout) { HAL_UART_Transmit(&huart2, (uint8_t*)cmd, strlen(cmd), 1000); // 添加超时检测和响应匹配逻辑 } // 主函数配置流程 int main(void) { // 硬件初始化 USART2_Init(); // 连接WiFi ESP8266_SendCmd("AT+CWJAP=\"SSID\",\"PASSWORD\"\r\n", "OK", 5000); // 连接OneNet MQTT char mqtt_cmd[128]; sprintf(mqtt_cmd, "AT+MQTTUSERCFG=0,1,\"设备ID\",\"产品ID\",\"API_KEY\",0,0,\"\"\r\n"); ESP8266_SendCmd(mqtt_cmd, "OK", 3000); ESP8266_SendCmd("AT+MQTTCONN=0,\"183.230.40.96\",6002,1\r\n", "OK", 5000); // 数据上传示例 char data[64]; sprintf(data, "{\"temperature\":25.5}"); ESP8266_SendCmd("AT+MQTTPUB=0,\"$sys/设备ID/数据流\",1,1,0,%d\r\n", "OK", 3000); HAL_UART_Transmit(&huart2, (uint8_t*)data, strlen(data), 1000); } ``` #### 五、关键配置参数 | 参数类型 | 示例值 | |----------------|---------------------------------| | OneNet MQTT地址 | `183.230.40.96:6002` | | 主题格式 | `$sys/{产品ID}/{设备ID}/dp/post`| | 数据格式 | JSON(如`{"key1":value1,...}`)| #### 六、注意事项 1. **AT指令响应处理**: 需添加超时机制和错误重试逻辑 2. **数据加密**: 建议启用MQTT的TLS加密(端口$8883$) 3. **心跳包**: 定期发送`AT+MQTTKEEPALIVE=0,60`维持连接[^1]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值