[C] 纯文本查看 复制代码
/*
*********************************************************************************************************
*
* 模块名称 : 主程序模块。
* 文件名称 : main.c
* 版 本 : V1.0
* 说 明 : ECDSA算法的UID验证
*
* 注意实现 : 1、ECDSA使用的曲线是SECP256R1
* 2、哈希值计算使用的SHA224
* 修改记录 :
* 版本号 日期 作者 说明
* V1.0 2026-03-02 armfly 首发
*
* Copyright (C), 2026-2030, 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url]
*
*********************************************************************************************************
*/
#include "bsp.h" /* 底层硬件驱动 */
#include "SEGGER_RTT.h"
#include "cmox_crypto.h"
/*
*********************************************************************************************************
* 变量和函数
*********************************************************************************************************
*/
cmox_ecc_handle_t Ecc_Ctx; /* ECC 上下文 */
uint8_t Working_Buffer[2000]; /* ECC 工作缓冲区 */
uint8_t Computed_Hash[CMOX_SHA224_SIZE]; /* 计算哈希值 */
uint8_t Signature[CMOX_ECC_SECP256R1_SIG_LEN];/* 记录签名 */
uint8_t Public_Key[64]; /* 公钥 */
uint8_t uid[12]; /* UID缓冲 */
cmox_hash_retval_t hretval; /* 哈希值计算返回状态 */
cmox_ecc_retval_t retval; /* ECDSA校验返回状态*/
size_t computed_size; /* 哈希值返回值个数记录*/
uint32_t fault_check = CMOX_ECC_AUTH_FAIL; /* ECDSA异常记录*/
/* 打印数组函数,按每行16个字节的格式输出 */
void print_array_16_per_line(const char *name, const uint8_t *array, size_t len)
{
SEGGER_RTT_printf(0, "%s:\n", name);
for (size_t i = 0; i < len; i++)
{
/* 打印每个字节,以两位十六进制形式显示 */
SEGGER_RTT_printf(0, "0x%02X", array);
/* 每行16个元素后换行,或者最后一个元素后也换行 */
if ((i + 1) % 16 == 0 || i == len - 1)
{
SEGGER_RTT_printf(0, "\n");
}
else
{
SEGGER_RTT_printf(0, " ");
}
}
SEGGER_RTT_printf(0, "\n"); /* 额外空行分隔两个数组 */
}
/*
*********************************************************************************************************
* 函 数 名: main
* 功能说明: c程序入口
* 形 参:无
* 返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
uint8_t ucKeyCode;
bsp_Init(); /* 硬件初始化 */
/* 配置通道0,上行配置*/
SEGGER_RTT_ConfigUpBuffer(0, "RTTUP", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
/* 配置通道0,下行配置*/
SEGGER_RTT_ConfigDownBuffer(0, "RTTDOWN", NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
/*第1步:读取UID,签名和公钥 =========================================================*/
/* (1) STM32H7的UID读取,12个字节 */
for(int i = 0; i < sizeof(uid); i++)
{
uid = *(__IO uint8_t*)(0x1FF1E800 + i);
}
print_array_16_per_line("uid", uid, 12);
/* (2) 读取签名值,64个字节 */
for(int i = 0; i < CMOX_ECC_SECP256R1_SIG_LEN; i++)
{
Signature = *(__IO uint8_t*)(0x08100000 + i);
}
print_array_16_per_line("Signature", Signature, 64);
/* (3) 读取公钥,64个字节 */
for(int i = 0; i < 64; i++)
{
Public_Key = *(__IO uint8_t*)(0x08100000 + i + CMOX_ECC_SECP256R1_SIG_LEN);
}
print_array_16_per_line("Public_Key", Public_Key, 64);
/*第2步:初始化加密库 =======================================================================*/
cmox_init_arg_t init_target = {CMOX_INIT_TARGET_AUTO, NULL};
if (cmox_initialize(&init_target) != CMOX_INIT_SUCCESS)
{
SEGGER_RTT_printf(0, "初始化失败\r\n");
}
/*第3步:计算哈希值(摘要) ================================================================*/
/* 通过传入所有必要参数直接计算摘要 */
hretval = cmox_hash_compute(CMOX_SHA224_ALGO, /* 使用SHA224算法 */
uid, sizeof(uid), /* 待计算摘要的消息 */
Computed_Hash, /* 接收摘要数据的缓冲区 */
CMOX_SHA224_SIZE, /* 预期的摘要大小 */
&computed_size); /* 计算得到的摘要大小 */
/* 验证计算是否成功 */
if (hretval != CMOX_HASH_SUCCESS)
{
SEGGER_RTT_printf(0, "Hash计算失败\r\n");
}
/* 验证哈希数值是否有28字节 */
if (computed_size != CMOX_SHA224_SIZE)
{
SEGGER_RTT_printf(0, "Hash值个数和期盼的不一样多\r\n");
}
/*第4步:根据UID,签名和公钥进行验证 ================================================================*/
/* 构建一个ECC上下文,指定数学实现方式和用于后续处理的工作缓冲区 */
/* 注意:CMOX_ECC256_MATH_FUNCS 指的是在 cmox_default_config.h 中选择的默认数学实现。要使用特定的实现,用户可以直接选择:
1、CMOX_MATH_FUNCS_SMALL 选择小型数学实现,主要是内存占用小
2、CMOX_MATH_FUNCS_FAST 选择快速数学实现
3、CMOX_MATH_FUNCS_SUPERFAST256 选择针对256位计算优化的快速数学实现
*/
cmox_ecc_construct(&Ecc_Ctx, CMOX_ECC256_MATH_FUNCS, Working_Buffer, sizeof(Working_Buffer));
retval = cmox_ecdsa_verify(&Ecc_Ctx, /* ECC上下文 */
CMOX_ECC_CURVE_SECP256R1, /* 选择的SECP256R1 ECC曲线 */
Public_Key, sizeof(Public_Key), /* 用于验证的公钥 */
Computed_Hash, CMOX_SHA224_SIZE,/* 待验证的摘要 */
Signature, sizeof(Signature), /* 签名数据缓冲区 */
&fault_check); /* 故障检查变量:确保在此API调用期间不会发生故障注入 */
/* 验证是否成功 */
if ((retval != CMOX_ECC_AUTH_SUCCESS) && (fault_check != CMOX_ECC_AUTH_SUCCESS))
{
SEGGER_RTT_printf(0, "签名验证失败\r\n");
}
else
{
SEGGER_RTT_printf(0, "签名验证成功,LED2定时100ms闪烁\r\n");
bsp_StartAutoTimer(0, 100); /* 启动1个100ms的自动重装的定时器 */
}
/* 清除上下文 */
cmox_ecc_cleanup(&Ecc_Ctx);
/* 进入主程序循环体 */
while (1)
{
bsp_Idle(); /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
/* 判断定时器超时时间 */
if (bsp_CheckTimer(0))
{
bsp_LedToggle(2);
}
/* 按键滤波和检测由后台systick中断服务程序实现,我们只需要调用bsp_GetKey读取键值即可。 */
ucKeyCode = bsp_GetKey(); /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
if (ucKeyCode != KEY_NONE)
{
switch (ucKeyCode)
{
case KEY_DOWN_K1: /* K1键按下 */
break;
default:
/* 其它的键值不处理 */
break;
}
}
}
}
/***************************** 安富莱电子 [url=http://www.armfly.com]www.armfly.com[/url] (END OF FILE) *********************************/