Пример #1
0
uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address)
{
    uint8_t rx_size;

    if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0)
            || ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP)))
        return SHA204_BAD_PARAM;

    address >>= 2;
    if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG)
    {
        if (address > SHA204_ADDRESS_MASK_CONFIG)
            return SHA204_BAD_PARAM;
    }
    else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP)
    {
        if (address > SHA204_ADDRESS_MASK_OTP)
            return SHA204_BAD_PARAM;
    }
    else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA)
    {
        if (address > SHA204_ADDRESS_MASK)
            return SHA204_BAD_PARAM;
    }

    tx_buffer[SHA204_COUNT_IDX] = READ_COUNT;
    tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ;
    tx_buffer[READ_ZONE_IDX] = zone;
    tx_buffer[READ_ADDR_IDX] = (uint8_t)(address & SHA204_ADDRESS_MASK);
    tx_buffer[READ_ADDR_IDX + 1] = 0;

    rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE;

    return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY);
}
Пример #2
0
uint8_t atsha204Class::sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode)
{
    if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE))
        return SHA204_BAD_PARAM;

    tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT;
    tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM;
    tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE;

    tx_buffer[RANDOM_PARAM2_IDX] =
        tx_buffer[RANDOM_PARAM2_IDX + 1] = 0;

    return sha204c_send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, RANDOM_EXEC_MAX - RANDOM_DELAY);
}
Пример #3
0
uint8_t atsha204Class::sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer)
{
    if (!tx_buffer || !rx_buffer)
        return SHA204_BAD_PARAM;

    tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT;
    tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV;

    // Parameters are 0.
    tx_buffer[DEVREV_PARAM1_IDX] =
        tx_buffer[DEVREV_PARAM2_IDX] =
            tx_buffer[DEVREV_PARAM2_IDX + 1] = 0;

    return sha204c_send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0],
                                    DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY);
}
Пример #4
0
/** \brief This function creates a command packet, sends it, and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_execute(struct sha204_command_parameters *args)
{
    uint8_t *p_buffer;
    uint8_t len;
    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer
    };

    uint8_t ret_code = sha204m_check_parameters(args);
    if (ret_code != SHA204_SUCCESS)
        return ret_code;

    // Supply delays and response size.
    switch (args->op_code) {
    case SHA204_CHECKMAC:
        comm_parameters.poll_delay = CHECKMAC_DELAY;
        comm_parameters.poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY;
        comm_parameters.rx_size = CHECKMAC_RSP_SIZE;
        break;

    case SHA204_DERIVE_KEY:
        comm_parameters.poll_delay = DERIVE_KEY_DELAY;
        comm_parameters.poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY;
        comm_parameters.rx_size = DERIVE_KEY_RSP_SIZE;
        break;

    case SHA204_DEVREV:
        comm_parameters.poll_delay = DEVREV_DELAY;
        comm_parameters.poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY;
        comm_parameters.rx_size = DEVREV_RSP_SIZE;
        break;

    case SHA204_GENDIG:
        comm_parameters.poll_delay = GENDIG_DELAY;
        comm_parameters.poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY;
        comm_parameters.rx_size = GENDIG_RSP_SIZE;
        break;

    case SHA204_HMAC:
        comm_parameters.poll_delay = HMAC_DELAY;
        comm_parameters.poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY;
        comm_parameters.rx_size = HMAC_RSP_SIZE;
        break;

    case SHA204_LOCK:
        comm_parameters.poll_delay = LOCK_DELAY;
        comm_parameters.poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY;
        comm_parameters.rx_size = LOCK_RSP_SIZE;
        break;

    case SHA204_MAC:
        comm_parameters.poll_delay = MAC_DELAY;
        comm_parameters.poll_timeout = MAC_EXEC_MAX - MAC_DELAY;
        comm_parameters.rx_size = MAC_RSP_SIZE;
        break;

    case SHA204_NONCE:
        comm_parameters.poll_delay = NONCE_DELAY;
        comm_parameters.poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY;
        comm_parameters.rx_size = args->param_1 == NONCE_MODE_PASSTHROUGH
                                  ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG;
        break;

    case SHA204_PAUSE:
        comm_parameters.poll_delay = PAUSE_DELAY;
        comm_parameters.poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY;
        comm_parameters.rx_size = PAUSE_RSP_SIZE;
        break;

    case SHA204_RANDOM:
        comm_parameters.poll_delay = RANDOM_DELAY;
        comm_parameters.poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY;
        comm_parameters.rx_size = RANDOM_RSP_SIZE;
        break;

    case SHA204_READ:
        comm_parameters.poll_delay = READ_DELAY;
        comm_parameters.poll_timeout = READ_EXEC_MAX - READ_DELAY;
        comm_parameters.rx_size = (args->param_1 & SHA204_ZONE_COUNT_FLAG)
                                  ? READ_32_RSP_SIZE : READ_4_RSP_SIZE;
        break;

    case SHA204_UPDATE_EXTRA:
        comm_parameters.poll_delay = UPDATE_DELAY;
        comm_parameters.poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY;
        comm_parameters.rx_size = UPDATE_RSP_SIZE;
        break;

    case SHA204_WRITE:
        comm_parameters.poll_delay = WRITE_DELAY;
        comm_parameters.poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY;
        comm_parameters.rx_size = WRITE_RSP_SIZE;
        break;

    default:
        comm_parameters.poll_delay = 0;
        comm_parameters.poll_timeout = SHA204_COMMAND_EXEC_MAX;
        comm_parameters.rx_size = args->rx_size;
    }

    // Assemble command.
    len = args->data_len_1 + args->data_len_2 + args->data_len_3 + SHA204_CMD_SIZE_MIN;
    p_buffer = args->tx_buffer;
    *p_buffer++ = len;
    *p_buffer++ = args->op_code;
    *p_buffer++ = args->param_1;
    *p_buffer++ = args->param_2 & 0xFF;
    *p_buffer++ = args->param_2 >> 8;

    if (args->data_len_1 > 0) {
        memcpy(p_buffer, args->data_1, args->data_len_1);
        p_buffer += args->data_len_1;
    }
    if (args->data_len_2 > 0) {
        memcpy(p_buffer, args->data_2, args->data_len_2);
        p_buffer += args->data_len_2;
    }
    if (args->data_len_3 > 0) {
        memcpy(p_buffer, args->data_3, args->data_len_3);
        p_buffer += args->data_len_3;
    }

    sha204c_calculate_crc(len - SHA204_CRC_SIZE, args->tx_buffer, p_buffer);

    // Send command and receive response.
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a CheckMAC command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_check_mac(struct sha204_check_mac_parameters *args)
{
    if (		// no null pointers allowed
        !args->tx_buffer || !args->rx_buffer || !args->client_response || !args->other_data
        // No reserved bits should be set.
        || (args->mode | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK
        // key_id > 15 not allowed
        || args->key_id > SHA204_KEY_ID_MAX)
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = CHECKMAC_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_CHECKMAC;
    args->tx_buffer[CHECKMAC_MODE_IDX] = args->mode & CHECKMAC_MODE_MASK;
    args->tx_buffer[CHECKMAC_KEYID_IDX]= args->key_id;
    args->tx_buffer[CHECKMAC_KEYID_IDX + 1] = 0;
    if (args->client_challenge == NULL)
        memset(&args->tx_buffer[CHECKMAC_CLIENT_CHALLENGE_IDX], 0, CHECKMAC_CLIENT_CHALLENGE_SIZE);
    else
        memcpy(&args->tx_buffer[CHECKMAC_CLIENT_CHALLENGE_IDX], args->client_challenge, CHECKMAC_CLIENT_CHALLENGE_SIZE);

    memcpy(&args->tx_buffer[CHECKMAC_CLIENT_RESPONSE_IDX], args->client_response, CHECKMAC_CLIENT_RESPONSE_SIZE);
    memcpy(&args->tx_buffer[CHECKMAC_DATA_IDX], args->other_data, CHECKMAC_OTHER_DATA_SIZE);

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = CHECKMAC_RSP_SIZE,
        .poll_delay = CHECKMAC_DELAY,
        .poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a DeriveKey command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_derive_key(struct sha204_derive_key_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer || ((args->use_random & ~DERIVE_KEY_RANDOM_FLAG) != 0)
            || (args->target_key > SHA204_KEY_ID_MAX))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_DERIVE_KEY;
    args->tx_buffer[DERIVE_KEY_RANDOM_IDX] = args->use_random;
    args->tx_buffer[DERIVE_KEY_TARGETKEY_IDX] = args->target_key;
    args->tx_buffer[DERIVE_KEY_TARGETKEY_IDX + 1] = 0;
    if (args->mac != NULL)
    {
        memcpy(&args->tx_buffer[DERIVE_KEY_MAC_IDX], args->mac, DERIVE_KEY_MAC_SIZE);
        args->tx_buffer[SHA204_COUNT_IDX] = DERIVE_KEY_COUNT_LARGE;
    }
    else
        args->tx_buffer[SHA204_COUNT_IDX] = DERIVE_KEY_COUNT_SMALL;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = DERIVE_KEY_RSP_SIZE,
        .poll_delay = DERIVE_KEY_DELAY,
        .poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a DevRev command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_dev_rev(struct sha204_dev_rev_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer)
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV;

    // Parameters are 0.
    args->tx_buffer[DEVREV_PARAM1_IDX] =
        args->tx_buffer[DEVREV_PARAM2_IDX] =
            args->tx_buffer[DEVREV_PARAM2_IDX + 1] = 0;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = DEVREV_RSP_SIZE,
        .poll_delay = DEVREV_DELAY,
        .poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a GenDig command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_gen_dig(struct sha204_gen_dig_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer
            || ((args->zone != GENDIG_ZONE_OTP) && (args->zone != GENDIG_ZONE_DATA)))
        return SHA204_BAD_PARAM;

    if (((args->zone == GENDIG_ZONE_OTP) && (args->key_id > SHA204_OTP_BLOCK_MAX))
            || ((args->zone == GENDIG_ZONE_DATA) && (args->key_id > SHA204_KEY_ID_MAX)))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_GENDIG;
    args->tx_buffer[GENDIG_ZONE_IDX] = args->zone;
    args->tx_buffer[GENDIG_KEYID_IDX] = args->key_id;
    args->tx_buffer[GENDIG_KEYID_IDX + 1] = 0;
    if (args->other_data != NULL)
    {
        memcpy(&args->tx_buffer[GENDIG_DATA_IDX], args->other_data, GENDIG_OTHER_DATA_SIZE);
        args->tx_buffer[SHA204_COUNT_IDX] = GENDIG_COUNT_DATA;
    }
    else
        args->tx_buffer[SHA204_COUNT_IDX] = GENDIG_COUNT;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = GENDIG_RSP_SIZE,
        .poll_delay = GENDIG_DELAY,
        .poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends an HMAC command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_hmac(struct sha204_hmac_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer || ((args->mode & ~HMAC_MODE_MASK) != 0))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = HMAC_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_HMAC;
    args->tx_buffer[HMAC_MODE_IDX] = args->mode;

    // Although valid key identifiers are only
    // from 0 to 15, all 16 bits are used in the HMAC message.
    args->tx_buffer[HMAC_KEYID_IDX] = args->key_id & 0xFF;
    args->tx_buffer[HMAC_KEYID_IDX + 1] = args->key_id >> 8;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = HMAC_RSP_SIZE,
        .poll_delay = HMAC_DELAY,
        .poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a Lock command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_lock(struct sha204_lock_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer || ((args->zone & ~LOCK_ZONE_MASK) != 0)
            || ((args->zone & LOCK_ZONE_NO_CRC) && (args->summary != 0)))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = LOCK_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_LOCK;
    args->tx_buffer[LOCK_ZONE_IDX] = args->zone & LOCK_ZONE_MASK;
    args->tx_buffer[LOCK_SUMMARY_IDX]= args->summary & 0xFF;
    args->tx_buffer[LOCK_SUMMARY_IDX + 1]= args->summary >> 8;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = LOCK_RSP_SIZE,
        .poll_delay = LOCK_DELAY,
        .poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a MAC command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_mac(struct sha204_mac_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer || ((args->mode & ~MAC_MODE_MASK) != 0)
            || (((args->mode & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !args->challenge))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = MAC_COUNT_SHORT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_MAC;
    args->tx_buffer[MAC_MODE_IDX] = args->mode;
    args->tx_buffer[MAC_KEYID_IDX] = args->key_id & 0xFF;
    args->tx_buffer[MAC_KEYID_IDX + 1] = args->key_id >> 8;
    if ((args->mode & MAC_MODE_BLOCK2_TEMPKEY) == 0)
    {
        memcpy(&args->tx_buffer[MAC_CHALLENGE_IDX], args->challenge, MAC_CHALLENGE_SIZE);
        args->tx_buffer[SHA204_COUNT_IDX] = MAC_COUNT_LONG;
    }

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = MAC_RSP_SIZE,
        .poll_delay = MAC_DELAY,
        .poll_timeout = MAC_EXEC_MAX - MAC_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a Nonce command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_nonce(struct sha204_nonce_parameters *args)
{
    uint8_t rx_size;

    if (!args->tx_buffer || !args->rx_buffer || !args->num_in
            || (args->mode > NONCE_MODE_PASSTHROUGH) || (args->mode == NONCE_MODE_INVALID))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_NONCE;
    args->tx_buffer[NONCE_MODE_IDX] = args->mode;

    // 2. parameter is 0.
    args->tx_buffer[NONCE_PARAM2_IDX] =
        args->tx_buffer[NONCE_PARAM2_IDX + 1] = 0;

    if (args->mode != NONCE_MODE_PASSTHROUGH)
    {
        memcpy(&args->tx_buffer[NONCE_INPUT_IDX], args->num_in, NONCE_NUMIN_SIZE);
        args->tx_buffer[SHA204_COUNT_IDX] = NONCE_COUNT_SHORT;
        rx_size = NONCE_RSP_SIZE_LONG;
    }
    else
    {
        memcpy(&args->tx_buffer[NONCE_INPUT_IDX], args->num_in, NONCE_NUMIN_SIZE_PASSTHROUGH);
        args->tx_buffer[SHA204_COUNT_IDX] = NONCE_COUNT_LONG;
        rx_size = NONCE_RSP_SIZE_SHORT;
    }

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = rx_size,
        .poll_delay = NONCE_DELAY,
        .poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a Pause command to SWI devices and receives a response from the selected device.
 *         All others pause.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_pause(struct sha204_pause_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer)
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = PAUSE_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_PAUSE;
    args->tx_buffer[PAUSE_SELECT_IDX] = args->selector;

    // 2. parameter is 0.
    args->tx_buffer[PAUSE_PARAM2_IDX] =
        args->tx_buffer[PAUSE_PARAM2_IDX + 1] = 0;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = PAUSE_RSP_SIZE,
        .poll_delay = PAUSE_DELAY,
        .poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a Random command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_random(struct sha204_random_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer || (args->mode > RANDOM_NO_SEED_UPDATE))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM;
    args->tx_buffer[RANDOM_MODE_IDX] = args->mode & RANDOM_SEED_UPDATE;

    // 2. parameter is 0.
    args->tx_buffer[RANDOM_PARAM2_IDX] =
        args->tx_buffer[RANDOM_PARAM2_IDX + 1] = 0;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = RANDOM_RSP_SIZE,
        .poll_delay = RANDOM_DELAY,
        .poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends a Read command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_read(struct sha204_read_parameters *args)
{
    uint8_t rx_size;
    uint16_t address;

    if (!args->tx_buffer || !args->rx_buffer || ((args->zone & ~READ_ZONE_MASK) != 0)
            || ((args->zone & READ_ZONE_MODE_32_BYTES) && (args->zone == SHA204_ZONE_OTP)))
        return SHA204_BAD_PARAM;

    // If we would just mask address bits, we would
    // read from an address that was not intended.
    address = args->address >> 2;
    if ((args->zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) {
        if (address > SHA204_ADDRESS_MASK_CONFIG)
            return SHA204_BAD_PARAM;
    }
    if ((args->zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) {
        if (address > SHA204_ADDRESS_MASK_OTP)
            // If we would just mask this bit, we would
            // read from an address that was not intended.
            return SHA204_BAD_PARAM;
    }
    if ((args->zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) {
        if (address > SHA204_ADDRESS_MASK)
            // If we would just mask this bit, we would
            // read from an address that was not intended.
            return SHA204_BAD_PARAM;
    }

    args->tx_buffer[SHA204_COUNT_IDX] = READ_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ;
    args->tx_buffer[READ_ZONE_IDX] = args->zone;
    args->tx_buffer[READ_ADDR_IDX] = (uint8_t) address;
    args->tx_buffer[READ_ADDR_IDX + 1] = 0;

    rx_size = (args->zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = rx_size,
        .poll_delay = READ_DELAY,
        .poll_timeout = READ_EXEC_MAX - READ_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/** \brief This function sends an UpdateExtra command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_update_extra(struct sha204_update_extra_parameters *args)
{
    if (!args->tx_buffer || !args->rx_buffer || (args->mode > UPDATE_CONFIG_BYTE_86))
        return SHA204_BAD_PARAM;

    args->tx_buffer[SHA204_COUNT_IDX] = UPDATE_COUNT;
    args->tx_buffer[SHA204_OPCODE_IDX] = SHA204_UPDATE_EXTRA;
    args->tx_buffer[UPDATE_MODE_IDX] = args->mode;
    args->tx_buffer[UPDATE_VALUE_IDX] = args->new_value;
    args->tx_buffer[UPDATE_VALUE_IDX + 1] = 0;

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = UPDATE_RSP_SIZE,
        .poll_delay = UPDATE_DELAY,
        .poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}


/**\brief This function sends a Write command to the device and receives its response.
 * \param[in, out]  args pointer to parameter structure
 * \return status of the operation
 */
