ATECC508A加密芯片

ATECC508A加密芯片使用

开一个帖子交流下ATECC508A,也包括同类型芯片ATSHA208A

  • demo使用
  • 串口调试
  • ConfigZone配置
  • DataZone配置
  • 加密读写
  • 挑战(challenge)应答及校验
  • Openssl相关
  • 证书相关

demo使用

目前官网上能下载到的demo有cryptoauth-node-auth-basiccryptoauth-d21-host
接下来的问题围绕着demo中代码展开讨论

串口调试

官方调试开发板
MAU主板
使用的是官方的开发板进行了测试

ConfigZone配置

datasheet中的说明如下图
这里写图片描述

重点说一下ReadKey和WriteKey,恰恰是这两个简单的说明,让人不清楚这两个参数如何使用。
在bit6和bit7配置为1的时候,本slot需要加密读或者写,所以需要秘钥,这个秘钥是需要存储在parent slot中的,这个parent slot的ID就是这两个Key。所以加密读写slot的时候,需要首先在parent key的slot中写入秘钥,然后再修改需要加密读写的slot。

DataZone配置

待补充
##Demo数据分析
Demo中提供了一套配置参数,解析如下

tatic const uint8_t g_ecc_configdata[128] = {
0x01, 0x23, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x04, 0x05, 0x06, 0x07, 0xEE, 0x00, 0x01, 0x00,
0xC0, 0x00, 0x55, 0x00, 0x8F, 0x20, 0xC4, 0x44, 0x87, 0x20, 0xC4, 0x44, 0x8F, 0x0F, 0x8F, 0x8F,
0x9F, 0x8F, 0x83, 0x64, 0xC4, 0x44, 0xC4, 0x44, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x33, 0x00, 0x1C, 0x00, 0x13, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x33, 0x00,
0x1C, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x3C, 0x00 };

利用程序分析如下:

serial NUM: 0x01 0x23 0x00 0x00 0x04 0x05 0x06 0x07 0xee
I2C enable: 0x01
I2C address: 0xc0
check mac: 0x00
OPT mode: 0x55
chip mode: 0x00
slot00 config: 0x8f 0x20 ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:1; WriteKey:0B0000; WriteConfig:0B0010;
slot01 config: 0xc4 0x44 ; ReadKey:0B0100; NoMac:0; LimitUse:0; EncryptRead:1; IsSecret:1; WriteKey:0B0100; WriteConfig:0B0100;
slot02 config: 0x87 0x20 ; ReadKey:0B0111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:1; WriteKey:0B0000; WriteConfig:0B0010;
slot03 config: 0xc4 0x44 ; ReadKey:0B0100; NoMac:0; LimitUse:0; EncryptRead:1; IsSecret:1; WriteKey:0B0100; WriteConfig:0B0100;
slot04 config: 0x8f 0x0f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:1; WriteKey:0B1111; WriteConfig:0B0000;
slot05 config: 0x8f 0x8f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:1; WriteKey:0B1111; WriteConfig:0B1000;
slot06 config: 0x9f 0x8f ; ReadKey:0B1111; NoMac:1; LimitUse:0; EncryptRead:0; IsSecret:1; WriteKey:0B1111; WriteConfig:0B1000;
slot07 config: 0x83 0x64 ; ReadKey:0B0011; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:1; WriteKey:0B0100; WriteConfig:0B0110;
slot08 config: 0xc4 0x44 ; ReadKey:0B0100; NoMac:0; LimitUse:0; EncryptRead:1; IsSecret:1; WriteKey:0B0100; WriteConfig:0B0100;
slot09 config: 0xc4 0x44 ; ReadKey:0B0100; NoMac:0; LimitUse:0; EncryptRead:1; IsSecret:1; WriteKey:0B0100; WriteConfig:0B0100;
slot10 config: 0x0f 0x0f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:0; WriteKey:0B1111; WriteConfig:0B0000;
slot11 config: 0x0f 0x0f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:0; WriteKey:0B1111; WriteConfig:0B0000;
slot12 config: 0x0f 0x0f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:0; WriteKey:0B1111; WriteConfig:0B0000;
slot13 config: 0x0f 0x0f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:0; WriteKey:0B1111; WriteConfig:0B0000;
slot14 config: 0x0f 0x0f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:0; WriteKey:0B1111; WriteConfig:0B0000;
slot15 config: 0x0f 0x0f ; ReadKey:0B1111; NoMac:0; LimitUse:0; EncryptRead:0; IsSecret:0; WriteKey:0B1111; WriteConfig:0B0000;
counter 0: 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00
counter 1: 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00
LastKeyUse:0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff
UserEctrax: 0x00
SelectorX: 0x00
LockValue: 0x00
LockConfig: 0x00
SlotLockedX: 0xff 0xff
Rfu90: 0x00 0x00
X509Format : 0x00 0x00 0x00 0x00
KeyConfig00 config: 0x33 0x00 ; Private:1; Pubinfo:1; KeyType:0B100;
KeyConfig01 config: 0x1c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig02 config: 0x13 0x00 ; Private:1; Pubinfo:1; KeyType:0B100;
KeyConfig03 config: 0x1c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig04 config: 0x3c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig05 config: 0x1c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig06 config: 0x1c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig07 config: 0x33 0x00 ; Private:1; Pubinfo:1; KeyType:0B100;
KeyConfig08 config: 0x1c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig09 config: 0x1c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig10 config: 0x3c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig11 config: 0x3c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig12 config: 0x3c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig13 config: 0x3c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig14 config: 0x3c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;
KeyConfig15 config: 0x3c 0x00 ; Private:0; Pubinfo:0; KeyType:0B111;

