Files
GD32_BOOT/Robot_V2/sys/OTA.cpp
T
cbb 9c7145ef99 feat(ota): 实现安全OTA更新协议支持AES加密和CRC校验
- 添加AES128加密解密功能支持安全固件传输
- 实现基于随机数握手的安全会话密钥协商机制
- 集成CRC32带密钥校验确保数据完整性
- 重构OTA状态机支持握手、数据传输和验证流程
- 添加CANFD数据长度规范处理和安全跳转逻辑
- 移除调试打印语句优化性能

refactor(can): 优化CANFD发送和OTA确认处理逻辑

- 重构CANFD_AsyncSend函数支持规范数据长度
- 重命名sendACK为sendDATA_ACK并添加重载函数
- 修复数据长度处理和缓冲区填充逻辑
- 优化CAN消息发送的数据复制和验证流程
- 移除未使用的联合体类型定义

chore(project): 添加AES加密模块和系统初始化配置

- 在项目配置中添加AES128加密解密文件
- 在main.cpp中初始化CRC外设模块
- 添加安全十六进制打印调试函数
- 集成AES加密库到OTA处理流程中
- 优化系统时钟初始化配置
2026-01-01 01:39:19 +08:00

418 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "OTA.h"
#include "Can.h"
#include "aes128.h"
#include "config.h"
#include "gd32c10x.h" // 主头文件,包含了gd32c10x_crc.h的内容
#include "gd32c10x_fmc.h"
#include "systick.h"
#include <cstdio>
#include <cstring>
#include <flash.h>
#include <stdint.h>
extern CAN_transmiter CAN0_transmiter; // CAN初始化
extern FlashEEPROM flashEEP;
OTAHandler ota;
extern "C" {
void canfd_rx_irq_handler(void);
}
static inline uint32_t extract_u32_from_4bytes(const uint8_t *array) {
return ((uint32_t)array[3] << 24) | ((uint32_t)array[2] << 16) |
((uint32_t)array[1] << 8) | (uint32_t)array[0];
}
void OTAHandler::init() {}
void OTAHandler::process() {
if (ota_state == OTA_STATE_IDLE) {
ota_time = 0; // 重置计时器
static u8 zero[1] = {0};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_WAIT_ID, 0, zero);
#if DEBUG_OTA
printf("OTA status:%d\r\n", ota_state);
#endif
delay_1ms(10);
return;
} else {
delay_1ms(1);
ota_time++;
}
// 检查是否超时(例如:10秒无数据则退出OTA模式)
if (ota_time > OTA_TIMEOUT) { // 10秒超时(10000 x 1ms)
ota_time = 0;
ota_state = OTA_STATE_IDLE;
ota_error = OTA_ERROR_TIMEOUT;
send_error_frame(OTA_ERROR_TIMEOUT); // 验证失败
}
}
bool OTAHandler::validateApplication() {
u32 *app_vector = (u32 *)APP_START_ADDR;
u32 stack_ptr = app_vector[0];
u32 reset_handler = app_vector[1];
// 简单验证:检查栈指针是否在SRAM范围内
return (stack_ptr >= 0x20000000 && stack_ptr < 0x20008000) &&
(reset_handler >= APP_START_ADDR &&
reset_handler < (APP_START_ADDR + APP_MAX_SIZE));
}
void OTAHandler::jumpToApplication() {
if (!validateApplication())
return;
// 1. 关闭所有中断
__disable_irq();
for (int i = 0; i < 8; i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
}
// 2. 重置外设(特别是CAN,防止冲突)
can_deinit(CAN0);
// 3. 重置系统时钟到默认状态
rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
// 4. 关闭一些关键外设时钟
rcu_periph_clock_disable(RCU_GPIOA);
rcu_periph_clock_disable(RCU_GPIOB);
rcu_periph_clock_disable(RCU_GPIOC);
rcu_periph_clock_disable(RCU_USART0);
rcu_periph_clock_disable(RCU_CAN0);
rcu_periph_clock_disable(RCU_TIMER0);
rcu_periph_clock_disable(RCU_DMA0);
// 5. 设置MSP并跳转
uint32_t msp_value = *(__IO uint32_t *)APP_START_ADDR;
__set_MSP(msp_value);
uint32_t reset_handler = *(__IO uint32_t *)(APP_START_ADDR + 4);
typedef void (*AppEntryFunc)(void);
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
// 6. 跳转
app_entry();
}
void OTAHandler::eraseApplicationArea() {
// 擦除APP区域
fmc_unlock();
for (u32 addr = APP_START_ADDR; addr < (APP_START_ADDR + APP_MAX_SIZE);
addr += FMC_PAGE_SIZE) {
fmc_page_erase(addr);
}
fmc_lock();
}
void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
fmc_unlock();
u32 write_addr = APP_START_ADDR + offset;
// 32位对齐写入
for (u32 i = 0; i < size; i += 4) {
u32 word = 0;
memcpy(&word, &data[i], 4);
fmc_word_program(write_addr + i, word);
}
fmc_lock();
}
void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
if (id == CANFD_OTA_DATA_ID) {
ota_time = 0;
if (len == 64 and ota_state == OTA_STATE_RECEIVING_FIRMWARE) {
#if DEBUG_OTA
printf("stage8:OTA_RECEIVING_FIRMWARE\r\n");
#endif
// 数据解包
u32 receive_session_num;
u32 receive_packet_num;
u8 receive_encrypted_data[OTA_PACKET_SIZE];
u32 receive_IFEND;
u8 receive_dataCRC32[4];
receive_session_num = extract_u32_from_4bytes(data);
receive_packet_num = extract_u32_from_4bytes(data + 4);
for (int i = 0; i < 48; i++) {
receive_encrypted_data[i] = data[i + 8];
}
receive_IFEND = extract_u32_from_4bytes(data + 56);
for (int i = 0; i < 4; i++) {
receive_dataCRC32[i] = data[i + 60];
}
// 解密
u8 decrypted_data[OTA_PACKET_SIZE];
u8 calculated_dataCRC32[4];
aes128_set_key(&aes_ctx, current_K_session);
aes128_ecb_decrypt_48bytes(&aes_ctx, receive_encrypted_data,
decrypted_data);
// 计算解密后CRC数据
calculate_crc32_with_key(current_K_session, decrypted_data,
calculated_dataCRC32);
// CRC数据匹配
if (memcmp(receive_dataCRC32, calculated_dataCRC32, SIZE_U32) !=
0) {
ota_error = OTA_ERROR_INVALID_CRC;
send_error_frame(OTA_ERROR_INVALID_CRC);
return;
}
if (receive_IFEND == 0xFFFFFFFF) { // 接收到尾帧,发送结束信号
u8 pack_number[4] = {0xFF, 0xFF, 0xFF, 0xFF};
CAN0_transmiter.sendDATA_ACK(CANFD_OTA_ACK_ID, pack_number);
ota_state = OTA_STATE_FINISHED;
return;
}
// 下一个请求
u32 request_packet = receive_packet_num + 1;
u8 pack_number[4];
// 封包
memcpy(&pack_number, &request_packet, 4);
CAN0_transmiter.sendDATA_ACK(CANFD_OTA_ACK_ID, pack_number);
} else if (len == 4 and ota_state == OTA_STATE_CHECKING_FIRMWARE) {
#if DEBUG_OTA
printf("stage7:OTA_STATE_CHECKING_FIRMWARE\r\n");
#endif
// OTA请求包
u32 new_size = *(u32 *)data;
if (new_size <= APP_MAX_SIZE) {
expected_size = new_size;
received_size = 0;
} else {
ota_error = OTA_ERROR_INVALID_SIZE;
send_error_frame(OTA_ERROR_INVALID_SIZE);
return;
}
// eraseApplicationArea();
u8 send_data[6] = {0xBA, 0xC0, 0x00,
0x00, 0x00, 0x00}; // 确认开始传输
// 发送接收包0请求
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 6, send_data);
ota_state = OTA_STATE_RECEIVING_FIRMWARE;
} else if (len == 2 and ota_state == OTA_STATE_FINISHED) {
#if DEBUG_OTA
printf("stage8:OTA_STATE_FINISHED\r\n");
#endif
u8 send_data[2] = {0x0A, 0xAC}; // 确认开始传输
// 4. 验证成功 - 发送最终ACK
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, send_data);
} else {
ota_error = OTA_ERROR_INVALID_PACKET;
send_error_frame(OTA_ERROR_INVALID_PACKET);
}
} else if (id == CANFD_OTA_REQ_ID) {
ota_time = 0;
#if DEBUG_OTA
printf("stage2:OTA_STATE_WAITING_RANDOM\r\n");
#endif
if (data[0] == 0x00 and data[1] == 0xAC and len == 2 and
ota_state == OTA_STATE_IDLE) { // 收到发起信号
u8 send_data[2] = {0x00, 0xac}; // 确认握手开始,请求随机数
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2,
send_data); // 发送握手开始信号
ota_state = OTA_STATE_WAITING_RANDOM;
} else if (len == 16 and ota_state == OTA_STATE_WAITING_RANDOM) {
#if DEBUG_OTA
printf("stage4:OTA_STATE_WAITING_CONFIRM\r\n");
#endif
while (len-- > 0) {
nonce_server[len] = data[len];
}
// 1. 获取设备唯一码
getDeviceSerialNumber(device_uid);
// 2. 初始化AES上下文(设置主密钥)
aes128_set_key(&aes_ctx, K_master);
// 3. 生成会话密钥 K_session (16字节)
u8 K_session[16];
aes128_encrypt_block(&aes_ctx, nonce_server,
K_session); // 用主密钥加密随机数
// 4. 用主密钥加密明文 (AES-128-ECB)
u8 encrypted_Ksession[16];
u8 temp_block[AES_BLOCK_SIZE];
// 加密第一个16字节块
aes128_encrypt_block(&aes_ctx, K_session, temp_block);
memcpy(encrypted_Ksession, temp_block, 16);
// 5. 构造握手响应包 (36字节)
u8 handshake_response[36];
// 5.1 前12字节:设备UID
memcpy(handshake_response, device_uid, 12);
// 5.2 接下来8字节:nonce后半部分
memcpy(handshake_response + 12, nonce_server + 8, 8);
// 5.3 最后16字节:加密数据的K-session
memcpy(handshake_response + 20, encrypted_Ksession, 16);
// 6. 通过CAN发送响应
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 36,
handshake_response);
// 7. 保存会话密钥供后续使用
memcpy(current_K_session, K_session, 16);
// 8. 更新状态机
ota_state = OTA_STATE_WAITING_CONFIRM;
} else if (len == 16 and ota_state == OTA_STATE_WAITING_CONFIRM) {
#if DEBUG_OTA
printf("stage6:OTA_STATE_CHECKING_SESSION\r\n");
#endif
u8 plaintext[16];
u8 expected[16];
// 1. 用K_session解密
u8 encrypted_confirm[16];
memcpy(encrypted_confirm, data, 16);
aes128_set_key(&aes_ctx, current_K_session);
aes128_decrypt_block(&aes_ctx, encrypted_confirm, plaintext);
// 2. 计算期望值 (nonce_server XOR 0x55)
// 注意:需要保存原始的nonce_server
for (int i = 0; i < 16; i++) {
expected[i] = nonce_server[i] ^ 0x55;
}
// 3. 验证解密结果
if (memcmp(plaintext, expected, 16) != 0) {
// 验证失败 - 可能密钥错误或攻击
ota_error = OTA_ERROR_INVALID_KEY;
send_error_frame(OTA_ERROR_INVALID_KEY); // 验证失败
// reset_ota_state();
return;
}
u8 send_data[2] = {0xBA, 0xC0}; // 确认开始传输
// 4. 验证成功 - 发送最终ACK
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, send_data);
// 5. 更新状态 - 进入固件接收阶段
ota_state = OTA_STATE_CHECKING_FIRMWARE;
} else {
// 其他握手异常
ota_error = OTA_ERROR_INVALID_HANDSHAKE;
send_error_frame(OTA_ERROR_INVALID_HANDSHAKE);
return;
}
}
}
void send_error_frame(u8 error) {
u8 error_frame[1] = {error};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 1, error_frame);
}
/**
* @brief 获取GD32设备唯一码
* @param buffer 存储唯一码的缓冲区,至少需要12字节
* @return void
*/
void getDeviceSerialNumber(u8 *buffer) {
uint32_t serial_msb = DEVICE_SERIAL_ADDR_MSB;
uint32_t serial_mid = DEVICE_SERIAL_ADDR_MID;
uint32_t serial_lsb = DEVICE_SERIAL_ADDR_LSB;
// 将96位唯一ID复制到缓冲区 (以小端序存储)
for (int i = 0; i < 4; i++) {
buffer[i] = (u8)(serial_lsb >> (i * 8));
buffer[i + 4] = (u8)(serial_mid >> (i * 8));
buffer[i + 8] = (u8)(serial_msb >> (i * 8));
}
}
/**
* @brief 获取GD32设备唯一码为字符串格式
* @param str 存储唯一码字符串的缓冲区,至少需要25字节(包含结束符)
* @return void
*/
void getDeviceSerialNumberString(char *str) {
u8 serial[12];
getDeviceSerialNumber(serial);
// 将字节序列转换为十六进制字符串表示
for (int i = 0; i < 12; i++) {
sprintf(&str[i * 2], "%02X", serial[i]);
}
str[24] = '\0'; // 确保字符串结束
}
/**
* 带密钥的CRC32校验函数
*
* @param key 16字节密钥
* @param data 48字节待校验数据
* @param output 4字节输出缓冲区,存储CRC32校验值
*
* 特点:
* - 使用标准CRC32算法
* - 16字节密钥用于初始化CRC32状态
*/
void calculate_crc32_with_key(const uint8_t *key, const uint8_t *data,
u8 *output) {
// CRC32查找表(标准多项式0xEDB88320)
static const uint32_t crc_table[256] = {
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D};
// 用16字节密钥初始化CRC32状态
uint32_t crc = 0xFFFFFFFF;
for (int i = 0; i < 16; i++) {
crc = crc_table[(crc ^ key[i]) & 0xFF] ^ (crc >> 8);
}
// 计算48字节数据的CRC32
for (int i = 0; i < 48; i++) {
crc = crc_table[(crc ^ data[i]) & 0xFF] ^ (crc >> 8);
}
// 取反得到最终结果
crc = ~crc;
// 将CRC32结果拆分为4字节(小端格式)
output[0] = (uint8_t)(crc >> 0);
output[1] = (uint8_t)(crc >> 8);
output[2] = (uint8_t)(crc >> 16);
output[3] = (uint8_t)(crc >> 24);
}