uint8_t sha204m_write(struct sha204_write_parameters *args)
{
    uint8_t *p_command;
    uint8_t count;
    uint16_t address;

    if (!args->tx_buffer || !args->rx_buffer || !args->new_value || ((args->zone & ~WRITE_ZONE_MASK) != 0))
        return SHA204_BAD_PARAM;

    // If we would just mask address bits, we would
    // read from an address that was not intended.
    address = args->address >> 2;
    if ((args->zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) {
        if (address > SHA204_ADDRESS_MASK_CONFIG)
            return SHA204_BAD_PARAM;
    }
    if ((args->zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) {
        if (address > SHA204_ADDRESS_MASK_OTP)
            // If we would just mask this bit, we would
            // read from an address that was not intended.
            return SHA204_BAD_PARAM;
    }
    if ((args->zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) {
        if (address > SHA204_ADDRESS_MASK)
            // If we would just mask this bit, we would
            // read from an address that was not intended.
            return SHA204_BAD_PARAM;
    }

    p_command = &args->tx_buffer[SHA204_OPCODE_IDX];
    *p_command++ = SHA204_WRITE;
    *p_command++ = args->zone;
    *p_command++ = (uint8_t) address;
    *p_command++ = 0;

    count = (args->zone & SHA204_ZONE_COUNT_FLAG) ? SHA204_ZONE_ACCESS_32 : SHA204_ZONE_ACCESS_4;
    memcpy(p_command, args->new_value, count);
    p_command += count;

    if (args->mac != NULL)
    {
        memcpy(p_command, args->mac, WRITE_MAC_SIZE);
        p_command += WRITE_MAC_SIZE;
    }

    // Supply count.
    args->tx_buffer[SHA204_COUNT_IDX] = (uint8_t) (p_command - &args->tx_buffer[0] + SHA204_CRC_SIZE);

    struct sha204_send_and_receive_parameters comm_parameters = {
        .tx_buffer = args->tx_buffer,
        .rx_buffer = args->rx_buffer,
        .rx_size = WRITE_RSP_SIZE,
        .poll_delay = WRITE_DELAY,
        .poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY
    };
    return sha204c_send_and_receive(&comm_parameters);
}
Пример #5
0
uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
                                       uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
                                       uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer)
{
    uint8_t poll_delay, poll_timeout, response_size;
    uint8_t *p_buffer;
    uint8_t len;

    uint8_t ret_code = sha204m_check_parameters(op_code, param1, param2,
                       datalen1, data1, datalen2, data2, datalen3, data3,
                       tx_size, tx_buffer, rx_size, rx_buffer);
    if (ret_code != SHA204_SUCCESS)
        return ret_code;

    // Supply delays and response size.
    switch (op_code)
    {
    case SHA204_CHECKMAC:
        poll_delay = CHECKMAC_DELAY;
        poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY;
        response_size = CHECKMAC_RSP_SIZE;
        break;

    case SHA204_DERIVE_KEY:
        poll_delay = DERIVE_KEY_DELAY;
        poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY;
        response_size = DERIVE_KEY_RSP_SIZE;
        break;

    case SHA204_DEVREV:
        poll_delay = DEVREV_DELAY;
        poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY;
        response_size = DEVREV_RSP_SIZE;
        break;

    case SHA204_GENDIG:
        poll_delay = GENDIG_DELAY;
        poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY;
        response_size = GENDIG_RSP_SIZE;
        break;

    case SHA204_HMAC:
        poll_delay = HMAC_DELAY;
        poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY;
        response_size = HMAC_RSP_SIZE;
        break;

    case SHA204_LOCK:
        poll_delay = LOCK_DELAY;
        poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY;
        response_size = LOCK_RSP_SIZE;
        break;

    case SHA204_MAC:
        poll_delay = MAC_DELAY;
        poll_timeout = MAC_EXEC_MAX - MAC_DELAY;
        response_size = MAC_RSP_SIZE;
        break;

    case SHA204_NONCE:
        poll_delay = NONCE_DELAY;
        poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY;
        response_size = param1 == NONCE_MODE_PASSTHROUGH
                        ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG;
        break;

    case SHA204_PAUSE:
        poll_delay = PAUSE_DELAY;
        poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY;
        response_size = PAUSE_RSP_SIZE;
        break;

    case SHA204_RANDOM:
        poll_delay = RANDOM_DELAY;
        poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY;
        response_size = RANDOM_RSP_SIZE;
        break;

    case SHA204_READ:
        poll_delay = READ_DELAY;
        poll_timeout = READ_EXEC_MAX - READ_DELAY;
        response_size = (param1 & SHA204_ZONE_COUNT_FLAG)
                        ? READ_32_RSP_SIZE : READ_4_RSP_SIZE;
        break;

    case SHA204_UPDATE_EXTRA:
        poll_delay = UPDATE_DELAY;
        poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY;
        response_size = UPDATE_RSP_SIZE;
        break;

    case SHA204_WRITE:
        poll_delay = WRITE_DELAY;
        poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY;
        response_size = WRITE_RSP_SIZE;
        break;

    default:
        poll_delay = 0;
        poll_timeout = SHA204_COMMAND_EXEC_MAX;
        response_size = rx_size;
    }

    // Assemble command.
    len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN;
    p_buffer = tx_buffer;
    *p_buffer++ = len;
    *p_buffer++ = op_code;
    *p_buffer++ = param1;
    *p_buffer++ = param2 & 0xFF;
    *p_buffer++ = param2 >> 8;

    if (datalen1 > 0) {
        memcpy(p_buffer, data1, datalen1);
        p_buffer += datalen1;
    }
    if (datalen2 > 0) {
        memcpy(p_buffer, data2, datalen2);
        p_buffer += datalen2;
    }
    if (datalen3 > 0) {
        memcpy(p_buffer, data3, datalen3);
        p_buffer += datalen3;
    }

    sha204c_calculate_crc(len - SHA204_CRC_SIZE, tx_buffer, p_buffer);

    // Send command and receive response.
    return sha204c_send_and_receive(&tx_buffer[0], response_size,
                                    &rx_buffer[0], poll_delay, poll_timeout);
}