加密读写

Datasheet上表示了加密读写的两种用法,但是描述不清楚,或者因为个人理解有限吧。
参照cryptoauth-node-auth-basicdemo中的函数说明,测试了加密读写接口,文件为atca_basic.c文件中的两个函数
加密写接口如下

/** \brief Write 32 bytes of data into given slot.
 *		The function takes clear text bytes, but encrypts them for writing over the wire
 *		Data zone must be locked and the slot configuration must be set to encrypted write for the block to be successfully written
 *  \param[in] slotid
 *  \param[in] block
 *  \param[in] data      The 32 bytes of clear text data to be written to the slot
 *  \param[in] enckey    The key to encrypt with for writing
 *  \param[in] enckeyid  The keyid of the parent encryption key
 *  returns ATCA_STATUS
 */
ATCA_STATUS atcab_write_enc(uint8_t slotid, uint8_t block, const uint8_t *data, const uint8_t* enckey, const uint16_t enckeyid)

加密读接口如下

/** \brief Read 32 bytes of data from the given slot.
 *		The function returns clear text bytes. Encrypted bytes are read over the wire, then subsequently decrypted
 *		Data zone must be locked and the slot configuration must be set to encrypted read for the block to be successfully read
 *  \param[in]  slotid    The slot id for the encrypted read
 *  \param[in]  block     The block id in the specified slot
 *  \param[out] data      The 32 bytes of clear text data that was read encrypted from the slot, then decrypted
 *  \param[in]  enckey    The key to encrypt with for writing
 *  \param[in]  enckeyid  The keyid of the parent encryption key
 *  returns ATCA_STATUS
 */
ATCA_STATUS atcab_read_enc(uint8_t slotid, uint8_t block, uint8_t *data, const uint8_t* enckey, const uint16_t enckeyid)

目前疑惑的地方就是这个enckey参数,究竟是从哪里来的,我随意写出来的enckey参数,加密写入没问题,但是读取的时候,就会返回出来错误的数据,与写入的不一致,希望能有人一起讨论一下
2017-10-11 15:51(修改)
问题已经解决,这个enckey是需要首先写入芯片,作为存储秘钥的slot的parent slot,并且这个enckye在随后向slot写入和读取秘钥的时候,都是作为必备参数的。

挑战(challenge)应答及校验

芯片本身的挑战响应与校验方式很简单,参照文件node_auth.c中的两个函数,改写测试函数如下
slot0提供公钥,host得到公钥保存起来。

static int get_pub_key(void)
{
	int ret = 0;
	int i = 0;
	
	
	//slot0上生成key
	ret = atcab_genkey(0, device_public_key);
	if (ret != ATCA_SUCCESS) return ret;
	
	printf("\r\n device_public_key:");
	for(i=0;i<64;i++)
	{
		printf("0x%02x,",device_public_key[i]);
	}
	printf("\r\n"); 
	
	char displaystr[256];
	int displaylen = sizeof(displaystr);	

	atcab_bin2hex(device_public_key, 64, displaystr, &displaylen );
	printf("\r\n device_public_key:\r\n%s\r\n", displaystr);

	return 0;
	
}

host随机一个挑战,发送给芯片,芯片用slot0做出应答,
挑战应答函数如下

