打印
[CW32F030系列]

CW32F030C8T6 数字签名实战指

[复制链接]
53|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
磨砂|  楼主 | 2025-7-8 21:39 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一.CW32F030C8T6 数字签名相关寄存器
1.1 概述
数字签名主要用来存放芯片唯一身份标识(UID)、产品型号、FLASH 容量、SRAM 容量、芯片封装引脚数等信息, 可以通过 SWD 或者 CPU 读取。数字签名相关信息在出厂时编程,用户固件或外部设备可通过读取数字签名来对 芯片的合法性进行验证。
1.2 产品唯一身份标识(UID)
寄存器(80bit) UID寄存器存储了芯片的唯一身份标识符,其地址为 0x0001 2660 - 0x0001 2669,共 80bit。UID在芯片生产时写入, 用户无法修改。UID 寄存器支持以单字节 / 半字 / 全字等方式读取,然后使用自定义算法连接起来。 唯一身份标识符典型应用场景:
用作设备序列号
设备合法性验证 , 防止盗版 用户在设备生产时采用私有密钥对 UID 进行加密运算,并将计算结果存放在主 FLASH 存储器或 OTP 存储器, 程序在设备启动后,读取 UID 并采用同样的密钥进行加密运算,并将运算结果和之前存储的计算结果进行比 较,相同则认为该设备是合法的,否则程序不启动,可有效防止用户设备被非法复制(盗版)。
作为安全密钥使用 用户结合 UID 和私有算法,可在用户对 FLASH 编程前进行安全校验,提高 FLASH 内代码的安全性。
激活安全启动流程等
1.3 产品型号寄存器
产品型号寄存器存储了产品型号的 ASCII 码,其地址为 0x0001 2610 - 0x0001 2625,共 22 字节。产品型号不足 22 字节时,用 0x00 进行填充。 如芯片的型号为 CW32x030C8T7-LQFP48,对应存储 ( 从低地址开始 ) 的数据为:0x43
1.4 FLASH 容量寄存器
FLASH 容量寄存器存储了芯片内置 FLASH 存储器的容量大小,其地址为 0x0001 2628 - 0x0001 262B,共 4 字节。 从 FLASH 容量寄存器读出的 FLASH 容量大小以字节为单位,如 0x0001 0000 代表 64KB,0x0000 8000 代表 32KB。
1.5 SRAM 容量寄存器
SRAM 容量寄存器存储了芯片内置 SRAM 存储器的容量大小,其地址为 0x0001 262C - 0x0001 262F,共 4 字节。 从 SRAM 容量寄存器读出的 SRAM 容量大小以字节为单位,如 0x0001 0000 代表 64KB,0x0000 4000 代表 16KB。
1.6 引脚数量寄存器
引脚数量寄存器存储了芯片引脚数,其地址为 0x0001 2626 - 0x0001 2627,共 2 字节。如 0x0020 代表 32Pin, 0x0030 代表 48Pin。
二.数字签名实现方法
2.1 使用加密库
CW32F030C8T6 可通过第三方加密库(如mbedTLS、WolfSSL)实现数字签名。常见算法包括RSA、ECDSA。

2.2 基于SHA和RSA的签名流程
生成哈希值:使用SHA-256对固件计算哈希值。
私钥签名:用开发者私钥对哈希值进行RSA加密,生成签名。
公钥验证:在设备端用预置的公钥解密签名,与重新计算的哈希值比对。
2.3 代码示例 (基于mbedTLS)
使用 CW32F030C8T6 实现 ECDSA 数字签名

2.3.1硬件准备

确保 CW32F030C8T6 开发环境已配置完毕,包括必要的开发工具链(如 Keil MDK 或 IAR Embedded Workbench)和调试工具(如 J-Link 或 ST-Link)。

环境配置
https://blog.csdn.net/weixin_43260261/article/details/148895475?spm=1011.2415.3001.5331

2.3.2软件库选择

使用支持 ECDSA 的加密库,如 Mbed TLS、wolfSSL 或 TinyCrypt。这些库提供 ECDSA 的实现,可以直接集成到项目中

2.3.3密钥生成

ECDSA 需要一对密钥(私钥和公钥)。使用加密库生成 ECC 密钥对。以下(基于 Mbed TLS):

#include "mbedtls/ecdsa.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"

mbedtls_ecdsa_context ctx;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;

mbedtls_ecdsa_init(&ctx);
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctr_drbg);

// 初始化随机数生成器
mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);

// 生成 ECC 密钥对(使用 secp256r1 曲线)
mbedtls_ecdsa_genkey(&ctx, MBEDTLS_ECP_DP_SECP256R1, mbedtls_ctr_drbg_random, &ctr_drbg);



2.3.4签名生成

使用私钥对消息进行签名。

