ATECC508A芯片开发笔记(七):实现数字签名(Sign)并校验(Verify)证书签名

ATECC508A芯片开发笔记(七):实现数字签名(Sign)并校验(Verify)证书签名ATECC508A芯片开发笔记(七):实现对数据数字签名(Sign)并验证(Verify)证书签名一、数据签名、验证基本流程二、利用508对数据签名并验证代码实现:三、X.509证书验证本节介绍利用508对证书数据进行签名、验证的步骤和原理。一、数据签名、验证基本流程由网络安全知识我们知道,对数据进行签名,其实就是用私钥加密而已,而验证签名就是用该私钥对应的公钥进行解密。而如果对整个数

大家好,又见面了,我是你们的朋友全栈君。



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_locstd_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的安全性能保证)



博主热门文章推荐:

一篇读懂系列:

LoRa Mesh系列:

网络安全系列:

嵌入式开发系列:

AI / 机器学习系列:


在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/131388.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • socat 使用「建议收藏」

    转原文链接:http://www.wenquan.name/?p=1158用socat试几个netcat常用的用法,对比如下:1.听tcp12345端口#nc-l127.0.0.112345#socattcp-listen:12345-2.向远处tcp12345端口发点字#echo“test”|nc127.0.0.112345#echo“t…

    2022年4月8日
    53
  • Git规范:Git提交规范

    Git规范:Git提交规范1 Commitmessag 格式 type scope subject 1 type 必须 作用 用于说明 Gitcommit 的类别 只允许使用下面的标识 feat 新功能 feature fix to 修复 bug 可以是 QA QualityAssur 发现的 BUG 也可以是研发自己发现的 BUG 备注 fix 产生 diff 并自动修复此问题 适合于一次提交直接修复问题 to 只产生 diff 不自动修复此问题 subject scope type

    2025年11月5日
    3
  • 概率(Probability)的定义和性质

    描述性定义:在相同的条件下,独立重复地做NNN次试验,当试验次数NNN很大时,如果事件AAA发生的频率fN(A)fN(A)f_N(A)稳定地在[0,1][0,1][0,1]内的某一个数值ppp,而且一般来说随着试验次数的增多,这种摆动的幅度会越来越小,则称数值ppp为事件AAA发生的概率,记为P(A)=pP(A)=pP(A)=p…

    2022年4月5日
    122
  • django动态路由_路由器和转换器的区别

    django动态路由_路由器和转换器的区别自定义路径转换器有时候上面的内置的url转换器并不能满足我们的需求,因此django给我们提供了一个接口可以让我们自己定义自己的url转换器django内置的路径转换器源码解析在我们自定义路由转

    2022年7月29日
    6
  • pycharm编码设置为utf-8._python字符编码使用ascii编码对么

    pycharm编码设置为utf-8._python字符编码使用ascii编码对么我试着读入两个文本文件,一个用UTF8编码。我在PyCharm中使用python3。在两个文件中的示例:1.itsgroupareinSpain.itsgroupareinAntarctica.2.susgruposestanenEspaña.susgruposestanenAntártida.在命令行中,我使用:^{pr2}$把文件读入标准输入.在在我的…

    2022年8月28日
    4
  • windows server ftp服务器怎么搭建_serveru访问ftp

    windows server ftp服务器怎么搭建_serveru访问ftp首先说说什么是ftp?FTP协议是专门针对在两个系统之间传输大的文件这种应用开发出来的,它是TCP/IP协议的一部分。FTP的意思就是文件传输协议,用来管理TCP/IP网络上大型文件的快速传输。FTP最早也是在Unix上开发出来的,并且很长一段时间里只有Unix系统支持FTP功能,后来逐渐普及到其他系统,并成为Internet/Intranet网络中的标准组件。FTP服务器就是局域网信息资源的存储中心,主要是用来进行文件共享和传输。为了便于数据信息的共享和沟通,很多企业甚至个人都想搭建自己的ftp

    2025年11月2日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号