static int get_response(void)
{
	int ret = 0;
	int i = 0;

	//设备使用slot0响应challenge,得到response
	ret = atcacert_get_response(0, s_challenge, s_response);
	if (ret != ATCACERT_E_SUCCESS) return ret;

	printf("\r\n s_response:");
	for(i=0;i<64;i++)
	{
		printf("0x%02x,",s_response[i]);
	}
	printf("\r\n");
	
	char displaystr[256];
	int displaylen = sizeof(displaystr);	

	atcab_bin2hex(s_response, 64, displaystr, &displaylen );
	printf("\r\n s_response:\r\n%s\r\n", displaystr);
	return 0;
}

这样host拥有了公钥,挑战,和挑战应答,就可以验证芯片是否合法有效了

芯片本身也可以检查其他人发送过来的,公钥,挑战和应答是否合法有效
应答检查函数如下

static int check_response(void)
{
	int ret = 0;
	int i = 0;
	char displaystr[256];
	int displaylen = sizeof(displaystr);	
	char displaystr2[256];
	int displaylen2 = sizeof(displaystr);	
	char displaystr3[256];
	int displaylen3 = sizeof(displaystr);	



	//检验设备应答
	ret = atcacert_verify_response_hw(device_public_key, s_challenge, s_response);


	printf("\r\n device_public_key:");
	for(i=0;i<64;i++)
	{
		printf("0x%02x,",device_public_key[i]);
	}
	printf("\r\n");  

	atcab_bin2hex(device_public_key, 64, displaystr, &displaylen );
	printf("\r\n device_public_key:\r\n%s\r\n", displaystr);

	printf("\r\n s_challenge:");
	for(i=0;i<32;i++)
	{
		printf("0x%02x,",s_challenge[i]);
	}
	printf("\r\n");  

	memset(displaystr,0x0,256);
	atcab_bin2hex(s_challenge, 32, displaystr2, &displaylen2 );
	printf("\r\n s_challenge:\r\n%s\r\n", displaystr2);


	printf("\r\n s_response:");
	for(i=0;i<64;i++)
	{
		printf("0x%02x,",s_response[i]);
	}
	printf("\r\n");  

	memset(displaystr,0x0,256);
	atcab_bin2hex(s_response, 64, displaystr3, &displaylen3 );
	printf("\r\n s_response:\r\n%s\r\n", displaystr3);


	if (ret != ATCACERT_E_SUCCESS)
	{
    		printf("HOST: Device response to challenge fail!\r\n");
	}
	else
	{
    		printf("HOST: Device response to challenge verified!\r\n");

	}
    
	return ret;
}

##Openssl相关
之所以提到Openssl,例如在检查挑战应答是否合法的时候,是在host里面,如果host里面没有ATECC508芯片的话,那就需要软件实现ECDSA算法来校验应答是否正确

网上查看了相关同学的博客,也没有找到合适的C语言代码
结合openssl的头文件,找到了一个相关函数
说明如下

/** Verifies that the given signature is valid ECDSA signature
 *  of the supplied hash value using the specified public key.
 *  \param  type     this parameter is ignored
 *  \param  dgst     pointer to the hash value
 *  \param  dgstlen  length of the hash value
 *  \param  sig      pointer to the DER encoded signature
 *  \param  siglen   length of the DER encoded signature
 *  \param  eckey    EC_KEY object containing a public EC key
 *  \return 1 if the signature is valid, 0 if the signature is invalid
 *          and -1 on error
 */
int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen,
                 const unsigned char *sig, int siglen, EC_KEY *eckey);

2017-10-12 补充
编写了一段代码模拟主机验证挑战、应答和公钥的正确性

#include <openssl/crypto.h>
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/ec.h>

#define MAXSIGLEN  128 
 
// 公钥
static const unsigned char pubkey[64] = 
	{0x6a,0x06,0x81,0x17,0x1a,0x20,0xa1,0x4b,0xed,0x75,
	0x14,0xc9,0x81,0xc0,0x03,0xfc,0x4a,0x28,0x11,0x58,
	0x08,0xc2,0x0b,0xf5,0x99,0xc2,0x3b,0x33,0x33,0x50,
	0xb6,0x17,0x69,0x0d,0x56,0x05,0x3a,0xe4,0x06,0x49,
	0xc3,0x3f,0xbb,0x0c,0xa3,0xaf,0x91,0xc5,0x26,0x20,
	0xc5,0xa7,0x55,0xdf,0x33,0xd7,0x9e,0x82,0xba,0x9a,
	0x57,0x3f,0x12,0x6c}; 

unsigned char challenge[32]=
	{0x0c,0xa6,0x34,0xc8,0x37,0x2f,0x87,0x99,0x99,0x7e,
	0x9e,0xe9,0xd5,0xbc,0x72,0x71,0x84,0xd1,0x97,0x0a,
	0xea,0xfe,0xac,0x60,0x7e,0xd1,0x3e,0x12,0xb7,0x32,0x25,0xf1};