unsigned char hash[32]; // 假设消息的哈希值为 32 字节
unsigned char sig[64];  // ECDSA 签名输出

// 计算消息的哈希(此处省略哈希计算步骤)
// ...

// 生成签名
mbedtls_ecdsa_write_signature(&ctx, MBEDTLS_MD_SHA256, hash, sizeof(hash), sig, sizeof(sig), mbedtls_ctr_drbg_random, &ctr_drbg);


2.3.5签名验证

使用公钥验证签名。

int ret = mbedtls_ecdsa_read_signature(&ctx, hash, sizeof(hash), sig, sizeof(sig));
if (ret == 0) {
    // 签名验证成功
} else {
    // 签名验证失败
}


2.3.6资源清理

完成操作后,释放资源:

mbedtls_ecdsa_free(&ctx);
mbedtls_entropy_free(&entropy);
mbedtls_ctr_drbg_free(&ctr_drbg);


2.3.7优化建议

CW32F030C8T6 的资源有限,建议使用较小的曲线(如 secp192r1)以减少计算负载。如果性能要求较高,可以考虑硬件加速或优化库的实现。

2.4 验证签名的步骤
烧录公钥到CW32F030C8T6的安全存储区(如OTP或Flash保护区)。
设备启动时重新计算固件哈希值。
用公钥解密签名,匹配哈希值。
2.5 注意事项
私钥需离线存储,避免泄露。
推荐使用硬件安全元件(如SE)或TrustZone增强保护。
定期更新密钥对以应对潜在**风险。
确保芯片的硬件标识符(如UID)与官方文档一致,避免使用非原装或篡改过的芯片。CW32F030C8T6的UID通常位于特定内存地址,需通过读取命令验证。
推荐使用ECDSA或RSA算法,密钥长度需符合安全标准(如RSA-2048或ECC-256)。算法实现需通过权威认证(如FIPS 140-2),避免使用自定义或未经验证的加密库。
私钥必须存储在安全环境中(如HSM或安全芯片),禁止硬编码在代码中。公钥可嵌入固件,但需校验其完整性和来源。定期轮换密钥以降低泄露风险。
固件签名应在隔离的构建环境中完成,确保编译与签名环节无缝衔接。签名后需生成哈希值(如SHA-256)并与签名一起存储,供后续验证使用。
在Bootloader中集成签名验证逻辑,确保只有合法签名的固件可被加载。验证失败时立即触发安全异常(如系统复位或警报),并记录错误日志。
量产阶段禁用JTAG/SWD等调试接口,防止未签名代码通过调试端口注入。可通过芯片的选项字节(Option Bytes)配置实现。
参考CW32官方提供的安全手册和ANSI/ISO相关标准,确保签名流程符合行业规范。保留完整的签名记录和审计日志以备审查。
三.案例-读取数字签名相关内容
uint8_t Chip_Type[24];       // 存储芯片型号的数组,长度为24字节
uint16_t Pin_Count;          // 存储芯片引脚数量的变量
uint32_t Flash_Size;         // 存储芯片Flash大小的变量
uint32_t Ram_Size;           // 存储芯片RAM大小的变量
uint8_t Chip_Uid[10];        // 存储芯片唯一标识符的数组,长度为10字节

/**
******************************************************************************
** \brief  项目主函数
**
** \return uint32_t 返回值,如有需要
**
** 该示例用于切换GPIOA.00
**
******************************************************************************/
int32_t main(void)
{
    // 初始化GPIOB时钟
    RCC_AHBPeriphClk_Enable(RCC_AHB_PERIPH_GPIOB, ENABLE);  // 开启GPIOB时钟

    // 配置GPIOB引脚6
    CW_GPIOB->ANALOG_f.PIN6 = 0U;      // 设置PB06为数字模式
    CW_GPIOB->BRR_f.BRR6 = 1U;         // 复位PB06
    CW_GPIOB->DIR_f.PIN6 = 0U;         // 设置PB06为输出模式

    // 获取芯片信息
    DIGITALSIGN_GetChipType(Chip_Type);        // 获取芯片型号
    Pin_Count = DIGITALSIGN_GetPinCount();     // 获取芯片引脚数量
    Flash_Size = DIGITALSIGN_GetFlashSize();   // 获取芯片Flash大小
    Ram_Size = DIGITALSIGN_GetRamSize();       // 获取芯片RAM大小
    DIGITALSIGN_GetChipUid(Chip_Uid);          // 获取芯片唯一标识符

    // 主循环
    while (1)
    {
        CW_GPIOB->TOG = bv8;           // 切换GPIOB引脚8状态
        CW_GPIOB->TOG = bv6;           // 切换GPIOB引脚6状态
        FirmwareDelay(100000);         // 延时
    }
}



————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_43260261/article/details/149168909

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

107

主题

4310

帖子

2

粉丝