static void gzp_process_encrypted_user_data(uint8_t* rx_payload, uint8_t length) { uint8_t tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH]; if(gzp_id_req_received()) { gzp_crypt_select_key(GZP_ID_EXCHANGE); } else { gzp_crypt_select_key(GZP_DATA_EXCHANGE); } gzp_crypt(&rx_payload[1], &rx_payload[1], length - 1); if(gzp_validate_id(&rx_payload[GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID])) { gzp_encrypted_user_data_length = length - GZP_USER_DATA_PACKET_OVERHEAD; memcpy((void*)gzp_encrypted_user_data, &rx_payload[GZP_CMD_ENCRYPTED_USER_DATA_PAYLOAD], gzp_encrypted_user_data_length); } // Build response packet tx_payload[0] = GZP_CMD_ENCRYPTED_USER_DATA_RESP; gzp_add_validation_id(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID]); gzp_crypt(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], &tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], GZP_VALIDATION_ID_LENGTH); gzp_get_session_counter(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]); // Update "session token" only if no ID request is pending if(!gzp_id_req_received()) { gzp_crypt_set_session_token(&tx_payload[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]); } gzp_preload_ack(tx_payload, GZP_CMD_ENCRYPTED_USER_DATA_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE); }
static void gzp_process_id_fetch(uint8_t* rx_payload) { uint8_t tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH]; if(gzp_id_req_received()) { gzp_crypt_select_key(GZP_ID_EXCHANGE); gzp_crypt(&rx_payload[1], &rx_payload[1], GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH - 1); if(gzp_validate_id(&rx_payload[GZP_CMD_HOST_ID_FETCH_VALIDATION_ID])) { switch(gzp_id_req_stat) { case GZP_ID_REQ_PENDING_AND_GRANTED: tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = GZP_ID_RESP_GRANTED; gzp_get_host_id(&tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_HOST_ID]); gzp_id_req_stat = GZP_ID_REQ_IDLE; break; case GZP_ID_REQ_PENDING_AND_REJECTED: tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = GZP_ID_RESP_REJECTED; gzp_id_req_stat = GZP_ID_REQ_IDLE; break; case GZP_ID_REQ_PENDING: default: tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_STATUS] = GZP_ID_RESP_PENDING; break; } tx_payload[0] = GZP_CMD_HOST_ID_FETCH_RESP; gzp_add_validation_id(&tx_payload[GZP_CMD_HOST_ID_FETCH_RESP_VALIDATION_ID]); gzp_crypt(&tx_payload[1], &tx_payload[1], GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH - 1); gzp_preload_ack(tx_payload, GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH, GZP_DATA_PIPE); } } }
static bool gzp_crypt_tx_transaction(const uint8_t *src, uint8_t length) { uint8_t tx_packet[GZLL_MAX_FW_PAYLOAD_LENGTH]; uint8_t rx_packet[GZLL_MAX_ACK_PAYLOAD_LENGTH]; uint8_t tx_packet_length; tx_packet_length = length + GZP_USER_DATA_PACKET_OVERHEAD; // Assemble tx packet tx_packet[0] = GZP_CMD_ENCRYPTED_USER_DATA; gzp_add_validation_id(&tx_packet[GZP_CMD_ENCRYPTED_USER_DATA_VALIDATION_ID]); memcpy(&tx_packet[GZP_CMD_ENCRYPTED_USER_DATA_PAYLOAD], (uint8_t*)src, length); // Encrypt tx packet if(gzp_id_req_pending) { gzp_crypt_select_key(GZP_ID_EXCHANGE); } else { gzp_crypt_select_key(GZP_DATA_EXCHANGE); } gzp_crypt(&tx_packet[1], &tx_packet[1], tx_packet_length - 1); // If packet was successfully sent AND a response packet was received if(gzp_tx_rx_transaction(tx_packet, tx_packet_length, rx_packet, NULL, GZP_DATA_PIPE) == GZP_TX_RX_SUCCESS) { if(rx_packet[0] == GZP_CMD_ENCRYPTED_USER_DATA_RESP) { gzp_crypt(&rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], &rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID], GZP_VALIDATION_ID_LENGTH); // Validate response in order to know whether packet was correctly decrypted by host if(gzp_validate_id(&rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_VALIDATION_ID])) { // Update session token if normal operation (!gzp_id_req_pending) if(!gzp_id_req_pending) { gzp_crypt_set_session_token(&rx_packet[GZP_CMD_ENCRYPTED_USER_DATA_RESP_SESSION_TOKEN]); } return true; } else { return false; } } } return false; }
static bool gzp_key_update(void) { uint8_t tx_packet[GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH], rx_packet[GZP_MAX_ACK_PAYLOAD_LENGTH]; // Send "prepare packet" to get session token to be used for key update tx_packet[0] = (uint8_t)GZP_CMD_KEY_UPDATE_PREPARE; // If packet was successfully sent AND a response packet was received if(gzp_tx_rx_transaction(tx_packet, GZP_CMD_KEY_UPDATE_PREPARE_PAYLOAD_LENGTH, rx_packet, NULL, GZP_DATA_PIPE) == GZP_TX_RX_SUCCESS) { if(rx_packet[0] == (uint8_t)GZP_CMD_KEY_UPDATE_PREPARE_RESP) { gzp_crypt_set_session_token(&rx_packet[GZP_CMD_KEY_UPDATE_PREPARE_RESP_SESSION_TOKEN]); // Build "key update" packet tx_packet[0] = (uint8_t)GZP_CMD_KEY_UPDATE; gzp_add_validation_id(&tx_packet[GZP_CMD_KEY_UPDATE_VALIDATION_ID]); gzp_random_numbers_generate(&tx_packet[GZP_CMD_KEY_UPDATE_NEW_KEY], GZP_DYN_KEY_LENGTH); gzp_crypt_set_dyn_key(&tx_packet[GZP_CMD_KEY_UPDATE_NEW_KEY]); // Encrypt "key update packet" gzp_crypt_select_key(GZP_KEY_EXCHANGE); gzp_crypt(&tx_packet[1], &tx_packet[1], GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH - 1); // Send "key update" packet if(gzp_tx_packet(tx_packet, GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH, GZP_DATA_PIPE)) { return true; } } } return false; }
static void gzp_process_key_update(uint8_t* rx_payload) { gzp_crypt_select_key(GZP_KEY_EXCHANGE); gzp_crypt(&rx_payload[1], &rx_payload[1], GZP_CMD_KEY_UPDATE_PAYLOAD_LENGTH - 1); if(gzp_validate_id(&rx_payload[GZP_CMD_KEY_UPDATE_VALIDATION_ID])) { gzp_crypt_set_dyn_key(&rx_payload[GZP_CMD_KEY_UPDATE_NEW_KEY]); } }
gzp_id_req_res_t gzp_id_req_send() { uint8_t tx_packet[GZP_CMD_HOST_ID_REQ_PAYLOAD_LENGTH]; uint8_t rx_packet[GZP_MAX_ACK_PAYLOAD_LENGTH]; gzp_tx_rx_trans_result_t trans_result; // If no ID request is pending, send new "ID request" if(!gzp_id_req_pending) { // Build "Host ID request packet" tx_packet[0] = (uint8_t)GZP_CMD_HOST_ID_REQ; // Generate new session token gzp_random_numbers_generate(&tx_packet[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN], GZP_SESSION_TOKEN_LENGTH); // Send "Host ID request" if(gzp_tx_packet(tx_packet, GZP_CMD_HOST_ID_REQ_PAYLOAD_LENGTH, GZP_DATA_PIPE)) { // Update session token if "Host ID request" was successfully transmitted gzp_crypt_set_session_token(&tx_packet[GZP_CMD_HOST_ID_REQ_SESSION_TOKEN]); gzp_id_req_pending = true; return GZP_ID_RESP_PENDING; } } else // If "ID request is pending" send "fetch ID" packet { // Build "host ID fetch" packet tx_packet[0] = (uint8_t)GZP_CMD_HOST_ID_FETCH; gzp_add_validation_id(&tx_packet[GZP_CMD_HOST_ID_FETCH_VALIDATION_ID]); // Encrypt "host ID fetch" packet gzp_crypt_select_key(GZP_ID_EXCHANGE); gzp_crypt(&tx_packet[1], &tx_packet[1], GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH - 1); trans_result = gzp_tx_rx_transaction(tx_packet, GZP_CMD_HOST_ID_FETCH_PAYLOAD_LENGTH, rx_packet, NULL, GZP_DATA_PIPE); // If packet was successfully sent AND a response packet was received if(trans_result == GZP_TX_RX_SUCCESS) { // Validate response packet if(rx_packet[0] == (uint8_t)GZP_CMD_HOST_ID_FETCH_RESP) { gzp_crypt(&rx_packet[1], &rx_packet[1], GZP_CMD_HOST_ID_FETCH_RESP_PAYLOAD_LENGTH - 1); if(gzp_validate_id(&rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_VALIDATION_ID])) { switch(rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_STATUS]) { case GZP_ID_RESP_PENDING: break; case GZP_ID_RESP_REJECTED: gzp_id_req_pending = false; break; case GZP_ID_RESP_GRANTED: gzp_set_host_id(&rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_HOST_ID]); gzp_random_numbers_generate(dyn_key, GZP_DYN_KEY_LENGTH); gzp_crypt_set_dyn_key(dyn_key); #ifndef GZP_NV_STORAGE_DISABLE (void)gzp_params_store(true); #endif gzp_id_req_pending = false; break; default: break; } return (gzp_id_req_res_t)rx_packet[GZP_CMD_HOST_ID_FETCH_RESP_STATUS]; } else { gzp_id_req_pending = false; return GZP_ID_RESP_REJECTED; } } } } gzp_id_req_pending = false; return GZP_ID_RESP_FAILED; }