unsigned char response[64]=
	{0x46,0x59,0x81,0xfd,0x7b,0xb3,0xc9,0x78,0x9f,0x12,
	0x33,0x8b,0x3a,0x6a,0x3c,0x07,0xaa,0x64,0x1d,0xa9,
	0xf5,0x5a,0x6f,0x26,0x40,0xc2,0x6f,0x2d,0x39,0xe1,
	0x80,0xc1,0xe4,0x2e,0xfb,0x9a,0xc2,0x05,0xd9,0xb3,
	0x82,0xe2,0x9b,0xe5,0xf2,0xd0,0x5b,0x0b,0xaf,0x6c,
	0xf1,0x27,0x88,0xc6,0x74,0xec,0xf7,0x88,0xc0,0xae,
	0xdc,0x0c,0x83,0x6a};

 /* 验证函数 */ 
static int verify(int keytype,const unsigned char *sig,int siglen,const unsigned char *dig,int dig_len)
{
	int ret;
	EC_KEY *ec_key = NULL;
	EC_GROUP *ec_group;
	unsigned char *pp = (unsigned char*)pubkey;


	if ((ec_key = EC_KEY_new()) == NULL)
	{
		printf("Error:EC_KEY_new();");
		return -1;
	}
	if ((ec_group = EC_GROUP_new_by_curve_name(keytype)) == NULL)
	{
		printf("Error:EC_GROUP_new_by_curve_name()\n");
		EC_KEY_free(ec_key);
		return -1;
	}

	/* 设置密钥参数 */
	ret=EC_KEY_set_group(ec_key,ec_group);
	if(ret!=1)
	{
		printf("Error:EC_KEY_set_group;");
		EC_KEY_free(ec_key);
		return -1;
	}

	/* 导入公钥 */
	ec_key = o2i_ECPublicKey(&ec_key,(const unsigned char**)&pp,sizeof(pubkey));
	if (ec_key == NULL)
	{
		printf("Error:o2i_ECPublicKey ;");
		EC_KEY_free(ec_key);
		return 0;
	}  
	
	/*
	ret=EC_KEY_oct2key(ec_key,pubkey,64,NULL);
	if(ret!=1)
	{
		printf("Error:EC_KEY_oct2priv;");
		EC_KEY_free(ec_key);
		return -1;
	}
	*/
	/* 验证签名 */
	ret = ECDSA_verify(0,(const unsigned char*)dig, dig_len, sig, siglen,ec_key);  
	EC_KEY_free(ec_key);
	return ret == 1 ? 1 : 0;
}  

/* 主函数 */
int main(int argc, char* argv[]) 
{
       EC_builtin_curve    *curves;

       int                 i,crv_len;
	unsigned char digest[32]={};
	unsigned int  dgst_len = 0;

	EVP_MD_CTX *md_ctx = EVP_MD_CTX_new();
	EVP_DigestInit(md_ctx, EVP_sha256()); // 散列算法
	EVP_DigestUpdate(md_ctx, (const void*)challenge,32);
	EVP_DigestFinal(md_ctx, digest, &dgst_len);


	printf("digest:");
	for(i=0;i<dgst_len;i++)
	{
		printf("0x%02x ",digest[i]);
	}
	printf("\r\n");
	
 	/* 获取实现的椭圆曲线个数 */
       crv_len = EC_get_builtin_curves(NULL, 0);
       curves = (EC_builtin_curve *)malloc(sizeof(EC_builtin_curve) * crv_len);
       /* 获取椭圆曲线列表 */
       EC_get_builtin_curves(curves, crv_len);
	  
	for(i=0;i<crv_len;i++)
	{
		//printf("curves[%d]:[%d]%s \r\n",i,curves[i].nid,curves[i].comment);
		int ret = verify(curves[i].nid,(const unsigned char *)&response,sizeof(response),(const unsigned char *)&digest,dgst_len);
		if(ret==1)
		{
			printf("|keytype:[%d]:[%s] Verify:OK\n",curves[i].nid,curves[i].comment);
		}
		else
		{
			printf("|keytype:[%d]:[%s] Verify:Error\n",curves[i].nid,curves[i].comment);
		}
	}
	return 0;
}

目前还是存在问题,o2i_ECPublicKey将秘钥从buffer导出成EC_KEY格式的时候一直有问题,目前尚不清楚原因为何

##证书相关

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖哥王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值