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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux重启网卡命令_linux重启网卡命令有哪些

    linux重启网卡命令_linux重启网卡命令有哪些在linux下改了ip地址后,不能立即生效。以前是重启机器,我觉得这样很傻,后来知道网卡可以重启。/etc/init.d/networkrestart

    2022年9月22日
    3
  • 宽字节注入原理_sqlmap宽字节注入

    宽字节注入原理_sqlmap宽字节注入在mysql中,用于转义的函数有addslashes,mysql_real_escape_string,mysql_escape_string等,还有一种情况是magic_quote_gpc,不过高版本的PHP将去除这个特性。首先,宽字节注入与HTML页面编码是无关的,笔者曾经看到<metacharset=utf8>就放弃了尝试,这是一个误区,SQL注入不是XSS。虽然他们中编码的成…

    2022年10月14日
    2
  • pytorch tensor转int_numpy和pytorch

    pytorch tensor转int_numpy和pytorchtensor转换为numpy采用.numpy()函数即可a=torch.tensor([1,2,3])print(a)print(type(a))print(a.dtype)b=a.numpy()print(b)print(type(b))print(b.dtype)输出:torch.tensor整数默认为int64即LongTensor小数默认为float32不过一般对tensor采用tensor.data()或者tensor.detach(

    2022年10月9日
    4
  • laravel 多个项目共享SESSION

    laravel 多个项目共享SESSION

    2021年11月7日
    47
  • c语言里void什么作用,C语言中void是什么意思?

    c语言里void什么作用,C语言中void是什么意思?C语言中void是什么意思?C语言中“void”表示为无类型,相应的“void*”为无类型指针,常用在程序编写中对定义函数的参数类型、返回值、函数中指针类型进行声明,其作用是对函数返回和参数的进行限定。C语言关键字auto:声明自动变量break:跳出当前循环case:开关语句分支char:声明字符型变量或函数返回值类型const:声明只读变量continue:结束当前循环,开始下一轮循环…

    2022年5月12日
    54
  • 电信dns地址是多少?

    电信dns地址是多少?安徽电信dns地址202.102.192.68202.102.199.68澳门电信dns地址202.175.3.8202.175.3.3北京电信dns地址202.96.199.133202.96.0.133202.106.0.20202.106.148.1重庆电信dns地址61.128.128.68…

    2022年7月15日
    19

发表回复

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

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