ATSHA204a - CheckMac with Roll Key Operation

Go To Last Post
2 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I have a ATSHA204a configured to roll the key in slot 4 when the derivedKey command is executed. In the below example, I am able to reset the key to its original value, then I use the deriveKey command to "roll" the key. My problem is calculating the new key to run the checkMac command. I am either not calculating the rolled key correctly and/or I am not calculating the mac correctly. Any help is appreciated. If anyone has a working example and willing to share, that would be great.

 

In the below example, the slot is configured as follows:

 

Encrypted Read & Write are allowed

MAC required for running the derviedKey command

Parent Key = Key 2

Read Key = Key 9

 

 

 

uint8_t sha204_validate_key_roll(uint8_t *rootkey){
	
	status = ATCA_SUCCESS;
	atca_nonce_in_out_t nonce_params;
	atca_temp_key_t temp_key;
	atca_check_mac_in_out_t checkmac_params;
	struct atca_derive_key_mac_in_out derivekey_mac_params;
	uint16_t target_key_id = 4;	
	
	uint8_t parent_key[ATCA_KEY_SIZE] = {0};
	uint8_t key_04[ATCA_KEY_SIZE] = {0};
	uint8_t other_data[13]  = {0};
	uint8_t mac[ATCA_SHA_DIGEST_SIZE] = { '\0'};	
	uint8_t calc_derived_key_input[96] = { '\0'};	
	uint8_t num_in[NONCE_NUMIN_SIZE] = { '\0'};	
	uint8_t rand_out[RANDOM_NUM_SIZE] = { '\0'};		
	uint8_t sn[9] = { '\0'};		
	uint8_t response[CHECKMAC_CLIENT_RESPONSE_SIZE] = { '\0'};		
	uint8_t derived_key[ATCA_KEY_SIZE] = { '\0'};	
	uint8_t challenge[CHECKMAC_CLIENT_CHALLENGE_SIZE] = {0};		
	memset(&derived_key, 0, ATCA_KEY_SIZE);	

	
	// get a random number for the challenge
	status = atcab_random(challenge);
	if(status != ATCA_SUCCESS){	sha204_parser_rc(status);return status;}	
	
	// calculate the parent key (0x02 - used for the encrypting the key
	status = sha204_create_diverse_key(rootkey, 0x02, parent_key, 0x77);
	if (status != ATCA_SUCCESS)
	{
		return status;		
	}			
	// calculate the known original key 4 - this key is derived from the root
	status = sha204_create_diverse_key(rootkey, target_key_id, key_04, 0x77);
	if (status != ATCA_SUCCESS)	{return status;}			
	
	// get the devices serial number
	status = atcab_read_serial_number(sn);
	if (status != ATCA_SUCCESS){sha204_parser_rc(status);return status;	}
	
	 // Initialize the slot with a known key. key 2 is used for encryption. Key 4 is derived from the root key  
	status = atcab_write_enc(target_key_id, 0, key_04, parent_key, 0x02);
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);return status;}	
	
	// create the mac required for derive key SlotConfig<TargetKey>.Bit15 == 1
	derivekey_mac_params.mode = DERIVE_KEY_MODE; 
	derivekey_mac_params.target_key_id = target_key_id;
	derivekey_mac_params.sn = sn;
	derivekey_mac_params.parent_key = parent_key;
	derivekey_mac_params.mac = mac;	
        status = atcah_derive_key_mac(&derivekey_mac_params);
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);	return status;	}		
	
	//create the key with the deriveKey command
	status=sha204_diverse_key_example(target_key_id, mac, 0x77);
	if (status != ATCA_SUCCESS){printf("Unable to run derivedKey Command: ");sha204_parser_rc(status);	return status;	}
	
	// Perform random nonce
	memset(&temp_key, 0, sizeof(temp_key));
	memset(num_in, 0, sizeof(num_in));
	memset(&nonce_params, 0, sizeof(nonce_params));
	nonce_params.mode = NONCE_MODE_SEED_UPDATE;
	nonce_params.zero = 0;
	nonce_params.num_in = num_in;
	nonce_params.rand_out = rand_out;
	nonce_params.temp_key = &temp_key;
	status = atcab_nonce_rand(nonce_params.num_in, rand_out);
	if (status != ATCA_SUCCESS)	{printf("Unable to atcab_nonce_rand:\n\r");	sha204_parser_rc(status);return status;	}
	
	// Calculate nonce value
	status = atcah_nonce(&nonce_params);
	if (status != ATCA_SUCCESS)	{printf("Unable to atcah_nonce:\n\r");	sha204_parser_rc(status);return status;	}
	
	uint8_t i;
	for (i = 0; i < sizeof(other_data); i++)
	{
		other_data[i] = (uint8_t)(i + 0xF0);
	}
	
	// calculate the new derived key
	memset(&calc_derived_key_input, 0, sizeof(calc_derived_key_input));
	memcpy(&calc_derived_key_input[0], key_04, sizeof(key_04));
	calc_derived_key_input[32] = ATCA_DERIVE_KEY;
	calc_derived_key_input[33] = CHECKMAC_MODE_BLOCK2_TEMPKEY; // param 1
	calc_derived_key_input[34] = (uint8_t)target_key_id; // param 2
	calc_derived_key_input[35] = 0x00;
	calc_derived_key_input[36] = sn[8];
	calc_derived_key_input[37] = sn[0];
	calc_derived_key_input[38] = sn[1];
	memcpy(&calc_derived_key_input[64], &temp_key.value[0], 32);			
	status = atcac_sw_sha2_256(calc_derived_key_input, sizeof(calc_derived_key_input), derived_key);
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);	return status;}		
	
	// Calculate response
	checkmac_params.mode = CHECKMAC_MODE_BLOCK2_TEMPKEY;
	checkmac_params.key_id = target_key_id;
	checkmac_params.client_chal = NULL;
	checkmac_params.client_resp = response;
	checkmac_params.other_data = other_data;
	checkmac_params.sn = sn;
	checkmac_params.otp = NULL;	
	checkmac_params.slot_key = derived_key;
	checkmac_params.target_key = derived_key;	
	checkmac_params.temp_key = &temp_key;
	
        status = atcah_check_mac(&checkmac_params); // software
        if (status != ATCA_SUCCESS){printf("Unable to atcah_check_mac for key %d:\n\r", target_key_id); sha204_parser_rc(status); return status; }
	
	// Perform CheckMac on Hardware
	status = atcab_checkmac(checkmac_params.mode,checkmac_params.key_id,checkmac_params.client_chal,
	checkmac_params.client_resp,checkmac_params.other_data);
	if (status != ATCA_SUCCESS)	{printf("Unable to atcab_checkmac for key %d: ", target_key_id);sha204_parser_rc(status);} 
			
	return status;
}

 

