uint8_t atsha204Class::sha204c_wakeup(uint8_t *response) { uint8_t ret_code = sha204p_wakeup(); if (ret_code != SHA204_SUCCESS) return ret_code; ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); if (ret_code != SHA204_SUCCESS) return ret_code; // Verify status response. Serial.print("Buffer pos: "); Serial.println(response[SHA204_BUFFER_POS_COUNT]); if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) ret_code = SHA204_INVALID_SIZE; else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) ret_code = SHA204_COMM_FAIL; else { if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) ret_code = SHA204_BAD_CRC; } if (ret_code != SHA204_SUCCESS) delay(SHA204_COMMAND_EXEC_MAX); return ret_code; }
/** \brief This function is the entry function for an example application that uses the SHA204 ASF component. * \return result (0: success, otherwise failure) */ int main(void) { static uint8_t tx_buffer_command[CHECKMAC_COUNT]; // biggest command in this example static uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; static uint8_t challenge[MAC_CHALLENGE_SIZE]; static uint8_t other_data[CHECKMAC_OTHER_DATA_SIZE]; uint8_t sha204_lib_return = SHA204_SUCCESS; uint32_t loop_count = 0; uint8_t i2c_address_index = 0; uint8_t twi_address_client; uint8_t twi_address_host; // Initialize system clock. sysclk_init(); // Initialize board. board_init(); // Initialize logging (USART). log_init(); // Initialize interrupt vectors. irq_initialize_vectors(); // Send example info. log_sha204_title("ATSHA204 Mac / CheckMac Example\r\n"); // Indicate entering main loop. led_display_number(0xFF); sha204h_delay_ms(1000); // The main loop wakes up all four devices, sends a Mac command to one serving // as a client, and subsequently a CheckMac command with the Mac challenge and response data // to another SHA204 serving as a host. At the end of the loop, all four devices // are put back to sleep by sending a Sleep command to every one of them. while (true) { // Indicate success or error for some time. led_display_number(sha204_lib_return); sha204h_delay_ms(1000); log_sha204_title("----------------------"); sprintf((char *) tx_buffer_command, "loop count = %lu", loop_count++); log_sha204_title((char *) tx_buffer_command); // Indicate that Mac / CheckMac command sequence is running. led_display_number(0xFF); // Generate Wakeup pulse. All SHA204 devices that share SDA will wake up. log_sha204_title("generating 60 us Wakeup low pulse on TWI SDA"); sha204_lib_return = sha204p_wakeup(); if (sha204_lib_return != SHA204_SUCCESS) { // todo Indicate Wakeup failure. continue; } // Exercise all four devices. twi_address_client = sha204_i2c_address(i2c_address_index % 4); i2c_address_index++; twi_address_host = sha204_i2c_address(i2c_address_index % 4); i2c_address_index++; // --------------------------------------------------------------------------------- // Now let's send a Mac to one SHA204, and verify the generated Mac with a second // SHA204 serving as a host device. In this example, we are not using the Nonce // command but the least secure and simplest mode. // Let host generate a random number to use as Mac challenge. An unlocked SHA204 // will always generate "FFFF0000FFFF0000...". struct sha204_random_parameters random; random.mode = 0; random.tx_buffer = tx_buffer_command; random.rx_buffer = rx_buffer; sha204p_set_device_id(twi_address_host); log_sha204_title("sending Random command to host"); sha204_lib_return = sha204m_random(&random); log_sha204(random.tx_buffer[SHA204_COUNT_IDX], random.tx_buffer, false); if (sha204_lib_return != SHA204_SUCCESS) { sha204_sleep_all(); continue; } log_sha204(random.rx_buffer[SHA204_COUNT_IDX], random.rx_buffer, true); // Save challenge for subsequent CheckMac command. memcpy(challenge, &random.rx_buffer[SHA204_BUFFER_POS_DATA], sizeof(challenge)); // Send Mac command to client. struct sha204_mac_parameters mac; mac.mode = 0; mac.key_id = 0; mac.challenge = challenge; mac.tx_buffer = tx_buffer_command; mac.rx_buffer = rx_buffer; sha204p_set_device_id(twi_address_client); log_sha204_title("sending Mac command to client"); sha204_lib_return = sha204m_mac(&mac); log_sha204(mac.tx_buffer[SHA204_COUNT_IDX], mac.tx_buffer, false); if (sha204_lib_return != SHA204_SUCCESS) { sha204_sleep_all(); continue; } log_sha204(mac.rx_buffer[SHA204_COUNT_IDX], mac.rx_buffer, true); // Save first four bytes of Mac command for subsequent CheckMac command. memset(other_data, 0, CHECKMAC_OTHER_DATA_SIZE); memcpy(other_data, &tx_buffer_command[SHA204_OPCODE_IDX], CHECKMAC_CLIENT_COMMAND_SIZE); // Send CheckMac command to host. struct sha204_check_mac_parameters check_mac; check_mac.mode = 0; check_mac.key_id = 0; check_mac.client_challenge = challenge; check_mac.client_response = &rx_buffer[SHA204_BUFFER_POS_DATA]; check_mac.other_data = other_data; check_mac.tx_buffer = tx_buffer_command; check_mac.rx_buffer = rx_buffer; sha204p_set_device_id(twi_address_host); log_sha204_title("sending CheckMac command to host"); sha204_lib_return = sha204m_check_mac(&check_mac); log_sha204(check_mac.tx_buffer[SHA204_COUNT_IDX], check_mac.tx_buffer, false); if (sha204_lib_return != SHA204_SUCCESS) { sha204_sleep_all(); continue; } log_sha204(check_mac.rx_buffer[SHA204_COUNT_IDX], check_mac.rx_buffer, true); log_sha204_title("sending a Sleep command to all devices"); sha204_sleep_all(); // Display response status byte. sha204_lib_return = check_mac.rx_buffer[SHA204_BUFFER_POS_STATUS]; } return sha204_lib_return; }
/** * \brief This function runs a SHA204 Read test on all four devices. * * This test wakes up the devices, reads their TWI addresses from * their Config zone, and sends them back to sleep. The test fails if * there are communication failures or the TWI addresses do not match. * * \param test current test case */ static void test_all_devices(const struct test_case *test) { test_assert_true(test, success, "Previous test failed."); success = false; uint8_t sha204_status; uint8_t i; uint8_t twi_address; uint8_t twi_address_retrieved = 0; uint8_t command[READ_COUNT]; uint8_t response[READ_4_RSP_SIZE]; sha204_status = sha204p_wakeup(); test_assert_true(test, sha204_status == SHA204_SUCCESS, "Sending Wakeup token failed."); // Address 16 holds the TWI address. struct sha204_read_parameters args = {.tx_buffer = command, .rx_buffer = response, .zone = SHA204_ZONE_CONFIG, .address = 16}; // Read TWI address from all four devices that are mounted on the Security Xplained extension board. for (i = 0; i < SHA204_DEVICE_COUNT; i++) { twi_address = sha204_i2c_address(i); sha204p_set_device_id(twi_address); memset(response, 0, sizeof(response)); success = false; sha204_status = sha204m_read(&args); if (sha204_status != SHA204_SUCCESS) break; twi_address_retrieved = args.rx_buffer[SHA204_BUFFER_POS_DATA] & 0xFE; if (twi_address_retrieved != twi_address) break; sha204_status = sha204p_sleep(); if (sha204_status != SHA204_SUCCESS) break; success = true; } // Sleep remaining devices in case one of them failed. for (; i < SHA204_DEVICE_COUNT; i++) { twi_address = sha204_i2c_address(i); sha204p_set_device_id(twi_address); sha204p_sleep(); } test_assert_true(test, sha204_status == SHA204_SUCCESS, "Communication error."); test_assert_true(test, twi_address_retrieved == twi_address, "TWI address does not match."); success = true; } //! \name Unit test configuration //@{ /** * \def CONF_TEST_USART * \brief USART to redirect STDIO to */ /** * \def CONF_TEST_BAUDRATE * \brief Baudrate of USART */ /** * \def CONF_TEST_CHARLENGTH * \brief Character length (bits) of USART */ /** * \def CONF_TEST_PARITY * \brief Parity mode of USART */ /** * \def CONF_TEST_STOPBITS * \brief Stop bit configuration of USART */ //@} /** * \brief This function runs ATSHA204 component unit tests. */ int main (void) { const usart_serial_options_t usart_serial_options = { .baudrate = CONF_TEST_BAUDRATE, .charlength = CONF_TEST_CHARLENGTH, .paritytype = CONF_TEST_PARITY, .stopbits = CONF_TEST_STOPBITS, }; sysclk_init(); board_init(); pmic_init(); sleepmgr_init(); stdio_serial_init(CONF_TEST_USART, &usart_serial_options); // Enable low level interrupts pmic_enable_level(PMIC_LVL_LOW); // Enable interrupt requests cpu_irq_enable(); // Define all the test cases DEFINE_TEST_CASE(sha204_test1, NULL, test_sha204_wakeup, NULL, "Testing Wakeup / Sleep"); DEFINE_TEST_CASE(sha204_test2, NULL, test_all_devices, NULL, "Testing all devices"); // Put test case addresses in an array DEFINE_TEST_ARRAY(sha204_tests) = { &sha204_test1, &sha204_test2 }; // Define the test suite DEFINE_TEST_SUITE(sha204_suite, sha204_tests, "XMEGA ATSHA204 component test suite"); // Run all tests in the test suite test_suite_run(&sha204_suite); while (1) { // Loop for infinity } }
uint8_t encrypted_read(int fd, uint16_t key_id, uint8_t *key_value,uint16_t slot, uint8_t *readdata) { int i; static uint8_t status = SHA204_SUCCESS; static uint8_t tmpdata[0x20] = {0}; static uint8_t random_number[0x20] = {0}; // Random number returned by Random NONCE command static uint8_t computed_response[0x20] = {0}; // Host computed expected response struct sha204h_decrypt_in_out decrypt_param; // Parameter for decrypt helper function struct sha204h_nonce_in_out nonce_param; // Parameter for nonce helper function struct sha204h_gen_dig_in_out gendig_param; // Parameter for gen_dig helper function struct sha204h_temp_key computed_tempkey; // TempKey parameter for nonce and gen_dig helper function //add by jli :That before every executing cmd sent to ATSHA204 chip should have waked it up once! sha204p_wakeup(fd); printf("ATSHA204A encrypted read !\n"); //nonce operation cmd_args.op_code = SHA204_NONCE; cmd_args.param_1 = NONCE_MODE_SEED_UPDATE; cmd_args.param_2 = NONCE_PARAM2; cmd_args.data_len_1 = NONCE_NUMIN_SIZE; cmd_args.data_1 = read_num_in; cmd_args.data_len_2 = 0; cmd_args.data_2 = NULL; cmd_args.data_len_3 = 0; cmd_args.data_3 = NULL; cmd_args.tx_size = NONCE_COUNT_SHORT; cmd_args.tx_buffer = global_tx_buffer; cmd_args.rx_size = NONCE_RSP_SIZE_LONG; cmd_args.rx_buffer = global_rx_buffer; status = sha204m_execute(fd,&cmd_args); //sha204p_idle(fd); if(status != SHA204_SUCCESS) { printf(" Mathine NONCE FAILED! \n"); return -1; } // Capture the random number from the NONCE command if it were successful memcpy(random_number,&global_rx_buffer[1],0x20); //host nonce operation nonce_param.mode = NONCE_MODE_SEED_UPDATE; nonce_param.num_in = read_num_in; nonce_param.rand_out = random_number; nonce_param.temp_key = &computed_tempkey; status = sha204h_nonce(nonce_param); if(status != SHA204_SUCCESS) { printf("HOST NONCE FAILED! \n"); return -1; } //gendig operation cmd_args.op_code = SHA204_GENDIG; cmd_args.param_1 = GENDIG_ZONE_DATA; cmd_args.param_2 = key_id; cmd_args.data_len_1 = 0; cmd_args.data_1 = NULL; cmd_args.data_len_2 = 0; cmd_args.data_2 = NULL; cmd_args.data_len_3 = 0; cmd_args.data_3 = NULL; cmd_args.tx_size = SHA204_CMD_SIZE_MIN; cmd_args.tx_buffer = global_tx_buffer; cmd_args.rx_size = GENDIG_RSP_SIZE; cmd_args.rx_buffer = global_rx_buffer; status = sha204m_execute(fd,&cmd_args); //sha204p_sleep(fd); if(status != SHA204_SUCCESS) { printf("Mathine GENGID FAILED! \n"); return -1; } //Host gengid operation memcpy(tmpdata,key_value,0x20); gendig_param.zone = GENDIG_ZONE_DATA; gendig_param.key_id = key_id; gendig_param.stored_value = tmpdata; gendig_param.temp_key = &computed_tempkey; status = sha204h_gen_dig(gendig_param); if(status != SHA204_SUCCESS) { printf("HOST GENDIG FAILED! \n"); return -1; } //Read operation cmd_args.op_code = SHA204_READ; cmd_args.param_1 = SHA204_ZONE_DATA|SHA204_ZONE_COUNT_FLAG; cmd_args.param_2 = (uint16_t)(slot * 8); cmd_args.data_len_1 = 0; cmd_args.data_1 = NULL; cmd_args.data_len_2 = 0; cmd_args.data_2 = NULL; cmd_args.data_len_3 = 0; cmd_args.data_3 = NULL; cmd_args.tx_size = 0x30; cmd_args.tx_buffer = global_tx_buffer; cmd_args.rx_size = 0x30; cmd_args.rx_buffer = global_rx_buffer; //sha204p_wakeup(fd); status = sha204m_execute(fd,&cmd_args); //sha204p_sleep(fd); memcpy(tmpdata,&global_rx_buffer[1],0x20); if(status != SHA204_SUCCESS) { printf("FAILED! e_read_data\n"); return -1 ; } decrypt_param.data = tmpdata; decrypt_param.temp_key = &computed_tempkey; status = sha204h_decrypt(decrypt_param); if(status != SHA204_SUCCESS) { printf("HOST DECRYPT FAILED! \n"); return -1; } memcpy(readdata,tmpdata,0x20); return status; }
void random_challenge_response_authentication(int fd, uint16_t key_id, uint8_t *secret_key_value) { static uint8_t status = SHA204_SUCCESS; static uint8_t random_number[0x20] = {0}; // Random number returned by Random NONCE command static uint8_t computed_response[0x20] = {0}; // Host computed expected response static uint8_t atsha204_response[0x20] = {0}; // Actual response received from the ATSHA204 device struct sha204h_nonce_in_out nonce_param; // Parameter for nonce helper function struct sha204h_mac_in_out mac_param; // Parameter for mac helper function struct sha204h_temp_key computed_tempkey; // TempKey parameter for nonce and mac helper function //add by jli :That before every executing cmd sent to ATSHA204 chip should have waked it up once! sha204p_wakeup(fd); printf("Random Chal_Response r\n"); // Notes: // 1. Random Challenge-Response involves the use of a random // challenge for EVERY authentication process. A host with a good // source of random number generation can simply ensure the challenge // is random while making a simple MAC command call. // // 2. A host without a good random generator may be tempted to use the // ATSHA204 random command to obtain a random number from the device. // While the random number obtained through this process is of the // highest quality, the process is susceptible to man-in-the-middle // attack, whereby the attacker simply intercepts the random number // and sent the host a non-random number. // // 3. Host systems without good random number generators and wanting to // avoid the susceptibility to man-in-the-middle attack described in // note #2 above can use the authentication process involving the // ATSHA204 NONCE command in Random Mode. The NONCE command guarantees // an internal random state within the ATSHA204 device that is virtually // impossible to fake. This is the process exemplified in this exercise. // *** STEP 1: ISSUE A NONCE WITH NO EEPROM SEED UPDATE *** // // The NONCE command generates an internal random state // in the ATSHA204 device. Note that the actual random NONCE is // a value computed using an internally generated random number // and other device parameters. The NONCE command emits this // random value for the host to use for host side computation of // an equivalent NONCE. Capture this random number and keep for // use with computing the equivalent NONCE on the host side. // Issue the NONCE command cmd_args.op_code = SHA204_NONCE; cmd_args.param_1 = NONCE_MODE_NO_SEED_UPDATE; cmd_args.param_2 = NONCE_PARAM2; cmd_args.data_len_1 = NONCE_NUMIN_SIZE; cmd_args.data_1 = num_in; cmd_args.data_len_2 = 0; cmd_args.data_2 = NULL; cmd_args.data_len_3 = 0; cmd_args.data_3 = NULL; cmd_args.tx_size = NONCE_COUNT_SHORT; cmd_args.tx_buffer = global_tx_buffer; cmd_args.rx_size = NONCE_RSP_SIZE_LONG; cmd_args.rx_buffer = global_rx_buffer; status = sha204m_execute(fd,&cmd_args); //sha204p_idle(fd); if(status != SHA204_SUCCESS) { printf(" Mathine NONCE FAILED! \n"); return; } // Capture the random number from the NONCE command if it were successful memcpy(random_number,&global_rx_buffer[1],0x20); // *** STEP 2: COMPUTE THE EQUIVALENT NONCE ON THE HOST SIDE // // Go the easy way using the host helper functions provided with // the ATSHA204 library. nonce_param.mode = NONCE_MODE_NO_SEED_UPDATE; nonce_param.num_in = num_in; nonce_param.rand_out = random_number; nonce_param.temp_key = &computed_tempkey; status = sha204h_nonce(nonce_param); if(status != SHA204_SUCCESS) { printf("HOST NONCE FAILED! \n"); return; } // *** STEP 3: ISSUE THE MAC COMMAND // // Starting from a randomized internal state of the ATSHA204 device // guarantees that this MAC command call is executing a random // challenge-response authentication. // Issue the MAC command cmd_args.op_code = SHA204_MAC; cmd_args.param_1 = MAC_MODE_BLOCK2_TEMPKEY; cmd_args.param_2 = key_id; cmd_args.data_len_1 = 0; cmd_args.data_1 = NULL; cmd_args.data_len_2 = 0; cmd_args.data_2 = NULL; cmd_args.data_len_3 = 0; cmd_args.data_3 = NULL; cmd_args.tx_size = MAC_COUNT_SHORT; cmd_args.tx_buffer = global_tx_buffer; cmd_args.rx_size = MAC_RSP_SIZE; cmd_args.rx_buffer = global_rx_buffer; status = sha204m_execute(fd,&cmd_args); //sha204p_sleep(fd); if(status != SHA204_SUCCESS) { printf("Mathine MACFAILED! \n"); return; } // Capture actual response from the ATSHA204 device memcpy(atsha204_response,&global_rx_buffer[1],0x20); // *** STEP 4: DYNAMICALLY VALIDATE THE (MAC) RESPONSE // // Note that this requires knowledge of the actual secret key // value. mac_param.mode = MAC_MODE_BLOCK2_TEMPKEY; mac_param.key_id = key_id; mac_param.challenge = NULL; mac_param.key = secret_key_value; mac_param.otp = NULL; mac_param.sn = NULL; mac_param.response = computed_response; mac_param.temp_key = &computed_tempkey; status = sha204h_mac(mac_param); if(status != SHA204_SUCCESS) { printf("HOST MAC FAILED! \n"); return; } // Moment of truth: Compare the received response with the dynamically computed expected response. status = memcmp(computed_response,atsha204_response,0x20); if ( !status ) { printf("Authentication SUCCESS!\n"); } else { printf("Authentication FAILED! \n"); return; } return; }