#include "atca_basic.h"
#include "atca_execution.h"
#include "host/atca_host.h"
ATCA_STATUS atcab_read_zone(uint8_t zone, uint16_t slot, uint8_t block, uint8_t offset, uint8_t *data, uint8_t len)
{
ATCAPacket packet;
ATCACommand ca_cmd = _gDevice->mCommands;
ATCA_STATUS status = ATCA_GEN_FAIL;
uint16_t addr;
do
{
if (data == NULL)
{
return ATCA_BAD_PARAM;
}
if (len != 4 && len != 32)
{
return ATCA_BAD_PARAM;
}
if ((status = atcab_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS)
{
break;
}
if (len == ATCA_BLOCK_SIZE)
{
zone = zone | ATCA_ZONE_READWRITE_32;
}
packet.param1 = zone;
packet.param2 = addr;
if ((status = atRead(ca_cmd, &packet)) != ATCA_SUCCESS)
{
break;
}
if ((status = atca_execute_command(&packet, _gDevice)) != ATCA_SUCCESS)
{
break;
}
memcpy(data, &packet.data[1], len);
}
while (0);
return status;
}
ATCA_STATUS atcab_read_serial_number(uint8_t* serial_number)
{
ATCA_STATUS status = ATCA_GEN_FAIL;
uint8_t read_buf[ATCA_BLOCK_SIZE];
if (!serial_number)
{
return ATCA_BAD_PARAM;
}
do
{
if ((status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 0, 0, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS)
{
break;
}
memcpy(&serial_number[0], &read_buf[0], 4);
memcpy(&serial_number[4], &read_buf[8], 5);
}
while (0);
return status;
}
ATCA_STATUS atcab_is_slot_locked(uint16_t slot, bool *is_locked)
{
ATCA_STATUS ret = ATCA_GEN_FAIL;
uint8_t data[ATCA_WORD_SIZE];
uint16_t slot_locked;
do
{
if (slot > 15)
{
return ATCA_BAD_PARAM;
}
if (is_locked == NULL)
{
return ATCA_BAD_PARAM;
}
if ((ret = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 2 , 6 , data, ATCA_WORD_SIZE)) != ATCA_SUCCESS)
{
break;
}
slot_locked = ((uint16_t)data[0]) | ((uint16_t)data[1] << 8);
*is_locked = ((slot_locked & (1 << slot)) == 0);
}
while (0);
return ret;
}
ATCA_STATUS atcab_is_locked(uint8_t zone, bool *is_locked)
{
ATCA_STATUS ret = ATCA_GEN_FAIL;
uint8_t data[ATCA_WORD_SIZE];
do
{
if (is_locked == NULL)
{
return ATCA_BAD_PARAM;
}
if ((ret = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 2 , 5 , data, ATCA_WORD_SIZE)) != ATCA_SUCCESS)
{
break;
}
switch (zone)
{
case LOCK_ZONE_CONFIG: *is_locked = (data[3] != 0x55); break;
case LOCK_ZONE_DATA: *is_locked = (data[2] != 0x55); break;
default: ret = ATCA_BAD_PARAM; break;
}
}
while (0);
return ret;
}
#if defined(ATCA_USE_CONSTANT_HOST_NONCE)
ATCA_STATUS atcab_read_enc(uint16_t key_id, uint8_t block, uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id)
{
uint8_t num_in[NONCE_NUMIN_SIZE] = { 0 };
#else
ATCA_STATUS atcab_read_enc(uint16_t key_id, uint8_t block, uint8_t *data, const uint8_t* enc_key, const uint16_t enc_key_id, const uint8_t num_in[NONCE_NUMIN_SIZE])
{
#endif
ATCA_STATUS status = ATCA_GEN_FAIL;
uint8_t zone = ATCA_ZONE_DATA | ATCA_ZONE_READWRITE_32;
atca_nonce_in_out_t nonce_params;
atca_gen_dig_in_out_t gen_dig_param;
atca_temp_key_t temp_key;
uint8_t serial_num[32];
uint8_t rand_out[RANDOM_NUM_SIZE] = { 0 };
uint8_t other_data[4] = { 0 };
int i = 0;
do
{
if (data == NULL || enc_key == NULL)
{
status = ATCA_BAD_PARAM;
break;
}
if ((status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 0, 0, serial_num, 32)) != ATCA_SUCCESS)
{
break;
}
memmove(&serial_num[4], &serial_num[8], 5);
if ((status = atcab_nonce_rand(num_in, rand_out)) != ATCA_SUCCESS)
{
BREAK(status, "Nonce failed");
}
memset(&temp_key, 0, sizeof(temp_key));
memset(&nonce_params, 0, sizeof(nonce_params));
nonce_params.mode = NONCE_MODE_SEED_UPDATE;
nonce_params.zero = 0;
nonce_params.num_in = (uint8_t*)&num_in[0];
nonce_params.rand_out = rand_out;
nonce_params.temp_key = &temp_key;
if ((status = atcah_nonce(&nonce_params)) != ATCA_SUCCESS)
{
BREAK(status, "Calc TempKey failed");
}
other_data[0] = ATCA_GENDIG;
other_data[1] = GENDIG_ZONE_DATA;
other_data[2] = (uint8_t)(enc_key_id);
other_data[3] = (uint8_t)(enc_key_id >> 8);
if ((status = atcab_gendig(GENDIG_ZONE_DATA, enc_key_id, other_data, sizeof(other_data))) != ATCA_SUCCESS)
{
BREAK(status, "GenDig failed");
}
memset(&gen_dig_param, 0, sizeof(gen_dig_param));
gen_dig_param.key_id = enc_key_id;
gen_dig_param.is_key_nomac = false;
gen_dig_param.sn = serial_num;
gen_dig_param.stored_value = enc_key;
gen_dig_param.zone = GENDIG_ZONE_DATA;
gen_dig_param.other_data = other_data;
gen_dig_param.temp_key = &temp_key;
if ((status = atcah_gen_dig(&gen_dig_param)) != ATCA_SUCCESS)
{
BREAK(status, "");
}
if ((status = atcab_read_zone(zone, key_id, block, 0, data, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS)
{
BREAK(status, "Read encrypted failed");
}
for (i = 0; i < ATCA_BLOCK_SIZE; i++)
{
data[i] = data[i] ^ temp_key.value[i];
}
status = ATCA_SUCCESS;
}
while (0);
return status;
}
ATCA_STATUS atcab_read_config_zone(uint8_t* config_data)
{
ATCA_STATUS status = ATCA_GEN_FAIL;
do
{
if (config_data == NULL)
{
status = ATCA_BAD_PARAM;
break;
}
if ((_gDevice->mIface->mIfaceCFG->devtype == ATSHA204A) || (_gDevice->mIface->mIfaceCFG->devtype == ATSHA206A))
{
status = atcab_read_bytes_zone(ATCA_ZONE_CONFIG, 0, 0x00, config_data, ATCA_SHA_CONFIG_SIZE);
}
else
{
status = atcab_read_bytes_zone(ATCA_ZONE_CONFIG, 0, 0x00, config_data, ATCA_ECC_CONFIG_SIZE);
}
if (status != ATCA_SUCCESS)
{
break;
}
}
while (0);
return status;
}
ATCA_STATUS atcab_cmp_config_zone(uint8_t* config_data, bool* same_config)
{
ATCA_STATUS status = ATCA_GEN_FAIL;
uint8_t device_config_data[ATCA_ECC_CONFIG_SIZE];
size_t config_size = 0;
do
{
if ((config_data == NULL) || (same_config == NULL))
{
status = ATCA_BAD_PARAM;
BREAK(status, "Invalid Parameters");
}
*same_config = false;
if ((status = atcab_read_config_zone(device_config_data)) != ATCA_SUCCESS)
{
BREAK(status, "Read config zone failed");
}
if (ATCA_SUCCESS != (status = atcab_get_zone_size(ATCA_ZONE_CONFIG, 0, &config_size)))
{
BREAK(status, "Failed to get config zone size");
}
if (memcmp(&device_config_data[16], &config_data[16], 52 - 16))
{
break;
}
if (_gDevice->mIface->mIfaceCFG->devtype == ATECC608A)
{
if (memcmp(&device_config_data[68], &config_data[68], 84 - 68))
{
break;
}
}
else
{
}
if (90 < config_size)
{
if (memcmp(&device_config_data[90], &config_data[90], config_size - 90))
{
break;
}
}
*same_config = true;
}
while (0);
return status;
}
ATCA_STATUS atcab_read_sig(uint16_t slot, uint8_t* sig)
{
ATCA_STATUS status = ATCA_GEN_FAIL;
do
{
if (sig == NULL || slot < 8 || slot > 15)
{
return ATCA_BAD_PARAM;
}
if ((status = atcab_read_zone(ATCA_ZONE_DATA, slot, 0, 0, &sig[0], ATCA_BLOCK_SIZE)) != ATCA_SUCCESS)
{
break;
}
if ((status = atcab_read_zone(ATCA_ZONE_DATA, slot, 1, 0, &sig[ATCA_BLOCK_SIZE], ATCA_BLOCK_SIZE)) != ATCA_SUCCESS)
{
break;
}
}
while (0);
return status;
}
ATCA_STATUS atcab_read_pubkey(uint16_t slot, uint8_t *public_key)
{
ATCA_STATUS ret = ATCA_GEN_FAIL;
uint8_t read_buf[ATCA_BLOCK_SIZE];
uint8_t block = 0;
uint8_t offset = 0;
uint8_t cpy_index = 0;
uint8_t cpy_size = 0;
uint8_t read_index = 0;
if (public_key == NULL)
{
return ATCA_BAD_PARAM;
}
if (slot < 8 || slot > 0xF)
{
return ATCA_BAD_PARAM;
}
do
{
block = 0;
if ((ret = atcab_read_zone(ATCA_ZONE_DATA, slot, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS)
{
break;
}
cpy_size = ATCA_BLOCK_SIZE - ATCA_PUB_KEY_PAD;
read_index = ATCA_PUB_KEY_PAD;
memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size);
cpy_index += cpy_size;
block = 1;
if ((ret = atcab_read_zone(ATCA_ZONE_DATA, slot, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS)
{
break;
}
cpy_size = ATCA_PUB_KEY_PAD;
read_index = 0;
memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size);
cpy_index += cpy_size;
read_index = ATCA_PUB_KEY_PAD + ATCA_PUB_KEY_PAD;
cpy_size = ATCA_BLOCK_SIZE - read_index;
memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size);
cpy_index += cpy_size;
block = 2;
if ((ret = atcab_read_zone(ATCA_ZONE_DATA, slot, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS)
{
break;
}
cpy_size = ATCA_PUB_KEY_PAD + ATCA_PUB_KEY_PAD;
read_index = 0;
memcpy(&public_key[cpy_index], &read_buf[read_index], cpy_size);
}
while (0);
return ret;
}
ATCA_STATUS atcab_read_bytes_zone(uint8_t zone, uint16_t slot, size_t offset, uint8_t *data, size_t length)
{
ATCA_STATUS status = ATCA_GEN_FAIL;
size_t zone_size = 0;
uint8_t read_buf[32];
size_t data_idx = 0;
size_t cur_block = 0;
size_t cur_offset = 0;
uint8_t read_size = ATCA_BLOCK_SIZE;
size_t read_buf_idx = 0;
size_t copy_length = 0;
size_t read_offset = 0;
if (zone != ATCA_ZONE_CONFIG && zone != ATCA_ZONE_OTP && zone != ATCA_ZONE_DATA)
{
return ATCA_BAD_PARAM;
}
if (zone == ATCA_ZONE_DATA && slot > 15)
{
return ATCA_BAD_PARAM;
}
if (length == 0)
{
return ATCA_SUCCESS; }
if (data == NULL)
{
return ATCA_BAD_PARAM;
}
do
{
status = atcab_get_zone_size(zone, slot, &zone_size);
if (status != ATCA_SUCCESS)
{
break;
}
if (offset + length > zone_size)
{
return ATCA_BAD_PARAM;
}
cur_block = offset / ATCA_BLOCK_SIZE;
while (data_idx < length)
{
if (read_size == ATCA_BLOCK_SIZE && zone_size - cur_block * ATCA_BLOCK_SIZE < ATCA_BLOCK_SIZE)
{
read_size = ATCA_WORD_SIZE;
cur_offset = ((data_idx + offset) / ATCA_WORD_SIZE) % (ATCA_BLOCK_SIZE / ATCA_WORD_SIZE);
}
status = atcab_read_zone(
zone,
slot,
(uint8_t)cur_block,
(uint8_t)cur_offset,
read_buf,
read_size);
if (status != ATCA_SUCCESS)
{
break;
}
read_offset = cur_block * ATCA_BLOCK_SIZE + cur_offset * ATCA_WORD_SIZE;
if (read_offset < offset)
{
read_buf_idx = offset - read_offset; }
else
{
read_buf_idx = 0;
}
if (length - data_idx < read_size - read_buf_idx)
{
copy_length = length - data_idx;
}
else
{
copy_length = read_size - read_buf_idx;
}
memcpy(&data[data_idx], &read_buf[read_buf_idx], copy_length);
data_idx += copy_length;
if (read_size == ATCA_BLOCK_SIZE)
{
cur_block += 1;
}
else
{
cur_offset += 1;
}
}
if (status != ATCA_SUCCESS)
{
break;
}
}
while (false);
return status;
}