This topic has a solution.

"When all else fails, read the directions"

Last Edited: Thu. Jul 4, 2019 - 03:24 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A was able to figure this out. Posting the solution in hopes it will help someone else out.

 


/** \brief	Performs a Key Roll operation on key 04, then validates the calculated key with a checkmac.
		After the checkmac is run, the key is also validated with the gendig/checkmac commands.
							
		The SlotConfig<4> is set to 4  0xE2 0xD9 - A mac is required to run the derived key 
		
                Because the key rolls, you would need to keep track of how many times the derived key was run.
		This is normally done by checking the UpdateCount (run command (AC)). To keep things simple,
		we calculated the diversified key from the root, then do an encrypt write. This resets the key to
		a known value before rolling it. After the keys is "rolled" we validate it.  
 *  \param[in] root	pointer to the root key
 *  \return		ATCA_SUCCESS on success, otherwise an error code.
 */
uint8_t sha204_key_roll_example_validation(uint8_t *rootkey){
	 
	 printf("Running sha204_key_roll_test\n\r");	 
	 
	 status = ATCA_SUCCESS;		
	 uint16_t target_key_id = 4;
	 uint8_t key_04[ATCA_KEY_SIZE] = {0};
	 uint8_t parent_key[ATCA_KEY_SIZE] = {0};
	 uint8_t test_key[ATCA_KEY_SIZE] = {0};
	 uint8_t nonce_in[NONCE_NUMIN_SIZE_PASSTHROUGH] = {0};
	 uint8_t mac_param[88] = {0};	
	 uint8_t mac_out[MAC_CHALLENGE_SIZE] = {0};	 
	 uint8_t mac_mode = CHECKMAC_MODE_BLOCK1_TEMPKEY | CHECKMAC_MODE_SOURCE_FLAG_MATCH;	 		 
	 uint8_t mac[ATCA_SHA_DIGEST_SIZE] = { '\0'};	 
	 uint8_t calc_derived_key_input[ATCA_MSG_SIZE_DERIVE_KEY] = { '\0'};	
	 uint8_t nonce_seed_input[NONCE_NUMIN_SIZE_PASSTHROUGH] = {0};		 
	 uint8_t nonce_seed[NONCE_NUMIN_SIZE] = {0};
	 uint8_t derived_key[ATCA_KEY_SIZE] = {0};
	 uint8_t challenge[CHECKMAC_CLIENT_CHALLENGE_SIZE] = {0};  
	 uint8_t sn[ATCA_SERIAL_NUM_SIZE]= {0};  
	
	 atca_temp_key_t temp_key_params;	
	 struct atca_gen_dig_in_out gen_dig_params;
	 struct atca_derive_key_in_out derivekey_params;
	
	 uint8_t other_data[CHECKMAC_OTHER_DATA_SIZE] = {
		 ATCA_MAC, mac_mode, target_key_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	 };	 	 
	 status = atcab_random(nonce_seed_input);
	 if (status != ATCA_SUCCESS) { sha204_parser_rc(status); return status; }			 
	 memcpy(&nonce_seed[0], &nonce_seed_input[0], sizeof(nonce_seed));	 
	
	 status = atcab_random(challenge);
	 if (status != ATCA_SUCCESS) { sha204_parser_rc(status); return status; }		
	
	 // this can be anything
	 uint8_t other_data_offset[CHECKMAC_CLIENT_COMMAND_SIZE] = { ATCA_DERIVE_KEY, 0x05, target_key_id, 0x00 };

	// calculate the parent key (0x02 - used for the encrypting the key
	status = sha204_create_diverse_key(rootkey, 0x02, parent_key, 0x77);
	if (status != ATCA_SUCCESS) { return status; }
	printf("Created sha204_create_diverse_key parent...\n\r");	
	// calculate the known original key 4 - this key is derived from the root
	status = sha204_create_diverse_key(rootkey, target_key_id, key_04, 0x77);
	if (status != ATCA_SUCCESS)	{return status;}
	printf("Created sha204_create_diverse_key 0x04...\n\r");
	 // Read the device serial number
	status = atcab_read_serial_number(sn);
	if(status != ATCA_SUCCESS){	sha204_parser_rc(status);return status;}	
	printf("Read Serial Number complete:\t");
	print_buffer(sn, sizeof(sn));
	
	// load the nonce for the temp key - used later
	memset(&nonce_in[0], 0x77, sizeof(nonce_in)); // we padded with 0x77 -
	memcpy(&nonce_in[0], &sn[0], sizeof(sn)); // replace first 9 bytes with sn	
	
	// Initialize the slot with a known key - this basically starts the key roll back at the beginning	
	status = atcab_write_enc(target_key_id, 0, key_04, parent_key, 0x02);
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);return status;}	
	printf("Slot %d reset to original value: ", target_key_id);
	print_buffer(key_04, 32);
   
	// create the mac required for derive key SlotConfig<TargetKey>.Bit15 == 1
	struct atca_derive_key_mac_in_out derivekey_mac_params;
	derivekey_mac_params.mode = DERIVE_KEY_MODE; // 0x04
	derivekey_mac_params.target_key_id = target_key_id;
	derivekey_mac_params.sn = sn;
	derivekey_mac_params.parent_key = parent_key;
	derivekey_mac_params.mac = mac;
	status = atcah_derive_key_mac(&derivekey_mac_params);
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);	return status;	}
	printf("Mac required for derived key complete....\n\r");
	
	memset(&temp_key_params, 0, sizeof(temp_key_params));  
	// Calculate the derived key
	temp_key_params.source_flag = 1;
	temp_key_params.valid = 1;
	memcpy(&temp_key_params.value[0], &nonce_in[0], sizeof(nonce_in));	
	derivekey_params.mode = DERIVE_KEY_MODE; // Random nonce generated TempKey // 0x04
	derivekey_params.target_key_id = target_key_id;
	derivekey_params.parent_key = key_04;
	derivekey_params.sn = sn;
	derivekey_params.target_key = derived_key;
	derivekey_params.temp_key = &temp_key_params;	 	
	status = atcah_derive_key(&derivekey_params); 	 	
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);	return status;}
		
	printf("Calculating the derived key complete...\n\r");  
	printf("Calculated Derived Key:\t\t");	
	print_buffer(derived_key, 32);
	 
	// how to manually calculate the key - calculate the new derived key - only leaving for tutorial
	memset(&calc_derived_key_input, 0, sizeof(calc_derived_key_input));
	memcpy(&calc_derived_key_input[0], key_04, sizeof(parent_key));
	calc_derived_key_input[32] = ATCA_DERIVE_KEY;
	calc_derived_key_input[33] = DERIVE_KEY_MODE; // param 1 0x04
	calc_derived_key_input[34] = (uint8_t)target_key_id; // param 2
	calc_derived_key_input[35] = 0x00;
	calc_derived_key_input[36] = sn[8];
	calc_derived_key_input[37] = sn[0];
	calc_derived_key_input[38] = sn[1];
	memcpy(&calc_derived_key_input[64], &temp_key_params.value[0], 32);
	status = atcac_sw_sha2_256(calc_derived_key_input, sizeof(calc_derived_key_input), test_key);
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);	return status;}	
		
	 //create the key with the deriveKey command
	status=sha204_diverse_key_example(target_key_id, mac, 0x77);
	if (status != ATCA_SUCCESS){printf("Unable to run derivedKey Command: ");sha204_parser_rc(status);	return status;	}
	 		
	// load the derived key into the temp key register (pass-through)
	status = atcab_nonce_load(NONCE_MODE_PASSTHROUGH, derived_key, sizeof(derived_key)); // load the temp key with sn and random bytes - pass through		 
	if(status != ATCA_SUCCESS){sha204_parser_rc(status);return status;}	
		
	// build mac for checkmac 	
	memset(&mac_param[0], 0, sizeof(mac_param));
	memcpy(&mac_param[0], &derived_key[0], 32);
	memcpy(&mac_param[32], &challenge[0], 32);		
	
	mac_param[64] = other_data[0];
	mac_param[65] = other_data[1];
	mac_param[66] = other_data[2];
	mac_param[67] = other_data[3];	
	mac_param[76] = other_data[4];
	mac_param[77] = other_data[5];
	mac_param[79] = other_data[6];
	mac_param[79] = sn[8];
	mac_param[80] = other_data[7];
	mac_param[81] = other_data[8];
	mac_param[82] = other_data[9];
	mac_param[83] = other_data[10];
	mac_param[84] = sn[0];
	mac_param[85] = sn[1];
	mac_param[86] = other_data[11];
	mac_param[87] = other_data[12];
	
	status = atcac_sw_sha2_256(mac_param, sizeof(mac_param), mac_out);
	if (status != ATCA_SUCCESS)	{sha204_parser_rc(status);return status;}	
	
	// Run the checkmac command to validate the calculated derived key	-
	
	status = atcab_checkmac(mac_mode, target_key_id, challenge, mac_out, other_data);
		
	if(status != ATCA_SUCCESS){printf("atcab_checkmac failed: \n\r");sha204_parser_rc(status);return status;}	
	printf("Simple validation complete... now try a gendig\n\r");	
	
	status = atcab_nonce_load(NONCE_MODE_PASSTHROUGH, nonce_in, sizeof(nonce_in)); // load the temp key with sn and random bytes - pass through	
	if(status != ATCA_SUCCESS){sha204_parser_rc(status);return status;}
	printf("TempKey loaded with a Pass-Through Nonce...\n\r");	
	
	// create the temp key in the client tempkey register		
	status = atcab_gendig(GENDIG_ZONE_DATA, target_key_id, other_data_offset, sizeof(other_data_offset));
	if(status != ATCA_SUCCESS){	printf("Failed GENDIG:");sha204_parser_rc(status);return status;}		
	
	// calculated the temp key on the host - this should match what the gendig command created 	
	gen_dig_params.zone = ATCA_ZONE_DATA;
	gen_dig_params.key_id = target_key_id;
	gen_dig_params.stored_value = derived_key;
	gen_dig_params.sn = sn;
	gen_dig_params.temp_key = &temp_key_params;
	gen_dig_params.other_data = other_data_offset;
	gen_dig_params.is_key_nomac = true;
	status = atcah_gen_dig(&gen_dig_params);
		
	// now calculate the mac with the tempkey.	
	memset(&gen_dig_params, 0, sizeof(gen_dig_params));
	struct atca_check_mac_in_out test_mac_host;
	test_mac_host.mode = 0x06;
	test_mac_host.key_id = target_key_id;
	test_mac_host.client_chal = challenge;
	test_mac_host.client_resp = mac_out;
	test_mac_host.target_key = derived_key;
	test_mac_host.sn = sn;
	test_mac_host.temp_key = &temp_key_params;
	test_mac_host.other_data = other_data_offset;	
	status = atcah_check_mac(&test_mac_host);
	if (status != ATCA_SUCCESS)	{printf("Failed Host Check MAC:"); sha204_parser_rc(status);return status;}
				
	printf("Checking the digest internally...\n\r");
	status = atcab_checkmac(0x06, target_key_id, challenge, mac_out, other_data_offset);

	if (status != ATCA_SUCCESS)	{printf("CheckMac Failed!");sha204_parser_rc(status);}
			
	return status;
}

 

"When all else fails, read the directions"