大家好,又见面了,我是你们的朋友全栈君。
目录
ATECC508A芯片开发笔记(七):实现对数据数字签名(Sign)并验证(Verify)证书签名
- 一、数据签名、验证基本流程
- 二、利用508对数据签名并验证 代码实现:
- 三、X.509证书验证
本节介绍利用508对证书数据进行签名、验证的步骤和原理。
一、数据签名、验证基本流程
由网络安全知识我们知道,对数据进行签名,其实就是用私钥加密而已,而验证签名就是用该私钥对应的公钥进行解密。
而如果对整个数据签名,会造成运算量大要验证数据多等缺点,因此实际应用中,一般是对原始数据算一个通过Hash算法算一个Hash值,Hash值唯一会保证数据完整性,然后再对该Hash值进行签名
因此只需验证该签名数据,并再算一次Hash与解密后的签名数据进行比较,就实现了保证数据的完整性以及身份认证双重效果。
二、利用508对数据签名并验证 代码实现:
void SignAndVerify_508Demo(uint8_t *Buffer)
{
uint8_t SHA_DATA[32] = {
0};
uint8_t Signature_Out[64] = {
0};
bool verified = 0;
int err = 0;
err = atecc508_init(ATECC508_DEV_I2C_ADDRESS); //508A init
assert_noerr(err);
err = ComputeSHA256withOneStep(Buffer,sizeof(Buffer),SHA_DATA);
err = atecc508_sign_hash(SLOT_x, SHA_DATA, Signature_Out);
err = atecc508_generate_public_key(SLOT_x,publickeyFromAt508);
err = atecc508_verify_external_mode(SHA_DATA,Signature_Out,publickeyFromAt508,&verified);
}
Sign(数字签名)实现:
函数首先对508A初始化,接着对传入的数据通过SHA256算出Hash值SHA_DATA,
- 接着就通过508A的API
atecc508_sign_hash()
对这个数据签名,该函数第一个参数是Slot数,既利用该Slot存储的私钥对数据进行签名。并将签名数据输出到Signature_Out
Verify(验签)实现:
-
Verify时需要利用508A实现数据签名相应的公钥,因此首先利用
atecc508_generate_public_key
由Slot_x的私钥产生公钥(非对称加密中私钥可以产生公钥),存储在publickeyFromAt508
。 -
之后调用
atecc508_verify_external_mode()
(使用External验证模式)输入SHA数据、Signature数据、解签名用的PublicKey,最后508会返回Bool型的verified,如果为1则验证成功,否则失败。
其中ComputeSHA256withOneStep()是封装实现了SHA256算法,该函数会将输入数据Buffer用SHA256算出一个Hash值(32 Byte)并输出至SHA_DATA数组。
(SHA2的软件实现方法有很多,这里不再赘述,有兴趣可以在我的这篇博客中找到SHA实现源码和典型应用:https://blog.csdn.net/HowieXue/article/details/78700694 )
//
//para in: input Bytes, bytelength
//para out: Message_Digest SHA result
//
OSStatus ComputeSHA256withOneStep(const uint8_t *bytes, unsigned int bytecount, uint8_t Message_Digest[SHA256HashSize])
{
SHA256Context sha256Con;
SHA256Reset(&sha256Con);
SHA256Input(&sha256Con, bytes, bytecount);
SHA256Result(&sha256Con, Message_Digest);
}
三、X.509证书验证
设备认证流程关键就是验证证书,大多数用于设备端与Cloud端之间进行双向认证,过程示例图参考如下:
而508A Lib对证书验证有一个专门的API函数来实现: · atcacert_verify_cert_hw()
,(其实都是调用的atcab_verify_extern()
函数)
508A有一个证书管理的大结构体:atcacert_def_t,证书的类型、SN、签名、key等都封装在了里面。如果用508A验证证书,就需要填充该结构的数据
四、实现代码:
为方便Demo,新建一个测试用的atcacert_def_t 数据cert_def_device_xxx :
atcacert_def_t cert_def_device_xxx =
{
.type = CERTTYPE_X509,
.template_id = 0,
.chain_id = 0,
.private_key_slot = 0,
.sn_source = SNSRC_DEVICE_SN,
.cert_sn_dev_loc =
{
.zone = DEVZONE_NONE,
.slot = 0,
.is_genkey = 0,
.offset = 0,
.count = 0
},
.issue_date_format = DATEFMT_POSIX_UINT32_BE, //DATEFMT_RFC5280_UTC
.expire_date_format = DATEFMT_POSIX_UINT32_BE,
.tbs_cert_loc =
{
.offset = 0,
.count = 0
},
.expire_years = 0,
.public_key_dev_loc =
{
.zone = DEVZONE_DATA,
.slot = 0,
.is_genkey = 0,
.offset = 0,
.count = 0
},
.comp_cert_dev_loc =
{
.zone = DEVZONE_DATA,
.slot = 0,
.is_genkey = 0,
.offset = 0,
.count = 0
},//todo
.std_cert_elements =
{
{
// STDCERT_PUBLIC_KEY
.offset = 0,
.count = 0
},
{
// STDCERT_SIGNATURE
.offset = 0,
.count = 0
},
{
// STDCERT_ISSUE_DATE
.offset = 0,
.count = 0
},
{
// STDCERT_EXPIRE_DATE
.offset = 0,
.count = 0
},
{
// STDCERT_SIGNER_ID
.offset = 0,
.count = 0
},
{
// STDCERT_CERT_SN
.offset = 0,
.count = 0
},
{
// STDCERT_AUTH_KEY_ID
.offset = 0,
.count = 0
},
{
// STDCERT_SUBJ_KEY_ID
.offset = 0,
.count = 0
}
},
.cert_elements = NULL,
.cert_elements_count = 0,
.cert_template = xxx_DeviceCert,
.cert_template_size = sizeof(xxx_DeviceCert),
.cert_template = 0,
.cert_template_size = 0,
};
证书验证代码如下,在填充cert_def_device_xxx中,要保证两个最基本的tbs_cert_loc
以std_cert_elements[STDCERT_SIGNATURE].offset
设置正确,
这两个数据分别是所要验证的证书中,to be signed 部分的长度,以及Signature的位置偏移量。
//modify cert_def tbs length and sign location
cert_def_device_xxx.tbs_cert_loc.count = tbs_length ;
cert_def_device_xxx.std_cert_elements[STDCERT_SIGNATURE].offset = SignLocation;
//verify cert use 508a
err = atcacert_verify_cert_hw(&cert_def_device_xxx,
Certificate->certificateData,
Certificate->length,
PubKey);
if(err != 0)
return err;
else
return 0;
将正确参数传入atcacert_verify_cert_hw()
,其返回值为0则代表验证成功。其中参数部分,Certificate是证书结构体指针,其指向了在内存中存储的证书,包括其内容和长度。
刚才提到atcacert_verify_cert_hw()
内部也是调用的atcab_verify_extern()
,代码如下:
int atcacert_verify_cert_hw( const atcacert_def_t* cert_def,
const uint8_t* cert,
size_t cert_size,
const uint8_t ca_public_key[64])
{
int ret = 0;
uint8_t tbs_digest[32];
uint8_t signature[64];
bool is_verified = false;
if (cert_def == NULL || ca_public_key == NULL || cert == NULL)
return ATCACERT_E_BAD_PARAMS;
ret = atcacert_get_tbs_digest(cert_def, cert, cert_size, tbs_digest);
if (ret != ATCACERT_E_SUCCESS)
return ret;
ret = atcacert_get_signature(cert_def, cert, cert_size, signature);
if (ret != ATCACERT_E_SUCCESS)
return ret;
ret = atcab_verify_extern(tbs_digest, signature, ca_public_key, &is_verified);
if (ret != ATCA_SUCCESS)
return ret;
return is_verified ? ATCACERT_E_SUCCESS : ATCACERT_E_VERIFY_FAILED;
}
可见,atcacert_verify_cert_hw()
内部实现的就是上述流程中的步骤,先计算证书To be signed 部分的SHA256,然后从证书制定位置提取其前面数据,
最后将SHA256数据(tbs_digest)和签名数据以及PublicKey传入到atcab_verify_extern()
去验证,返回验证成功与否。
(传输之间无任何Secret交换,体现了508A的安全性能保证)
博主热门文章推荐:
一篇读懂系列:
- 一篇读懂无线充电技术(附方案选型及原理分析)
- 一篇读懂:Android/iOS手机如何通过音频接口(耳机孔)与外设通信
- 一篇读懂:Android手机如何通过USB接口与外设通信(附原理分析及方案选型)
LoRa Mesh系列:
- LoRa学习:LoRa关键参数(扩频因子,编码率,带宽)的设定及解释
- LoRa学习:信道占用检测原理(CAD)
- LoRa/FSK 无线频谱波形分析(频谱分析仪测试LoRa/FSK带宽、功率、频率误差等)
网络安全系列:
- ATECC508A芯片开发笔记(一):初识加密芯片
- SHA/HMAC/AES-CBC/CTR 算法执行效率及RAM消耗 测试结果
- 常见加密/签名/哈希算法性能比较 (多平台 AES/DES, DH, ECDSA, RSA等)
- AES加解密效率测试(纯软件AES128/256)–以嵌入式Cortex-M0与M3 平台为例
嵌入式开发系列:
- 嵌入式学习中较好的练手项目和课题整理(附代码资料、学习视频和嵌入式学习规划)
- IAR调试使用技巧汇总:数据断点、CallStack、设置堆栈、查看栈使用和栈深度、Memory、Set Next Statement等
- Linux内核编译配置(Menuconfig)、制作文件系统 详细步骤
- Android底层调用C代码(JNI实现)
- 树莓派到手第一步:上电启动、安装中文字体、虚拟键盘、开启SSH等
- Android/Linux设备有线&无线 双网共存(同时上内、外网)
AI / 机器学习系列:
- AI: 机器学习必须懂的几个术语:Lable、Feature、Model…
- AI:卷积神经网络CNN 解决过拟合的方法 (Overcome Overfitting)
- AI: 什么是机器学习的数据清洗(Data Cleaning)
- AI: 机器学习的模型是如何训练的?(在试错中学习)
- 数据可视化:TensorboardX安装及使用(安装测试+实例演示)
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/131388.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...