From 66fe491507ecfce89e7efc26df0c57527b20f3b6 Mon Sep 17 00:00:00 2001 From: Scott Thibault Date: Wed, 22 Feb 2017 22:41:22 -0500 Subject: [PATCH] Initial beta version --- Makefile | 9 + README.md | 37 + .../provision_sha204/provision_sha204.ino | 206 ++ library.properties | 9 + src/CryptoAuthLib.h | 62 + src/atca_command.c | 787 +++++ src/atca_command.h | 621 ++++ src/atca_compiler.h | 73 + src/atca_device.c | 119 + src/atca_device.h | 69 + src/atca_devtypes.h | 64 + src/atca_iface.c | 178 + src/atca_iface.h | 141 + src/atca_status.h | 92 + src/basic/README.md | 13 + src/basic/atca_basic.c | 2911 +++++++++++++++++ src/basic/atca_basic.h | 137 + src/basic/atca_helpers.c | 222 ++ src/basic/atca_helpers.h | 82 + src/crypto/README.md | 6 + src/crypto/atca_crypto_sw.h | 47 + src/crypto/atca_crypto_sw_ecdsa.c | 58 + src/crypto/atca_crypto_sw_ecdsa.h | 76 + src/crypto/atca_crypto_sw_rand.c | 53 + src/crypto/atca_crypto_sw_rand.h | 67 + src/crypto/atca_crypto_sw_sha1.c | 87 + src/crypto/atca_crypto_sw_sha1.h | 77 + src/crypto/atca_crypto_sw_sha2.c | 113 + src/crypto/atca_crypto_sw_sha2.h | 77 + src/crypto/hashes/sha1_routines.c | 295 ++ src/crypto/hashes/sha1_routines.h | 99 + src/crypto/hashes/sha2_routines.c | 228 ++ src/crypto/hashes/sha2_routines.h | 74 + src/hal/atca_hal.c | 179 + src/hal/atca_hal.h | 177 + src/hal/atca_start_config.h | 6 + src/hal/atca_start_iface.h | 6 + src/hal/hal_samd21_i2c_wire.cpp | 258 ++ src/hal/hal_samd21_i2c_wire.h | 14 + src/hal/hal_samd21_timer_wire.cpp | 12 + src/host/atca_host.c | 1038 ++++++ src/host/atca_host.h | 455 +++ 42 files changed, 9334 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 examples/provision_sha204/provision_sha204.ino create mode 100644 library.properties create mode 100644 src/CryptoAuthLib.h create mode 100644 src/atca_command.c create mode 100644 src/atca_command.h create mode 100644 src/atca_compiler.h create mode 100644 src/atca_device.c create mode 100644 src/atca_device.h create mode 100644 src/atca_devtypes.h create mode 100644 src/atca_iface.c create mode 100644 src/atca_iface.h create mode 100644 src/atca_status.h create mode 100644 src/basic/README.md create mode 100644 src/basic/atca_basic.c create mode 100644 src/basic/atca_basic.h create mode 100644 src/basic/atca_helpers.c create mode 100644 src/basic/atca_helpers.h create mode 100644 src/crypto/README.md create mode 100644 src/crypto/atca_crypto_sw.h create mode 100644 src/crypto/atca_crypto_sw_ecdsa.c create mode 100644 src/crypto/atca_crypto_sw_ecdsa.h create mode 100644 src/crypto/atca_crypto_sw_rand.c create mode 100644 src/crypto/atca_crypto_sw_rand.h create mode 100644 src/crypto/atca_crypto_sw_sha1.c create mode 100644 src/crypto/atca_crypto_sw_sha1.h create mode 100644 src/crypto/atca_crypto_sw_sha2.c create mode 100644 src/crypto/atca_crypto_sw_sha2.h create mode 100644 src/crypto/hashes/sha1_routines.c create mode 100644 src/crypto/hashes/sha1_routines.h create mode 100644 src/crypto/hashes/sha2_routines.c create mode 100644 src/crypto/hashes/sha2_routines.h create mode 100644 src/hal/atca_hal.c create mode 100644 src/hal/atca_hal.h create mode 100644 src/hal/atca_start_config.h create mode 100644 src/hal/atca_start_iface.h create mode 100644 src/hal/hal_samd21_i2c_wire.cpp create mode 100644 src/hal/hal_samd21_i2c_wire.h create mode 100644 src/hal/hal_samd21_timer_wire.cpp create mode 100644 src/host/atca_host.c create mode 100644 src/host/atca_host.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d2e843b --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +all: CryptoAuthLib.zip + +.PHONY: CryptoAuthLib.zip +CryptoAuthLib.zip: + -rm CryptoAuthLib.zip + -rm -rf release + mkdir -p release + cp -r library.properties src examples release + cd release; zip -r ../CryptoAuthLib.zip * --exclude '*~' diff --git a/README.md b/README.md new file mode 100644 index 0000000..c2ba3ba --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# CryptoAuthLib + +This is a port of the Atmel +[CryptoAuthLib](http://www.atmel.com/tools/CryptoAuthLib.aspx) library +for the Arduino platform. + +This is **beta** release, see disclaimer below. + +## License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. The name of Atmel may not be used to endorse or promote products derived + from this software without specific prior written permission. + +4. This software may only be redistributed and used in connection with an + Atmel integrated circuit. + +THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE +EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/examples/provision_sha204/provision_sha204.ino b/examples/provision_sha204/provision_sha204.ino new file mode 100644 index 0000000..edf0dd8 --- /dev/null +++ b/examples/provision_sha204/provision_sha204.ino @@ -0,0 +1,206 @@ +#include +#include +#include + +// Set to 1 to lock the data zone on success +#define LOCK_DATA 0 + +// Some slot configuration +uint8_t slot_config[3][4] { + {0x80, 0x40, 0x81, 0x41}, // slot 0 - private key, slot 1 - private key + {0x82, 0x30, 0x83, 0x31}, // slot 2 - derived key from 0, slot 3 - derived key from 1 + {0x04, 0x04, 0x05, 0x05} // slot 4 - user r/w data, slot 5 - user r/w data +}; + +// Private root keys. REPLACE THESE WITH SECRET KEYS +uint8_t root_keys[2][32] = { + {0x08,0xe6,0xe6,0x93,0x69,0x4a,0x4c,0xd7,0x84,0xf2,0x09,0xb6,0x74,0x6d,0xea,0x1e,0x8e,0x1d,0xa0,0xa8,0x21,0xaa,0x4f,0x59,0xb0,0x63,0xe7,0x80,0x93,0x69,0x2f,0x7c}, + {0x16,0x90,0x16,0x64,0x1b,0xe8,0x48,0x10,0x96,0xe2,0x94,0x18,0x1b,0x34,0x72,0x6d,0x6f,0x25,0xc4,0xac,0xa3,0x3a,0x4e,0xdc,0xa0,0xb3,0x8b,0xd6,0x43,0x16,0xf6,0x0c} +}; + +// A test challenge +uint8_t challenge[32] = { + 0x11,0x11,0x11,0x11,0x21,0x21,0x21,0x21,0x31,0x31,0x31,0x31,0x41,0x41,0x41,0x41,0xa2,0xa2,0xa2,0xa2,0xb2,0xb2,0xb2,0xb2,0xc2,0xc2,0xc2,0xc2,0xd2,0xd2,0xd2,0xd2 +}; + +// The expected reponse for the sample root keys and test challenge above +uint8_t answers[2][32] = { + {0x10,0x2a,0xd5,0xa1,0xfa,0xc1,0xfd,0x52,0xf6,0xac,0x02,0xb1,0xf7,0xd8,0x3d,0x86,0x31,0x25,0x0b,0x0c,0x9e,0xbd,0xd1,0x31,0xda,0x5e,0x59,0x36,0x4d,0xf3,0x10,0xb3}, + {0x76,0xa3,0x47,0x93,0xd0,0x9c,0x25,0xaf,0x91,0xed,0x49,0x3f,0x0b,0xaa,0xb6,0xb3,0x55,0x0c,0x51,0x0a,0x26,0x13,0x00,0xbb,0xbb,0x62,0x89,0xc7,0x37,0x2f,0x79,0x1a} +}; + +// Helper function to initialize library for a particular device. + +bool config_device(ATCADeviceType dev, uint8_t addr, uint32_t baud = 400000, int retries = 10) { + static ATCAIfaceCfg cfg; + cfg.iface_type = ATCA_I2C_IFACE, + cfg.devtype = dev; + cfg.atcai2c.slave_address = addr << 1; + cfg.atcai2c.baud = baud; + cfg.atcai2c.bus = 0; + cfg.wake_delay = (dev == ATECC108A) ? 800 : 2560; + cfg.rx_retries = retries; + if (atcab_init(&cfg) != ATCA_SUCCESS) + return false; + atcab_wakeup(); // may return error if device is already awake + return true; +}; + +// Provision and test SHA204A chip + +void setup() { + int i, res; + bool locked; + uint8_t cfg_word[4]; + uint8_t response[32]; + + Serial.begin(9600); + Wire.begin(); + + delay(15000); // a little time to open serial monitor please! + + Serial.println("Provision SHA204"); + + config_device(ATSHA204A, 0x64); + res = atcab_is_locked(LOCK_ZONE_CONFIG, &locked); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_is_locked error "); + Serial.println(res, HEX); + return; + } + if (!locked) { + // Not locked, configure slots 0-5 with our slot_config data. + for (i = 0; i < 3; i++) { + res = atcab_write_zone(ATCA_ZONE_CONFIG, 0, 0, 0x5+i, slot_config[i], 4); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_write_zone error "); + Serial.println(res, HEX); + return; + } + } + } else { + Serial.println("config already locked"); + } + + for (i = 0; i < 3; i++) { + // Validate the configuration of slots 0-5 + res = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 0, 0x5+i, cfg_word, 4); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_read_zone error "); + Serial.println(res, HEX); + return; + } + Serial.print(0x5+i, HEX); + Serial.print(": "); + Serial.print(cfg_word[0], HEX); + Serial.print(" "); + Serial.print(cfg_word[1], HEX); + Serial.print(" "); + Serial.print(cfg_word[2], HEX); + Serial.print(" "); + Serial.println(cfg_word[3], HEX); + if (memcmp(cfg_word, slot_config[i], 4) != 0) { + Serial.println("read back error"); + return; + } + } + Serial.println("configuration good"); + + if (!locked) { + // If the configuration is good, lock it down! + res = atcab_lock_config_zone(response); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_lock_config_zone error "); + Serial.println(res, HEX); + return; + } + if (response[0] != 0) { + Serial.print("configuration lock failed "); + Serial.println(response[0], HEX); + return; + } + Serial.println("configuration successfully locked!"); + } + + res = atcab_is_locked(LOCK_ZONE_DATA, &locked); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_is_locked error "); + Serial.println(res, HEX); + return; + } + if (!locked) { + // Write our root keys to slots 0/1 + for (i = 0; i < 2; i++) { + res = atcab_write_zone(ATCA_ZONE_DATA, i, 0, 0, root_keys[i], 32); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_write_zone error "); + Serial.println(res, HEX); + return; + } + } + } else { + Serial.println("data already locked"); + } + + // Run test with slot 0 key + Serial.println("test root key 0"); + atcab_mac(0x00, 0x0, challenge, response); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_mac error "); + Serial.println(res, HEX); + return; + } + if (memcmp(response, answers[0], 32) == 0) { + Serial.println("TEST 1 PASSED!"); + } else { + Serial.print("TEST 1 FAILED:"); + for (i = 0; i < 32; i++) { + Serial.print(" "); + Serial.print(response[i], HEX); + } + Serial.println(""); + return; + } + + // Run test with slot 1 key + Serial.println("test root key 1"); + atcab_mac(0x00, 0x1, challenge, response); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_mac error "); + Serial.println(res, HEX); + return; + } + if (memcmp(response, answers[1], 32) == 0) { + Serial.println("TEST 2 PASSED!"); + } else { + Serial.print("TEST 2 FAILED:"); + for (i = 0; i < 32; i++) { + Serial.print(" "); + Serial.print(response[i], HEX); + } + Serial.println(""); + return; + } + +#if LOCK_DATA + res = atcab_lock_data_zone(response); + if (res != ATCA_SUCCESS) { + Serial.print("atcab_lock_data_zone error "); + Serial.println(res, HEX); + return; + } + if (response[0] != 0) { + Serial.print("data lock failed "); + Serial.println(response[0], HEX); + return; + } + Serial.println("DATA successfully locked!"); +#else + Serial.println("DON'T FORGET TO LOCK DATA"); +#endif +} + +void loop() { + delay(1000); +} + diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..eac21bf --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=cryptoauthlib +author=sathibault +version=0.0.1 +maintainer=https://github.com/sathibault +sentence=Library interface to Atmel CryptoAuthentication chips +paragraph=Library interface to Atmel CryptoAuthentication chips +category=Communication +url=https://github.com/sathibault/cryptoauthlibuino +architectures=samd,avr diff --git a/src/CryptoAuthLib.h b/src/CryptoAuthLib.h new file mode 100644 index 0000000..2ee5f68 --- /dev/null +++ b/src/CryptoAuthLib.h @@ -0,0 +1,62 @@ +/** + * \file + * \brief Single aggregation point for all CryptoAuthLib header files + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef _ATCA_LIB_H +#define _ATCA_LIB_H + +#include +#include + +#define ATCA_HAL_I2C + +#include "hal/atca_hal.h" +#include "atca_status.h" +#include "atca_device.h" +#include "atca_command.h" +//#include "atca_cfgs.h" +#include "basic/atca_basic.h" +#include "basic/atca_helpers.h" + +//#define BREAK(status, message) break +//#define DBGOUT(message) break +//#define PRINT(message) break + +#endif diff --git a/src/atca_command.c b/src/atca_command.c new file mode 100644 index 0000000..8fa6fac --- /dev/null +++ b/src/atca_command.c @@ -0,0 +1,787 @@ +/** + * \file + * \brief Atmel CryptoAuthentication device command builder - this is the main object that builds the command + * byte strings for the given device. It does not execute the command. The basic flow is to call + * a command method to build the command you want given the parameters and then send that byte string + * through the device interface. + * + * The primary goal of the command builder is to wrap the given parameters with the correct packet size and CRC. + * The caller should first fill in the parameters required in the ATCAPacket parameter given to the command. + * The command builder will deal with the mechanics of creating a valid packet using the parameter information. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include +#include +#include "atca_command.h" +#include "atca_devtypes.h" + +/** \defgroup command ATCACommand (atca_) + \brief CryptoAuthLib command builder object, ATCACommand. Member functions for the ATCACommand object. + @{ */ + +/** \brief atca_command is the C object backing ATCACommand. See the atca_command.h file for + * details on the ATCACommand methods + */ +struct atca_command { + ATCADeviceType dt; + uint16_t *execution_times; +}; + + +/** \brief constructor for ATCACommand + * \param[in] device_type - specifies which set of commands and execution times should be associated with this command object + * \return ATCACommand instance + */ +ATCACommand newATCACommand( ATCADeviceType device_type ) // constructor +{ + ATCA_STATUS status = ATCA_SUCCESS; + ATCACommand cacmd = (ATCACommand)malloc(sizeof(struct atca_command)); + + cacmd->dt = device_type; + status = atInitExecTimes(cacmd, device_type); // setup typical execution times for this device type + + if (status != ATCA_SUCCESS) { + free(cacmd); + cacmd = NULL; + } + + return cacmd; +} + + +// full superset of commands goes here + +/** \brief ATCACommand CheckMAC method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atCheckMAC(ATCACommand cacmd, ATCAPacket *packet ) +{ + // Set the opcode & parameters + packet->opcode = ATCA_CHECKMAC; + packet->txsize = CHECKMAC_COUNT; + packet->rxsize = CHECKMAC_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Counter method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atCounter(ATCACommand cacmd, ATCAPacket *packet ) +{ + if ( !atIsECCFamily( cacmd->dt ) ) + return ATCA_BAD_OPCODE; + + // Set the opcode & parameters + packet->opcode = ATCA_COUNTER; + packet->txsize = COUNTER_COUNT; + packet->rxsize = COUNTER_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand DeriveKey method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \param[in] hasMAC hasMAC determines if MAC data is present in the packet input + * \return ATCA_STATUS + */ +ATCA_STATUS atDeriveKey(ATCACommand cacmd, ATCAPacket *packet, bool hasMAC ) +{ + // Set the opcode & parameters + packet->opcode = ATCA_DERIVE_KEY; + + // hasMAC must be given since the packet does not have any implicit information to + // know if it has a mac or not unless the size is preset + switch ( hasMAC ) { + case true: + packet->txsize = DERIVE_KEY_COUNT_LARGE; + break; + case false: + packet->txsize = DERIVE_KEY_COUNT_SMALL; + break; + } + + packet->rxsize = DERIVE_KEY_RSP_SIZE; + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand ECDH method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atECDH(ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_ECDH; + packet->txsize = ECDH_COUNT; + packet->rxsize = ECDH_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Generate Digest method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \param[in] hasMACKey + * \return ATCA_STATUS + */ +ATCA_STATUS atGenDig(ATCACommand cacmd, ATCAPacket *packet, bool hasMACKey ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_GENDIG; + + if ( packet->param1 == 0x03 ) // shared nonce mode + packet->txsize = GENDIG_COUNT + 32; + else if ( hasMACKey == true ) + packet->txsize = GENDIG_COUNT_DATA; + else + packet->txsize = GENDIG_COUNT; + + packet->rxsize = GENDIG_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Generate Key method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \param[in] isPubKey indicates whether "other data" is present in packet + * \return ATCA_STATUS + */ +ATCA_STATUS atGenKey(ATCACommand cacmd, ATCAPacket *packet, bool isPubKey ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_GENKEY; + + switch ( isPubKey ) { + case true: + packet->txsize = GENKEY_COUNT_DATA; + break; + case false: + packet->txsize = GENKEY_COUNT; + break; + } + + packet->rxsize = GENKEY_RSP_SIZE_LONG; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand HMAC method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atHMAC(ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_HMAC; + packet->txsize = HMAC_COUNT; + packet->rxsize = HMAC_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Info method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atInfo( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_INFO; + packet->txsize = INFO_COUNT; + packet->rxsize = INFO_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Lock method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atLock( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_LOCK; + packet->txsize = LOCK_COUNT; + packet->rxsize = LOCK_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand MAC method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atMAC( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + // variable packet size + packet->opcode = ATCA_MAC; + if ( packet->param1 == 0 ) + packet->txsize = MAC_COUNT_LONG; + else + packet->txsize = MAC_COUNT_SHORT; + + packet->rxsize = MAC_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Nonce method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atNonce( ATCACommand cacmd, ATCAPacket *packet ) +{ + // Set the opcode & parameters + // variable packet size + packet->opcode = ATCA_NONCE; + int mode = packet->param1 & 0x03; + + if ( (mode == 0 || mode == 1) ) { // mode[0:1] == 0 | 1 then NumIn is 20 bytes + packet->txsize = NONCE_COUNT_SHORT; // 20 byte challenge + packet->rxsize = NONCE_RSP_SIZE_LONG; + } else if ( mode == 0x03 ) { // NumIn is 32 bytes + packet->txsize = NONCE_COUNT_LONG; // 32 byte challenge + packet->rxsize = NONCE_RSP_SIZE_SHORT; + } else + return ATCA_BAD_PARAM; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Pause method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atPause( ATCACommand cacmd, ATCAPacket *packet ) +{ + // Set the opcode & parameters + packet->opcode = ATCA_PAUSE; + packet->txsize = PAUSE_COUNT; + packet->rxsize = PAUSE_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand PrivWrite method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atPrivWrite( ATCACommand cacmd, ATCAPacket *packet ) +{ + // Set the opcode & parameters + packet->opcode = ATCA_PRIVWRITE; + packet->txsize = PRIVWRITE_COUNT; + packet->rxsize = PRIVWRITE_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Random method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atRandom( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_RANDOM; + packet->txsize = RANDOM_COUNT; + packet->rxsize = RANDOM_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Read method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atRead( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_READ; + packet->txsize = READ_COUNT; + + // variable response size based on read type + if ((packet->param1 & 0x80) == 0 ) + packet->rxsize = READ_4_RSP_SIZE; + else + packet->rxsize = READ_32_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand SHA method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atSHA( ATCACommand cacmd, ATCAPacket *packet ) +{ + if ( packet->param2 > SHA_BLOCK_SIZE ) + return ATCA_BAD_PARAM; + + if ( packet->param1 == 0x01 && packet->param2 != SHA_BLOCK_SIZE ) + return ATCA_BAD_PARAM; // updates should always have 64 bytes of data + + if ( packet->param1 == 0x02 && packet->param2 > SHA_BLOCK_SIZE - 1 ) // END should be 0-63 bytes + return ATCA_BAD_PARAM; + + // Set the opcode & parameters + packet->opcode = ATCA_SHA; + + switch ( packet->param1 ) { + case 0x00: // START + packet->rxsize = SHA_RSP_SIZE_SHORT; + packet->txsize = SHA_COUNT_LONG; + break; + case 0x01: // UPDATE + packet->rxsize = SHA_RSP_SIZE_SHORT; + packet->txsize = SHA_COUNT_LONG + SHA_BLOCK_SIZE; + break; + case 0x02: // END + packet->rxsize = SHA_RSP_SIZE_LONG; + // check the given packet for a size variable in param2. If it is > 0, it should + // be 0-63, incorporate that size into the packet + packet->txsize = SHA_COUNT_LONG + packet->param2; + break; + } + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Sign method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atSign( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_SIGN; + packet->txsize = SIGN_COUNT; + + // could be a 64 or 72 byte response depending upon the key configuration for the KeyID + packet->rxsize = ATCA_RSP_SIZE_64; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand UpdateExtra method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atUpdateExtra( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_UPDATE_EXTRA; + packet->txsize = UPDATE_COUNT; + packet->rxsize = UPDATE_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand ECDSA Verify method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atVerify( ATCACommand cacmd, ATCAPacket *packet ) +{ + + // Set the opcode & parameters + packet->opcode = ATCA_VERIFY; + + // variable packet size based on mode + switch ( packet->param1 ) { + case 0: // Stored mode + packet->txsize = VERIFY_256_STORED_COUNT; + break; + case 1: // ValidateExternal mode + packet->txsize = VERIFY_256_EXTERNAL_COUNT; + break; + case 2: // External mode + packet->txsize = VERIFY_256_EXTERNAL_COUNT; + break; + case 3: // Validate mode + case 7: // Invalidate mode + packet->txsize = VERIFY_256_VALIDATE_COUNT; + break; + default: + return ATCA_BAD_PARAM; + } + packet->rxsize = VERIFY_RSP_SIZE; + + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Write method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atWrite( ATCACommand cacmd, ATCAPacket *packet ) +{ + int macsize; + int writesize; + + // Set the opcode & parameters + packet->opcode = ATCA_WRITE; + + macsize = ( packet->param1 & 0x40 ? 32 : 0 ); // if encrypted, use MAC + writesize = ( packet->param1 & 0x80 ? 32 : 4 ); + + if ( macsize == 32 && writesize == 32 ) + packet->txsize = WRITE_COUNT_LONG_MAC; + else if ( macsize == 32 && writesize == 4 ) + packet->txsize = WRITE_COUNT_SHORT_MAC; + else if ( macsize == 0 && writesize == 32 ) + packet->txsize = WRITE_COUNT_LONG; + else if ( macsize == 0 && writesize == 4 ) + packet->txsize = WRITE_COUNT_SHORT; + + packet->rxsize = WRITE_RSP_SIZE; + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand Write encrypted method + * \param[in] cacmd instance + * \param[in] packet pointer to the packet containing the command being built + * \return ATCA_STATUS + */ +ATCA_STATUS atWriteEnc(ATCACommand cacmd, ATCAPacket *packet) +{ + // Set the opcode & parameters + packet->opcode = ATCA_WRITE; + packet->txsize = WRITE_COUNT_LONG_MAC; + packet->rxsize = WRITE_RSP_SIZE; + atCalcCrc( packet ); + return ATCA_SUCCESS; +} + +/** \brief ATCACommand destructor + * \param[in] cacmd instance of a command object + */ + +void deleteATCACommand( ATCACommand *cacmd ) // destructor +{ + if ( *cacmd ) + free((void*)*cacmd); + + *cacmd = NULL; +} + + +/** \brief execution times for x08a family, these are based on the typical value from the datasheet + */ +uint16_t exectimes_x08a[] = { // in milleseconds + 1, // WAKE_TWHI + 13, // CMD_CHECKMAC + 20, // CMD_COUNTER + 50, // CMD_DERIVEKEY + 58, // CMD_ECDH + 11, // CMD_GENDIG + 115, // CMD_GENKEY + 23, // CMD_HMAC + 2, // CMD_INFO + 32, // CMD_LOCK + 14, // CMD_MAC + 29, // CMD_NONCE + 3, // CMD_PAUSE + 48, // CMD_PRIVWRITE + 23, // CMD_RANDOM with SEED Update mode takes ~21ms, high side of range + 1, // CMD_READMEM + 9, // CMD_SHA + 60, // CMD_SIGN + 10, // CMD_UPDATEEXTRA + 72, // CMD_VERIFY + 26 // CMD_WRITE +}; + + +/** \brief execution times for 204a, these are based on the typical value from the datasheet + */ +uint16_t exectimes_204a[] = { + 3, // WAKE_TWHI + 38, // CMD_CHECKMAC + 0, + 62, // CMD_DERIVEKEY + 0, + 43, // CMD_GENDIG + 0, + 69, // CMD_HMAC + 2, // CMD_DevRev + 24, // CMD_LOCK + 35, // CMD_MAC + 60, // CMD_NONCE + 2, // CMD_PAUSE + 0, + 50, // CMD_RANDOM + 4, // CMD_READMEM + 22, // CMD_SHA + 0, + 12, // CMD_UPDATEEXTRA + 0, + 42 // CMD_WRITEMEM +}; + +/** \brief initialize the execution times for a given device type + * + * \param[in] cacmd - the command containing the list of execution times for the device + * \param[in] device_type - the device type - execution times vary by device type + * \return ATCA_STATUS + */ + +ATCA_STATUS atInitExecTimes(ATCACommand cacmd, ATCADeviceType device_type) +{ + switch ( device_type ) { + case ATECC108A: + case ATECC508A: + cacmd->execution_times = exectimes_x08a; + break; + case ATSHA204A: + cacmd->execution_times = exectimes_204a; + break; + default: + return ATCA_BAD_PARAM; + break; + } + + return ATCA_SUCCESS; +} + +/** \brief return the typical execution type for the given command + * + * \param[in] cacmd the command object for which the execution times are associated + * \param[in] cmd - the specific command for which to lookup the execution time + * \return typical execution time in milleseconds for the given command + */ + +uint16_t atGetExecTime( ATCACommand cacmd, ATCA_CmdMap cmd ) +{ + return cacmd->execution_times[cmd]; +} + + +/** \brief This function calculates CRC given raw data, puts the CRC to given pointer + * + * \param[in] length size of data not including the CRC byte positions + * \param[in] data pointer to the data over which to compute the CRC + * \param[out] crc pointer to the place where the two-bytes of CRC will be placed + */ + +void atCRC( uint8_t length, uint8_t *data, uint8_t *crc) +{ + uint8_t counter; + uint16_t crc_register = 0; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + crc_register <<= 1; + if (data_bit != crc_bit) + crc_register ^= polynom; + } + } + crc[0] = (uint8_t)(crc_register & 0x00FF); + crc[1] = (uint8_t)(crc_register >> 8); +} + + +/** \brief This function calculates CRC and adds it to the correct offset in the packet data + * \param[in] packet Packet to calculate CRC data for + */ + +void atCalcCrc( ATCAPacket *packet ) +{ + uint8_t length, *crc; + + length = packet->txsize - ATCA_CRC_SIZE; + // computer pointer to CRC in the packet + crc = &(packet->txsize) + length; + + // stuff CRC into packet + atCRC(length, &(packet->txsize), crc); +} + + +/** \brief This function checks the consistency of a response. + * \param[in] response pointer to response + * \return status of the consistency check + */ + +uint8_t atCheckCrc(uint8_t *response) +{ + uint8_t crc[ATCA_CRC_SIZE]; + uint8_t count = response[ATCA_COUNT_IDX]; + + count -= ATCA_CRC_SIZE; + atCRC(count, response, crc); + + return (crc[0] == response[count] && crc[1] == response[count + 1]) ? ATCA_SUCCESS : ATCA_BAD_CRC; +} + + +/** \brief determines if a given device type is a SHA device or a superset of a SHA device + * \param[in] deviceType - the type of device to check for family type + * \return boolean indicating whether the given device is a SHA family device. + */ + +bool atIsSHAFamily( ATCADeviceType deviceType ) +{ + switch (deviceType) { + case ATSHA204A: + case ATECC108A: + case ATECC508A: + return true; + break; + default: + return false; + break; + } +} + +/** \brief determines if a given device type is an ECC device or a superset of a ECC device + * \param[in] deviceType - the type of device to check for family type + * \return boolean indicating whether the given device is an ECC family device. + */ + +bool atIsECCFamily( ATCADeviceType deviceType ) +{ + switch (deviceType) { + case ATECC108A: + case ATECC508A: + return true; + break; + default: + return false; + break; + } +} + +/** \brief checks for basic error frame in data + * \param[in] data pointer to received data - expected to be in the form of a CA device response frame + * \return ATCA_STATUS indicating type of error or no error + */ + +ATCA_STATUS isATCAError( uint8_t *data ) +{ + uint8_t good[4] = { 0x04, 0x00, 0x03, 0x40 }; + + if ( memcmp( data, good, 4 ) == 0 ) + return ATCA_SUCCESS; + + if ( data[0] == 0x04 ) { // error packets are always 4 bytes long + switch ( data[1] ) { + case 0x01: // checkmac or verify failed + return ATCA_CHECKMAC_VERIFY_FAILED; + break; + case 0x03: // command received byte length, opcode or parameter was illegal + return ATCA_BAD_OPCODE; + break; + case 0x0f: // chip can't execute the command + return ATCA_EXECUTION_ERROR; + break; + case 0x11: // chip was successfully woken up + return ATCA_WAKE_SUCCESS; + break; + case 0xff: // bad crc found or other comm error + return ATCA_STATUS_CRC; + break; + default: + return ATCA_GEN_FAIL; + break; + } + } else + return ATCA_SUCCESS; +} + +/** @} */ diff --git a/src/atca_command.h b/src/atca_command.h new file mode 100644 index 0000000..53e7ee5 --- /dev/null +++ b/src/atca_command.h @@ -0,0 +1,621 @@ +/** + * \file + * \brief Atmel Crypto Auth device command object - this is a command builder only, it does + * not send the command. The result of a command method is a fully formed packet, ready to send + * to the ATCAIFace object to dispatch. + * + * This command object supports the ATSHA and ATECC device family. + * The command list is a superset of all device commands for this family. The command object + * differentiates the packet contents based on specific device type within the family. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_COMMAND_H +#define ATCA_COMMAND_H + +#include "atca_compiler.h" +#include "atca_status.h" +#include "atca_devtypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*--- ATCACommand ---------*/ +typedef struct atca_command * ATCACommand; +ATCACommand newATCACommand(ATCADeviceType device_type); // constructor + +/* add ATCACommand declarations here + * + * since these are still C functions, not classes, naming is an important + * consideration to keep the namespace from colliding with other 3rd party + * libraries or even ourselves/ASF. + * + * Basic conventions: + * all methods start with the prefix 'at' + * all method names must be unique, obviously + * all method implementations should be proceeded by their Doxygen comment header + * + **/ + + +// this is the ATCACommand parameter structure. The caller to the command method must +// initialize param1, param2 and data if appropriate. The command method will fill in the rest +// and initialize the packet so it's ready to send via the ATCAIFace. +// this particular structure mimics the ATSHA and ATECC family device's command structures + +// Note: pack @ 2 is required, @ 1 causes word alignment crash (though it should not), a known bug in GCC. +// @2, the wire still has the intended byte alignment with arm-eabi. this is likely the least portable part of atca + +#pragma pack( push, ATCAPacket, 2 ) +/** \brief an ATCA packet structure. This is a superset of the packet transmitted on the wire. It's also + * used as a buffer for receiving the response + */ +typedef struct { + + // used for transmit/send + uint8_t _reserved; // used by HAL layer as needed (I/O tokens, Word address values) + + //--- start of packet i/o frame---- + uint8_t txsize; + uint8_t opcode; + uint8_t param1; // often same as mode + uint16_t param2; + uint8_t data[130]; // includes 2-byte CRC. data size is determined by largest possible data section of any + // command + crc (see: x08 verify data1 + data2 + data3 + data4) + // this is an explicit design trade-off (space) resulting in simplicity in use + // and implementation + //--- end of packet i/o frame + + // used for receive + uint8_t execTime; // execution time of command by opcode + uint16_t rxsize; // expected response size, response is held in data member + + // structure should be packed since it will be transmitted over the wire + // this method varies by compiler. As new compilers are supported, add their structure packing method here + +} ATCAPacket; +#pragma pack( pop, ATCAPacket) + +ATCA_STATUS atCheckMAC(ATCACommand cacmd, ATCAPacket *packet); +ATCA_STATUS atCounter(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atDeriveKey(ATCACommand cacmd, ATCAPacket *packet, bool hasMAC ); +ATCA_STATUS atECDH(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atGenDig(ATCACommand cacmd, ATCAPacket *packet, bool hasMACKey ); +ATCA_STATUS atGenKey(ATCACommand cacmd, ATCAPacket *packet, bool isPubKey ); +ATCA_STATUS atHMAC(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atInfo(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atLock(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atMAC(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atNonce(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atPause(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atPrivWrite(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atRandom(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atRead(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atSHA(ATCACommand cacmd, ATCAPacket *packet ); +ATCA_STATUS atSign(ATCACommand cacmd, ATCAPacket *packet); +ATCA_STATUS atUpdateExtra(ATCACommand cacmd, ATCAPacket *packet); +ATCA_STATUS atVerify(ATCACommand cacmd, ATCAPacket *packet); +ATCA_STATUS atWrite(ATCACommand cacmd, ATCAPacket *packet); +ATCA_STATUS atWriteEnc(ATCACommand cacmd, ATCAPacket *packet); + +bool atIsSHAFamily( ATCADeviceType deviceType ); +bool atIsECCFamily( ATCADeviceType deviceType ); +ATCA_STATUS isATCAError( uint8_t *data ); + +// this map is used to index into an array of execution times +typedef enum { + WAKE_TWHI, + CMD_CHECKMAC, + CMD_COUNTER, + CMD_DERIVEKEY, + CMD_ECDH, + CMD_GENDIG, + CMD_GENKEY, + CMD_HMAC, + CMD_INFO, + CMD_LOCK, + CMD_MAC, + CMD_NONCE, + CMD_PAUSE, + CMD_PRIVWRITE, + CMD_RANDOM, + CMD_READMEM, + CMD_SHA, + CMD_SIGN, + CMD_UPDATEEXTRA, + CMD_VERIFY, + CMD_WRITEMEM, + CMD_LASTCOMMAND // placeholder +} ATCA_CmdMap; + +ATCA_STATUS atInitExecTimes(ATCACommand cacmd, ATCADeviceType device_type); +uint16_t atGetExecTime( ATCACommand cacmd, ATCA_CmdMap cmd ); + +void deleteATCACommand( ATCACommand * ); // destructor +/*---- end of ATCACommand ----*/ + +// command helpers +void atCRC( uint8_t length, uint8_t *data, uint8_t *crc); +void atCalcCrc( ATCAPacket *pkt); +uint8_t atCheckCrc(uint8_t *response); + + +/* command definitions */ + +//! minimum number of bytes in command (from count byte to second CRC byte) +#define ATCA_CMD_SIZE_MIN ((uint8_t)7) +//! maximum size of command packet (Verify) +#define ATCA_CMD_SIZE_MAX ((uint8_t)4 * 36 + 7) +//! status byte for success +#define CMD_STATUS_SUCCESS ((uint8_t)0x00) +//! status byte after wake-up +#define CMD_STATUS_WAKEUP ((uint8_t)0x11) +//! command parse error +#define CMD_STATUS_BYTE_PARSE ((uint8_t)0x03) +//! command ECC error +#define CMD_STATUS_BYTE_ECC ((uint8_t)0x05) +//! command execution error +#define CMD_STATUS_BYTE_EXEC ((uint8_t)0x0F) +//! communication error +#define CMD_STATUS_BYTE_COMM ((uint8_t)0xFF) + +/** \brief + @{ */ + +/** \name opcodes for ATATECC Commands + @{ */ +#define ATCA_CHECKMAC ((uint8_t)0x28) //!< CheckMac command op-code +#define ATCA_DERIVE_KEY ((uint8_t)0x1C) //!< DeriveKey command op-code +#define ATCA_INFO ((uint8_t)0x30) //!< Info command op-code +#define ATCA_GENDIG ((uint8_t)0x15) //!< GenDig command op-code +#define ATCA_GENKEY ((uint8_t)0x40) //!< GenKey command op-code +#define ATCA_HMAC ((uint8_t)0x11) //!< HMAC command op-code +#define ATCA_LOCK ((uint8_t)0x17) //!< Lock command op-code +#define ATCA_MAC ((uint8_t)0x08) //!< MAC command op-code +#define ATCA_NONCE ((uint8_t)0x16) //!< Nonce command op-code +#define ATCA_PAUSE ((uint8_t)0x01) //!< Pause command op-code +#define ATCA_PRIVWRITE ((uint8_t)0x46) //!< PrivWrite command op-code +#define ATCA_RANDOM ((uint8_t)0x1B) //!< Random command op-code +#define ATCA_READ ((uint8_t)0x02) //!< Read command op-code +#define ATCA_SIGN ((uint8_t)0x41) //!< Sign command op-code +#define ATCA_UPDATE_EXTRA ((uint8_t)0x20) //!< UpdateExtra command op-code +#define ATCA_VERIFY ((uint8_t)0x45) //!< GenKey command op-code +#define ATCA_WRITE ((uint8_t)0x12) //!< Write command op-code +#define ATCA_ECDH ((uint8_t)0x43) //!< ECDH command op-code +#define ATCA_COUNTER ((uint8_t)0x24) //!< Counter command op-code +#define ATCA_SHA ((uint8_t)0x47) //!< SHA command op-code +/** @} */ + + +/** \name Definitions of Data and Packet Sizes + @{ */ +#define ATCA_BLOCK_SIZE (32) //!< size of a block +#define ATCA_WORD_SIZE (4) //!< size of a word +#define ATCA_PUB_KEY_PAD (4) //!< size of the public key pad +#define ATCA_SERIAL_NUM_SIZE (9) //!< number of bytes in the device serial number +#define ATCA_RSP_SIZE_VAL ((uint8_t)7) //!< size of response packet containing four bytes of data +#define ATCA_KEY_COUNT (16) //!< number of keys +#define ATCA_CONFIG_SIZE (128) //!< size of configuration zone +#define ATCA_SHA_CONFIG_SIZE (88) //!< size of configuration zone +#define ATCA_OTP_SIZE (64) //!< size of OTP zone +#define ATCA_DATA_SIZE (ATCA_KEY_COUNT * ATCA_KEY_SIZE) //!< size of data zone + +#define ATCA_COUNT_SIZE ((uint8_t)1) //!< Number of bytes in the command packet Count +#define ATCA_CRC_SIZE ((uint8_t)2) //!< Number of bytes in the command packet CRC +#define ATCA_PACKET_OVERHEAD (ATCA_COUNT_SIZE + ATCA_CRC_SIZE) //!< Number of bytes in the command packet + +#define ATCA_PUB_KEY_SIZE (64) //!< size of a p256 public key +#define ATCA_PRIV_KEY_SIZE (32) //!< size of a p256 private key +#define ATCA_SIG_SIZE (64) //!< size of a p256 signature +#define ATCA_KEY_SIZE (32) //!< size of a symmetric SHA key +#define RSA2048_KEY_SIZE (256) //!< size of a RSA private key + +#define ATCA_RSP_SIZE_MIN ((uint8_t)4) //!< minimum number of bytes in response +#define ATCA_RSP_SIZE_4 ((uint8_t)7) //!< size of response packet containing 4 bytes data +#define ATCA_RSP_SIZE_72 ((uint8_t)75) //!< size of response packet containing 64 bytes data +#define ATCA_RSP_SIZE_64 ((uint8_t)67) //!< size of response packet containing 64 bytes data +#define ATCA_RSP_SIZE_32 ((uint8_t)35) //!< size of response packet containing 32 bytes data +#define ATCA_RSP_SIZE_MAX ((uint8_t)75) //!< maximum size of response packet (GenKey and Verify command) + +/** \name Definitions for Command Parameter Ranges + @{ */ +#define ATCA_KEY_ID_MAX ((uint8_t)15) //!< maximum value for key id +#define ATCA_OTP_BLOCK_MAX ((uint8_t)1) //!< maximum value for OTP block +/** @} */ + +/** \name Definitions for Indexes Common to All Commands + @{ */ +#define ATCA_COUNT_IDX (0) //!< command packet index for count +#define ATCA_OPCODE_IDX (1) //!< command packet index for op-code +#define ATCA_PARAM1_IDX (2) //!< command packet index for first parameter +#define ATCA_PARAM2_IDX (3) //!< command packet index for second parameter +#define ATCA_DATA_IDX (5) //!< command packet index for data load +#define ATCA_RSP_DATA_IDX (1) //!< buffer index of data in response +/** @} */ + +/** \name Definitions for Zone and Address Parameters + @{ */ +#define ATCA_ZONE_CONFIG ((uint8_t)0x00) //!< Configuration zone +#define ATCA_ZONE_OTP ((uint8_t)0x01) //!< OTP (One Time Programming) zone +#define ATCA_ZONE_DATA ((uint8_t)0x02) //!< Data zone +#define ATCA_ZONE_MASK ((uint8_t)0x03) //!< Zone mask +#define ATCA_ZONE_READWRITE_32 ((uint8_t)0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes. +#define ATCA_ZONE_ACCESS_4 ((uint8_t)4) //!< Read or write 4 bytes. +#define ATCA_ZONE_ACCESS_32 ((uint8_t)32) //!< Read or write 32 bytes. +#define ATCA_ADDRESS_MASK_CONFIG (0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone. +#define ATCA_ADDRESS_MASK_OTP (0x000F) //!< Address bits 4 to 7 are 0 for OTP zone. +#define ATCA_ADDRESS_MASK (0x007F) //!< Address bit 7 to 15 are always 0. +/** @} */ + +/** \name Definitions for ECC Key type + @{ */ +#define ATCA_B283_KEY_TYPE 0 //!< B283 NIST ECC key +#define ATCA_K283_KEY_TYPE 1 //!< K283 NIST ECC key +#define ATCA_P256_KEY_TYPE 4 //!< P256 NIST ECC key +/** @} */ + +/** \name Definitions for the ECDH Command + @{ */ +#define ECDH_PREFIX_MODE ((uint8_t)0x00) +#define ECDH_COUNT (71) +#define ECDH_PUBKEYIN_SIZE (64) +/** @} */ + +/** \name Definitions for the COUNTER Command + @{ */ +#define COUNTER_COUNT ATCA_CMD_SIZE_MIN +#define COUNTER_MODE_IDX ATCA_PARAM1_IDX //!< COUNTER command index for mode +#define COUNTER_KEYID_IDX ATCA_PARAM2_IDX //!< COUNTER command index for key id +#define COUNTER_CHALLENGE_IDX ATCA_DATA_IDX //!< COUNTER command index for optional challenge +#define COUNTER_COUNT_LONG (70) //!< COUNTER command packet size without challenge +#define COUNTER_MODE_MASK ((uint8_t)0x01) //!< COUNTER mode bits 1 to 7 are 0 +typedef enum { + COUNTER_MODE_READ = 0, + COUNTER_MODE_INCREASE = 1 +} enum_counter_mode; +/** @} */ + +/** \name Definitions for the SHA Command + @{ */ +#define SHA_COUNT_SHORT ATCA_CMD_SIZE_MIN +#define SHA_COUNT_LONG (7) +#define ATCA_SHA_DIGEST_SIZE (32) +#define SHA_DATA_MAX (64) +#define SHA_BLOCK_SIZE (64) + +typedef enum { + SHA_MODE_SHA256_START = ((uint8_t) 0x00), //!< Initialization, does not accept a message + SHA_MODE_SHA256_UPDATE = ((uint8_t) 0x01), //!< Add 64 bytes in the meesage to the SHA context + SHA_MODE_SHA256_END = ((uint8_t) 0x02), //!< Complete the calculation and load the digest + SHA_MODE_SHA256_PUBLIC = ((uint8_t) 0x03), //!< Add 64 bytes in the slot to the SHA context + SHA_MODE_HMAC_START = ((uint8_t) 0x04), //!< Initialization + SHA_MODE_HMAC_UPDATE = ((uint8_t) 0x05), //!< + SHA_MODE_HMAC_END = ((uint8_t) 0x04) //!< +} enum_sha_mode; +#define SHA_SHA256_START_MASK ((uint8_t)0x00) //!< Initialization, does not accept a message +#define SHA_SHA256_UPDATE_MASK ((uint8_t)0x01) //!< Add 64 bytes in the meesage to the SHA context +#define SHA_SHA256_END_MASK ((uint8_t)0x02) //!< Complete the calculation and load the digest +#define SHA_SHA256_PUBLIC_MASK ((uint8_t)0x03) //!< Add 64 bytes in the slot to the SHA context +#define SHA_HMAC_START_MASK ((uint8_t)0x04) //!< Initialization +#define SHA_HMAC_END_MASK ((uint8_t)0x05) //!< Complete the HMAC/SHA256 computation +/** @} */ + + +/** \name Definitions for the CheckMac Command + @{ */ +#define CHECKMAC_MODE_IDX ATCA_PARAM1_IDX //!< CheckMAC command index for mode +#define CHECKMAC_KEYID_IDX ATCA_PARAM2_IDX //!< CheckMAC command index for key identifier +#define CHECKMAC_CLIENT_CHALLENGE_IDX ATCA_DATA_IDX //!< CheckMAC command index for client challenge +#define CHECKMAC_CLIENT_RESPONSE_IDX (37) //!< CheckMAC command index for client response +#define CHECKMAC_DATA_IDX (69) //!< CheckMAC command index for other data +#define CHECKMAC_COUNT (84) //!< CheckMAC command packet size +#define CHECKMAC_MODE_CHALLENGE ((uint8_t)0x00) //!< CheckMAC mode 0: first SHA block from key id +#define CHECKMAC_MODE_BLOCK2_TEMPKEY ((uint8_t)0x01) //!< CheckMAC mode bit 0: second SHA block from TempKey +#define CHECKMAC_MODE_BLOCK1_TEMPKEY ((uint8_t)0x02) //!< CheckMAC mode bit 1: first SHA block from TempKey +#define CHECKMAC_MODE_SOURCE_FLAG_MATCH ((uint8_t)0x04) //!< CheckMAC mode bit 2: match TempKey.SourceFlag +#define CHECKMAC_MODE_INCLUDE_OTP_64 ((uint8_t)0x20) //!< CheckMAC mode bit 5: include first 64 OTP bits +#define CHECKMAC_MODE_MASK ((uint8_t)0x27) //!< CheckMAC mode bits 3, 4, 6, and 7 are 0. +#define CHECKMAC_CLIENT_CHALLENGE_SIZE (32) //!< CheckMAC size of client challenge +#define CHECKMAC_CLIENT_RESPONSE_SIZE (32) //!< CheckMAC size of client response +#define CHECKMAC_OTHER_DATA_SIZE (13) //!< CheckMAC size of "other data" +#define CHECKMAC_CLIENT_COMMAND_SIZE (4) //!< CheckMAC size of client command header size inside "other data" +#define CHECKMAC_CMD_MATCH (0) //!< CheckMAC return value when there is a match +#define CHECKMAC_CMD_MISMATCH (1) //!< CheckMAC return value when there is a mismatch +/** @} */ + +/** \name Definitions for the DeriveKey Command + @{ */ +#define DERIVE_KEY_RANDOM_IDX ATCA_PARAM1_IDX //!< DeriveKey command index for random bit +#define DERIVE_KEY_TARGETKEY_IDX ATCA_PARAM2_IDX //!< DeriveKey command index for target slot +#define DERIVE_KEY_MAC_IDX ATCA_DATA_IDX //!< DeriveKey command index for optional MAC +#define DERIVE_KEY_COUNT_SMALL ATCA_CMD_SIZE_MIN //!< DeriveKey command packet size without MAC +#define DERIVE_KEY_COUNT_LARGE (39) //!< DeriveKey command packet size with MAC +#define DERIVE_KEY_RANDOM_FLAG ((uint8_t)4) //!< DeriveKey 1. parameter; has to match TempKey.SourceFlag +#define DERIVE_KEY_MAC_SIZE (32) //!< DeriveKey MAC size +/** @} */ + +/** \name Definitions for the GenDig Command + @{ */ +#define GENDIG_ZONE_IDX ATCA_PARAM1_IDX //!< GenDig command index for zone +#define GENDIG_KEYID_IDX ATCA_PARAM2_IDX //!< GenDig command index for key id +#define GENDIG_DATA_IDX ATCA_DATA_IDX //!< GenDig command index for optional data +#define GENDIG_COUNT ATCA_CMD_SIZE_MIN //!< GenDig command packet size without "other data" +#define GENDIG_COUNT_DATA (11) //!< GenDig command packet size with "other data" +#define GENDIG_OTHER_DATA_SIZE (32) //!< GenDig size of "other data". Is 4 bytes for SHA204, can be either 4 or 32 for ECC +#define GENDIG_ZONE_CONFIG ((uint8_t)0) //!< GenDig zone id config +#define GENDIG_ZONE_OTP ((uint8_t)1) //!< GenDig zone id OTP +#define GENDIG_ZONE_DATA ((uint8_t)2) //!< GenDig zone id data +/** @} */ + +/** \name Definitions for the GenKey Command + @{ */ +#define GENKEY_MODE_IDX ATCA_PARAM1_IDX //!< GenKey command index for mode +#define GENKEY_KEYID_IDX ATCA_PARAM2_IDX //!< GenKey command index for key id +#define GENKEY_DATA_IDX (5) //!< GenKey command index for other data +#define GENKEY_COUNT ATCA_CMD_SIZE_MIN //!< GenKey command packet size without "other data" +#define GENKEY_COUNT_DATA (10) //!< GenKey command packet size with "other data" +#define GENKEY_OTHER_DATA_SIZE (3) //!< GenKey size of "other data" +#define GENKEY_MODE_MASK ((uint8_t)0x1C) //!< GenKey mode bits 0 to 1 and 5 to 7 are 0 +#define GENKEY_MODE_PRIVATE ((uint8_t)0x04) //!< GenKey mode: private key generation +#define GENKEY_MODE_PUBLIC ((uint8_t)0x00) //!< GenKey mode: public key calculation +#define GENKEY_MODE_DIGEST ((uint8_t)0x10) //!< GenKey mode: digest calculation +#define GENKEY_MODE_ADD_DIGEST ((uint8_t)0x08) //!< GenKey mode: additional digest calculation +typedef enum { + GENKEY_MODE_PRIVATE_KEY_GENERATE = ((uint8_t) 0x04), //!< Private Key Creation + GENKEY_MODE_PUBLIC_KEY_DIGEST = ((uint8_t) 0x08), //!< Public Key Computation + GENKEY_MODE_DIGEST_IN_TEMPKEY = ((uint8_t) 0x10) //!< Digest Calculation +} enum_genkey_mode; +/** @} */ +/** \name Definitions for the GENKEY Command + @{ */ +/** @} */ + + +/** \name Definitions for the HMAC Command + @{ */ +#define HMAC_MODE_IDX ATCA_PARAM1_IDX //!< HMAC command index for mode +#define HMAC_KEYID_IDX ATCA_PARAM2_IDX //!< HMAC command index for key id +#define HMAC_COUNT ATCA_CMD_SIZE_MIN //!< HMAC command packet size +#define HMAC_MODE_SOURCE_FLAG_MATCH ((uint8_t)0x04) //!< HMAC mode bit 2: match TempKey.SourceFlag +#define HMAC_MODE_MASK ((uint8_t)0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0. +/** @} */ + +/** \name Definitions for the Info Command + @{ */ +#define INFO_PARAM1_IDX ATCA_PARAM1_IDX //!< Info command index for 1. parameter +#define INFO_PARAM2_IDX ATCA_PARAM2_IDX //!< Info command index for 2. parameter +#define INFO_COUNT ATCA_CMD_SIZE_MIN //!< Info command packet size +#define INFO_MODE_REVISION ((uint8_t)0x00) //!< Info mode Revision +#define INFO_MODE_KEY_VALID ((uint8_t)0x01) //!< Info mode KeyValid +#define INFO_MODE_STATE ((uint8_t)0x02) //!< Info mode State +#define INFO_MODE_GPIO ((uint8_t)0x03) //!< Info mode GPIO +#define INFO_MODE_MAX ((uint8_t)0x03) //!< Info mode maximum value +#define INFO_NO_STATE ((uint8_t)0x00) //!< Info mode is not the state mode. +#define INFO_OUTPUT_STATE_MASK ((uint8_t)0x01) //!< Info output state mask +#define INFO_DRIVER_STATE_MASK ((uint8_t)0x02) //!< Info driver state mask +#define INFO_PARAM2_MAX ((uint8_t)0x03) //!< Info param2 (state) maximum value +#define INFO_SIZE ((uint8_t)0x04) //!< Info param2 (state) maximum value +/** @} */ + +/** \name Definitions for the Lock Command + @{ */ +#define LOCK_ZONE_IDX ATCA_PARAM1_IDX //!< Lock command index for zone +#define LOCK_SUMMARY_IDX ATCA_PARAM2_IDX //!< Lock command index for summary +#define LOCK_COUNT ATCA_CMD_SIZE_MIN //!< Lock command packet size +#define LOCK_ZONE_CONFIG ((uint8_t)0x00) //!< Lock zone is Config +#define LOCK_ZONE_DATA ((uint8_t)0x01) //!< Lock zone is OTP or Data +#define LOCK_ZONE_DATA_SLOT ((uint8_t)0x02) //!< Lock slot of Data +#define LOCK_ZONE_NO_CRC ((uint8_t)0x80) //!< Lock command: Ignore summary. +#define LOCK_ZONE_MASK (0xBF) //!< Lock parameter 1 bits 6 are 0. +/** @} */ + +/** \name Definitions for the MAC Command + @{ */ +#define MAC_MODE_IDX ATCA_PARAM1_IDX //!< MAC command index for mode +#define MAC_KEYID_IDX ATCA_PARAM2_IDX //!< MAC command index for key id +#define MAC_CHALLENGE_IDX ATCA_DATA_IDX //!< MAC command index for optional challenge +#define MAC_COUNT_SHORT ATCA_CMD_SIZE_MIN //!< MAC command packet size without challenge +#define MAC_COUNT_LONG (39) //!< MAC command packet size with challenge +#define MAC_MODE_CHALLENGE ((uint8_t)0x00) //!< MAC mode 0: first SHA block from data slot +#define MAC_MODE_BLOCK2_TEMPKEY ((uint8_t)0x01) //!< MAC mode bit 0: second SHA block from TempKey +#define MAC_MODE_BLOCK1_TEMPKEY ((uint8_t)0x02) //!< MAC mode bit 1: first SHA block from TempKey +#define MAC_MODE_SOURCE_FLAG_MATCH ((uint8_t)0x04) //!< MAC mode bit 2: match TempKey.SourceFlag +#define MAC_MODE_PTNONCE_TEMPKEY ((uint8_t)0x06) //!< MAC mode bit 0: second SHA block from TempKey +#define MAC_MODE_PASSTHROUGH ((uint8_t)0x07) //!< MAC mode bit 0-2: pass-through mode +#define MAC_MODE_INCLUDE_OTP_88 ((uint8_t)0x10) //!< MAC mode bit 4: include first 88 OTP bits +#define MAC_MODE_INCLUDE_OTP_64 ((uint8_t)0x20) //!< MAC mode bit 5: include first 64 OTP bits +#define MAC_MODE_INCLUDE_SN ((uint8_t)0x40) //!< MAC mode bit 6: include serial number +#define MAC_CHALLENGE_SIZE (32) //!< MAC size of challenge +#define MAC_SIZE (32) //!< MAC size of response +#define MAC_MODE_MASK ((uint8_t)0x77) //!< MAC mode bits 3 and 7 are 0. +/** @} */ + +/** \name Definitions for the Nonce Command + @{ */ +#define NONCE_MODE_IDX ATCA_PARAM1_IDX //!< Nonce command index for mode +#define NONCE_PARAM2_IDX ATCA_PARAM2_IDX //!< Nonce command index for 2. parameter +#define NONCE_INPUT_IDX ATCA_DATA_IDX //!< Nonce command index for input data +#define NONCE_COUNT_SHORT (27) //!< Nonce command packet size for 20 bytes of data +#define NONCE_COUNT_LONG (39) //!< Nonce command packet size for 32 bytes of data +#define NONCE_MODE_MASK ((uint8_t)0x03) //!< Nonce mode bits 2 to 7 are 0. +#define NONCE_MODE_SEED_UPDATE ((uint8_t)0x00) //!< Nonce mode: update seed +#define NONCE_MODE_NO_SEED_UPDATE ((uint8_t)0x01) //!< Nonce mode: do not update seed +#define NONCE_MODE_INVALID ((uint8_t)0x02) //!< Nonce mode 2 is invalid. +#define NONCE_MODE_PASSTHROUGH ((uint8_t)0x03) //!< Nonce mode: pass-through +#define NONCE_MODE_RANDOM_OUT ((uint16_t)0x0000) //!< Nonce mode: output RandOut or single byte of zero +#define NONCE_MODE_TEMPKEY_OUT ((uint16_t)0x0080) //!< Nonce mode: output RandOut or single byte of zero +#define NONCE_NUMIN_SIZE (20) //!< Nonce data length +#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce data length in pass-through mode (mode = 3) +/** @} */ + +/** \name Definitions for the Pause Command + @{ */ +#define PAUSE_SELECT_IDX ATCA_PARAM1_IDX //!< Pause command index for Selector +#define PAUSE_PARAM2_IDX ATCA_PARAM2_IDX //!< Pause command index for 2. parameter +#define PAUSE_COUNT ATCA_CMD_SIZE_MIN //!< Pause command packet size +/** @} */ + +/** \name Definitions for the PrivWrite Command + @{ */ +#define PRIVWRITE_ZONE_IDX ATCA_PARAM1_IDX //!< PrivWrite command index for zone +#define PRIVWRITE_KEYID_IDX ATCA_PARAM2_IDX //!< PrivWrite command index for KeyID +#define PRIVWRITE_VALUE_IDX ( 5) //!< PrivWrite command index for value +#define PRIVWRITE_MAC_IDX (41) //!< PrivWrite command index for MAC +#define PRIVWRITE_COUNT (75) //!< PrivWrite command packet size +#define PRIVWRITE_ZONE_MASK ((uint8_t)0x40) //!< PrivWrite zone bits 0 to 5 and 7 are 0. +#define PRIVWRITE_MODE_ENCRYPT ((uint8_t)0x40) //!< PrivWrite mode: encrypted +/** @} */ + +/** \name Definitions for the Random Command + @{ */ +#define RANDOM_MODE_IDX ATCA_PARAM1_IDX //!< Random command index for mode +#define RANDOM_PARAM2_IDX ATCA_PARAM2_IDX //!< Random command index for 2. parameter +#define RANDOM_COUNT ATCA_CMD_SIZE_MIN //!< Random command packet size +#define RANDOM_SEED_UPDATE ((uint8_t)0x00) //!< Random mode for automatic seed update +#define RANDOM_NO_SEED_UPDATE ((uint8_t)0x01) //!< Random mode for no seed update +#define RANDOM_NUM_SIZE ((uint8_t)0x20) //!< Number of bytes in the data packet of a random command +/** @} */ + +/** \name Definitions for the Read Command + @{ */ +#define READ_ZONE_IDX ATCA_PARAM1_IDX //!< Read command index for zone +#define READ_ADDR_IDX ATCA_PARAM2_IDX //!< Read command index for address +#define READ_COUNT ATCA_CMD_SIZE_MIN //!< Read command packet size +#define READ_ZONE_MASK ((uint8_t)0x83) //!< Read zone bits 2 to 6 are 0. +/** @} */ + +/** \name Definitions for the Sign Command + @{ */ +#define SIGN_MODE_IDX ATCA_PARAM1_IDX //!< Sign command index for mode +#define SIGN_KEYID_IDX ATCA_PARAM2_IDX //!< Sign command index for key id +#define SIGN_COUNT ATCA_CMD_SIZE_MIN //!< Sign command packet size +#define SIGN_MODE_MASK ((uint8_t)0xC0) //!< Sign mode bits 0 to 5 are 0 +#define SIGN_MODE_INTERNAL ((uint8_t)0x00) //!< Sign mode 0: internal +#define SIGN_MODE_INCLUDE_SN ((uint8_t)0x40) //!< Sign mode bit 6: include serial number +#define SIGN_MODE_EXTERNAL ((uint8_t)0x80) //!< Sign mode bit 7: external +/** @} */ + +/** \name Definitions for the UpdateExtra Command + @{ */ +#define UPDATE_MODE_IDX ATCA_PARAM1_IDX //!< UpdateExtra command index for mode +#define UPDATE_VALUE_IDX ATCA_PARAM2_IDX //!< UpdateExtra command index for new value +#define UPDATE_COUNT ATCA_CMD_SIZE_MIN //!< UpdateExtra command packet size +#define UPDATE_CONFIG_BYTE_85 ((uint8_t)0x01) //!< UpdateExtra mode: update Config byte 85 +/** @} */ + +/** \name Definitions for the Verify Command + @{ */ +#define VERIFY_MODE_IDX ATCA_PARAM1_IDX //!< Verify command index for mode +#define VERIFY_KEYID_IDX ATCA_PARAM2_IDX //!< Verify command index for key id +#define VERIFY_DATA_IDX ( 5) //!< Verify command index for data +#define VERIFY_256_STORED_COUNT ( 71) //!< Verify command packet size for 256-bit key in stored mode +#define VERIFY_283_STORED_COUNT ( 79) //!< Verify command packet size for 283-bit key in stored mode +#define VERIFY_256_VALIDATE_COUNT ( 90) //!< Verify command packet size for 256-bit key in validate mode +#define VERIFY_283_VALIDATE_COUNT ( 98) //!< Verify command packet size for 283-bit key in validate mode +#define VERIFY_256_EXTERNAL_COUNT (135) //!< Verify command packet size for 256-bit key in external mode +#define VERIFY_283_EXTERNAL_COUNT (151) //!< Verify command packet size for 283-bit key in external mode +#define VERIFY_256_KEY_SIZE ( 64) //!< Verify key size for 256-bit key +#define VERIFY_283_KEY_SIZE ( 72) //!< Verify key size for 283-bit key +#define VERIFY_256_SIGNATURE_SIZE ( 64) //!< Verify signature size for 256-bit key +#define VERIFY_283_SIGNATURE_SIZE ( 72) //!< Verify signature size for 283-bit key +#define VERIFY_OTHER_DATA_SIZE ( 19) //!< Verify size of "other data" +#define VERIFY_MODE_MASK ((uint8_t)0x03) //!< Verify mode bits 2 to 7 are 0 +#define VERIFY_MODE_STORED ((uint8_t)0x00) //!< Verify mode: stored +#define VERIFY_MODE_VALIDATEEXTERNAL ((uint8_t)0x01) //!< Verify mode: validate external +#define VERIFY_MODE_EXTERNAL ((uint8_t)0x02) //!< Verify mode: external +#define VERIFY_MODE_VALIDATE ((uint8_t)0x03) //!< Verify mode: validate +#define VERIFY_MODE_INVALIDATE ((uint8_t)0x07) //!< Verify mode: invalidate +#define VERIFY_KEY_B283 ((uint16_t)0x0000) //!< Verify key type: B283 +#define VERIFY_KEY_K283 ((uint16_t)0x0001) //!< Verify key type: K283 +#define VERIFY_KEY_P256 ((uint16_t)0x0004) //!< Verify key type: P256 +/** @} */ + +/** \name Definitions for the Write Command + @{ */ +#define WRITE_ZONE_IDX ATCA_PARAM1_IDX //!< Write command index for zone +#define WRITE_ADDR_IDX ATCA_PARAM2_IDX //!< Write command index for address +#define WRITE_VALUE_IDX ATCA_DATA_IDX //!< Write command index for data +#define WRITE_MAC_VS_IDX ( 9) //!< Write command index for MAC following short data +#define WRITE_MAC_VL_IDX (37) //!< Write command index for MAC following long data +#define WRITE_COUNT_SHORT (11) //!< Write command packet size with short data and no MAC +#define WRITE_COUNT_LONG (39) //!< Write command packet size with long data and no MAC +#define WRITE_COUNT_SHORT_MAC (43) //!< Write command packet size with short data and MAC +#define WRITE_COUNT_LONG_MAC (71) //!< Write command packet size with long data and MAC +#define WRITE_MAC_SIZE (32) //!< Write MAC size +#define WRITE_ZONE_MASK ((uint8_t)0xC3) //!< Write zone bits 2 to 5 are 0. +#define WRITE_ZONE_WITH_MAC ((uint8_t)0x40) //!< Write zone bit 6: write encrypted with MAC +#define WRITE_ZONE_OTP ((uint8_t)1) //!< WRITE zone id OTP +#define WRITE_ZONE_DATA ((uint8_t)2) //!< WRITE zone id data +/** @} */ + +/** \name Response Size Definitions + @{ */ +#define CHECKMAC_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of DeriveKey command +#define DERIVE_KEY_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of DeriveKey command +#define GENDIG_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of GenDig command +#define GENKEY_RSP_SIZE_SHORT ATCA_RSP_SIZE_MIN //!< response size of GenKey command in Digest mode +#define GENKEY_RSP_SIZE_LONG ATCA_RSP_SIZE_72 //!< response size of GenKey command when generating key +#define HMAC_RSP_SIZE ATCA_RSP_SIZE_32 //!< response size of HMAC command +#define INFO_RSP_SIZE ATCA_RSP_SIZE_VAL //!< response size of Info command returns 4 bytes +#define LOCK_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of Lock command +#define MAC_RSP_SIZE ATCA_RSP_SIZE_32 //!< response size of MAC command +#define NONCE_RSP_SIZE_SHORT ATCA_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3 +#define NONCE_RSP_SIZE_LONG ATCA_RSP_SIZE_32 //!< response size of Nonce command +#define PAUSE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of Pause command +#define PRIVWRITE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of PrivWrite command +#define RANDOM_RSP_SIZE ATCA_RSP_SIZE_32 //!< response size of Random command +#define READ_4_RSP_SIZE ATCA_RSP_SIZE_VAL //!< response size of Read command when reading 4 bytes +#define READ_32_RSP_SIZE ATCA_RSP_SIZE_32 //!< response size of Read command when reading 32 bytes +#define SIGN_RSP_SIZE ATCA_RSP_SIZE_MAX //!< response size of Sign command +#define SHA_RSP_SIZE ATCA_RSP_SIZE_32 //!< response size of SHA command +#define UPDATE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of UpdateExtra command +#define VERIFY_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of UpdateExtra command +#define WRITE_RSP_SIZE ATCA_RSP_SIZE_MIN //!< response size of Write command + +#define ECDH_KEY_SIZE ATCA_BLOCK_SIZE //!< response size of ECDH command +#define ECDH_RSP_SIZE ATCA_RSP_SIZE_32 //!< response size of ECDH command +#define COUNTER_RSP_SIZE ATCA_RSP_SIZE_4 //!< response size of COUNTER command +#define SHA_RSP_SIZE_SHORT ATCA_RSP_SIZE_MIN //!< response size of SHA command +#define SHA_RSP_SIZE_LONG ATCA_RSP_SIZE_32 //!< response size of SHA command +/** @} */ +#ifdef __cplusplus +} +#endif +#endif + diff --git a/src/atca_compiler.h b/src/atca_compiler.h new file mode 100644 index 0000000..857c377 --- /dev/null +++ b/src/atca_compiler.h @@ -0,0 +1,73 @@ +/** + * \file + * \brief ATCA is meant to be portable across architectures, even non-Atmel architectures and compiler environments. + * This file is for isolating compiler specific macros. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#ifndef ATCA_COMPILER_H_ +#define ATCA_COMPILER_H_ + +#if defined(__clang__) +/* Clang/LLVM. ---------------------------------------------- */ + +#elif defined(__ICC) || defined(__INTEL_COMPILER) +/* Intel ICC/ICPC. ------------------------------------------ */ + +#elif defined(__GNUC__) || defined(__GNUG__) +/* GNU GCC/G++. --------------------------------------------- */ + +#elif defined(__HP_cc) || defined(__HP_aCC) +/* Hewlett-Packard C/aC++. ---------------------------------- */ + +#elif defined(__IBMC__) || defined(__IBMCPP__) +/* IBM XL C/C++. -------------------------------------------- */ + +#elif defined(_MSC_VER) +/* Microsoft Visual Studio. --------------------------------- */ + +#elif defined(__PGI) +/* Portland Group PGCC/PGCPP. ------------------------------- */ + +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +/* Oracle Solaris Studio. ----------------------------------- */ + +#endif + +#endif /* ATCA_COMPILER_H_ */ \ No newline at end of file diff --git a/src/atca_device.c b/src/atca_device.c new file mode 100644 index 0000000..642893d --- /dev/null +++ b/src/atca_device.c @@ -0,0 +1,119 @@ +/** + * \file + * \brief Atmel CryptoAuth device object + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include +#include "atca_device.h" + +/** \defgroup device ATCADevice (atca_) + * \brief ATCADevice object - composite of command and interface objects + @{ */ + +/** \brief atca_device is the C object backing ATCADevice. See the atca_device.h file for + * details on the ATCADevice methods + */ + +struct atca_device { + ATCACommand mCommands; // has-a command set to support a given CryptoAuth device + ATCAIface mIface; // has-a physical interface +}; + +/** \brief constructor for an Atmel CryptoAuth device + * \param[in] cfg pointer to an interface configuration object + * \return reference to a new ATCADevice + */ + +ATCADevice newATCADevice(ATCAIfaceCfg *cfg ) +{ + ATCADevice cadev = NULL; + + if (cfg == NULL) + return NULL; + + cadev = (ATCADevice)malloc(sizeof(struct atca_device)); + cadev->mCommands = (ATCACommand)newATCACommand(cfg->devtype); + cadev->mIface = (ATCAIface)newATCAIface(cfg); + + if (cadev->mCommands == NULL || cadev->mIface == NULL) { + free(cadev); + cadev = NULL; + } + + return cadev; +} + +/** \brief returns a reference to the ATCACommand object for the device + * \param[in] dev reference to a device + * \return reference to the ATCACommand object for the device + */ +ATCACommand atGetCommands( ATCADevice dev ) +{ + return dev->mCommands; +} + +/** \brief returns a reference to the ATCAIface interface object for the device + * \param[in] dev reference to a device + * \return reference to the ATCAIface object for the device + */ + +ATCAIface atGetIFace( ATCADevice dev ) +{ + return dev->mIface; +} + +/** \brief destructor for a device NULLs reference after object is freed + * \param[in] cadev pointer to a reference to a device + * + */ + +void deleteATCADevice( ATCADevice *cadev ) // destructor +{ + struct atca_device *dev = *cadev; + + if ( *cadev ) { + deleteATCACommand( (ATCACommand*)&(dev->mCommands)); + deleteATCAIface((ATCAIface*)&(dev->mIface)); + free((void*)*cadev); + } + + *cadev = NULL; +} + +/** @} */ diff --git a/src/atca_device.h b/src/atca_device.h new file mode 100644 index 0000000..8a3b20a --- /dev/null +++ b/src/atca_device.h @@ -0,0 +1,69 @@ +/** + * \file + * + * \brief Atmel Crypto Auth device object + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_DEVICE_H +#define ATCA_DEVICE_H + +#include "atca_command.h" +#include "atca_iface.h" +/** \defgroup device ATCADevice (atca_) + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct atca_device * ATCADevice; +ATCADevice newATCADevice(ATCAIfaceCfg *cfg ); // constructor + +/* member functions here */ +ATCACommand atGetCommands( ATCADevice dev ); +ATCAIface atGetIFace( ATCADevice dev ); + +void deleteATCADevice( ATCADevice *dev ); // destructor +/*---- end of OATCADevice ----*/ + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif diff --git a/src/atca_devtypes.h b/src/atca_devtypes.h new file mode 100644 index 0000000..3eb1d67 --- /dev/null +++ b/src/atca_devtypes.h @@ -0,0 +1,64 @@ +/** + * \file + * \brief Atmel Crypto Auth + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#ifndef ATCA_DEVTYPES_H_ +#define ATCA_DEVTYPES_H_ + +/** \defgroup device ATCADevice (atca_) + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + ATSHA204A, + ATECC108A, + ATECC508A, + ATCA_DEV_UNKNOWN = 0x20 +} ATCADeviceType; + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* ATCA_DEVTYPES_H_ */ \ No newline at end of file diff --git a/src/atca_iface.c b/src/atca_iface.c new file mode 100644 index 0000000..37f4f84 --- /dev/null +++ b/src/atca_iface.c @@ -0,0 +1,178 @@ +/** + * \file + * + * \brief Atmel Crypto Auth hardware interface object + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include +#include "atca_iface.h" +#include "hal/atca_hal.h" + +/** \defgroup interface ATCAIface (atca_) + * \brief Abstract interface to all CryptoAuth device types. This interface + * connects to the HAL implementation and abstracts the physical details of the + * device communication from all the upper layers of CryptoAuthLib + @{ */ + +/** \brief atca_iface is the C object backing ATCAIface. See the atca_iface.h file for + * details on the ATCAIface methods + */ + +struct atca_iface { + ATCAIfaceType mType; + ATCAIfaceCfg *mIfaceCFG; // points to previous defined/given Cfg object, caller manages this + + ATCA_STATUS (*atinit)(void *hal, ATCAIfaceCfg *); + ATCA_STATUS (*atpostinit)(ATCAIface hal); + ATCA_STATUS (*atsend)(ATCAIface hal, uint8_t *txdata, int txlength); + ATCA_STATUS (*atreceive)( ATCAIface hal, uint8_t *rxdata, uint16_t *rxlength); + ATCA_STATUS (*atwake)(ATCAIface hal); + ATCA_STATUS (*atidle)(ATCAIface hal); + ATCA_STATUS (*atsleep)(ATCAIface hal); + + // treat as private + void *hal_data; // generic pointer used by HAL to point to architecture specific structure + // no ATCA object should touch this except HAL, HAL manages this pointer and memory it points to +}; + +ATCA_STATUS _atinit(ATCAIface caiface, ATCAHAL_t *hal); + +/** \brief constructor for ATCAIface objects + * \param[in] cfg points to the logical configuration for the interface + * \return ATCAIface + */ + +ATCAIface newATCAIface(ATCAIfaceCfg *cfg) // constructor +{ + ATCAIface caiface = (ATCAIface)malloc(sizeof(struct atca_iface)); + + caiface->mType = cfg->iface_type; + caiface->mIfaceCFG = cfg; + + if (atinit(caiface) != ATCA_SUCCESS) { + free(caiface); + caiface = NULL; + } + + return caiface; +} + +// public ATCAIface methods + +ATCA_STATUS atinit(ATCAIface caiface) +{ + ATCA_STATUS status = ATCA_COMM_FAIL; + ATCAHAL_t hal; + + _atinit( caiface, &hal ); + + status = caiface->atinit( &hal, caiface->mIfaceCFG ); + if (status == ATCA_SUCCESS) { + caiface->hal_data = hal.hal_data; + + // Perform the post init + status = caiface->atpostinit( caiface ); + } + + return status; +} + +ATCA_STATUS atsend(ATCAIface caiface, uint8_t *txdata, int txlength) +{ + return caiface->atsend(caiface, txdata, txlength); +} + +ATCA_STATUS atreceive( ATCAIface caiface, uint8_t *rxdata, uint16_t *rxlength) +{ + return caiface->atreceive(caiface, rxdata, rxlength); +} + +ATCA_STATUS atwake(ATCAIface caiface) +{ + return caiface->atwake(caiface); +} + +ATCA_STATUS atidle(ATCAIface caiface) +{ + atca_delay_ms(1); + return caiface->atidle(caiface); +} + +ATCA_STATUS atsleep(ATCAIface caiface) +{ + atca_delay_ms(1); + return caiface->atsleep(caiface); +} + +ATCAIfaceCfg * atgetifacecfg(ATCAIface caiface) +{ + return caiface->mIfaceCFG; +} + +void* atgetifacehaldat(ATCAIface caiface) +{ + return caiface->hal_data; +} + +void deleteATCAIface(ATCAIface *caiface) // destructor +{ + if ( *caiface ) { + hal_iface_release( (*caiface)->mType, (*caiface)->hal_data); // let HAL clean up and disable physical level interface if ref count is 0 + free((void*)*caiface); + } + + *caiface = NULL; +} + +ATCA_STATUS _atinit(ATCAIface caiface, ATCAHAL_t *hal) +{ + // get method mapping to HAL methods for this interface + hal_iface_init( caiface->mIfaceCFG, hal ); + caiface->atinit = hal->halinit; + caiface->atpostinit = hal->halpostinit; + caiface->atsend = hal->halsend; + caiface->atreceive = hal->halreceive; + caiface->atwake = hal->halwake; + caiface->atsleep = hal->halsleep; + caiface->atidle = hal->halidle; + caiface->hal_data = hal->hal_data; + + return ATCA_SUCCESS; +} +/** @} */ diff --git a/src/atca_iface.h b/src/atca_iface.h new file mode 100644 index 0000000..6d4e050 --- /dev/null +++ b/src/atca_iface.h @@ -0,0 +1,141 @@ +/** + * \file + * + * \brief Atmel Crypto Auth hardware interface object + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_IFACE_H +#define ATCA_IFACE_H + +/** \defgroup interface ATCAIface (atca_) + * \brief Abstract interface to all CryptoAuth device types. This interface + * connects to the HAL implementation and abstracts the physical details of the + * device communication from all the upper layers of CryptoAuthLib + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "atca_command.h" + +typedef enum { + ATCA_I2C_IFACE, + ATCA_SWI_IFACE, + ATCA_UART_IFACE, + ATCA_SPI_IFACE, + ATCA_HID_IFACE + // additional physical interface types here +} ATCAIfaceType; + +/* ATCAIfaceCfg is a mediator object between a completely abstract notion of a physical interface and an actual physical interface. + + The main purpose of it is to keep hardware specifics from bleeding into the higher levels - hardware specifics could include + things like framework specific items (ASF SERCOM) vs a non-Atmel I2C library constant that defines an I2C port. But I2C has + roughly the same parameters regardless of architecture and framework. I2C + */ + +struct ATCAI2C { + uint8_t slave_address; // 8-bit slave address + uint8_t bus; // logical i2c bus number, 0-based - HAL will map this to a pin pair for SDA SCL + uint32_t baud; // typically 400000 +}; + +struct ATCASWI { + uint8_t bus; // logical SWI bus - HAL will map this to a pin or uart port +}; + +struct ATCAUART { + int port; // logic port number + uint32_t baud; // typically 115200 + uint8_t wordsize; // usually 8 + uint8_t parity; // 0 == even, 1 == odd, 2 == none + uint8_t stopbits; // 0,1,2 +}; + +struct ATCAHID { + int idx; // HID enumeration index + uint32_t vid; // Vendor ID of kit (0x03EB for CK101) + uint32_t pid; // Product ID of kit (0x2312 for CK101) + uint32_t packetsize; // Size of the USB packet + uint8_t guid[16]; // The GUID for this HID device +}; + +typedef struct { + ATCAIfaceType iface_type; // active iface - how to interpret the union below + ATCADeviceType devtype; // explicit device type + + union { // each instance of an iface cfg defines a single type of interface + struct ATCAI2C atcai2c; + struct ATCASWI atcaswi; + struct ATCAUART atcauart; + struct ATCAHID atcahid; + }; + + uint16_t wake_delay; // microseconds of tWHI + tWLO which varies based on chip type + int rx_retries; // the number of retries to attempt for receiving bytes + void *cfg_data; // opaque data used by HAL in device discovery +} ATCAIfaceCfg; + +typedef struct atca_iface * ATCAIface; +ATCAIface newATCAIface(ATCAIfaceCfg *cfg); // constructor +// IFace methods +ATCA_STATUS atinit(ATCAIface caiface); +ATCA_STATUS atpostinit(ATCAIface caiface); +ATCA_STATUS atsend(ATCAIface caiface, uint8_t *txdata, int txlength); +ATCA_STATUS atreceive(ATCAIface caiface, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS atwake(ATCAIface caiface); +ATCA_STATUS atidle(ATCAIface caiface); +ATCA_STATUS atsleep(ATCAIface caiface); + +// accessors +ATCAIfaceCfg * atgetifacecfg(ATCAIface caiface); +void* atgetifacehaldat(ATCAIface caiface); + +void deleteATCAIface( ATCAIface *dev ); // destructor +/*---- end of OATCAIface ----*/ + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif + + + diff --git a/src/atca_status.h b/src/atca_status.h new file mode 100644 index 0000000..fdc27d1 --- /dev/null +++ b/src/atca_status.h @@ -0,0 +1,92 @@ +/** + * \file + * + * \brief Atmel Crypto Auth status codes + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef _ATCA_STATUS_H +#define _ATCA_STATUS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* all status codes for the ATCA lib are defined here */ + +typedef enum { + ATCA_SUCCESS = 0x00, //!< Function succeeded. + ATCA_CONFIG_ZONE_LOCKED = 0x01, + ATCA_DATA_ZONE_LOCKED = 0x02, + ATCA_WAKE_FAILED = 0xD0, //!< response status byte indicates CheckMac failure (status byte = 0x01) + ATCA_CHECKMAC_VERIFY_FAILED = 0xD1, //!< response status byte indicates CheckMac failure (status byte = 0x01) + ATCA_PARSE_ERROR = 0xD2, //!< response status byte indicates parsing error (status byte = 0x03) + ATCA_STATUS_CRC = 0xD4, //!< response status byte indicates CRC error (status byte = 0xFF) + ATCA_STATUS_UNKNOWN = 0xD5, //!< response status byte is unknown + ATCA_STATUS_ECC = 0xD6, //!< response status byte is ECC fault (status byte = 0x05) + ATCA_FUNC_FAIL = 0xE0, //!< Function could not execute due to incorrect condition / state. + ATCA_GEN_FAIL = 0xE1, //!< unspecified error + ATCA_BAD_PARAM = 0xE2, //!< bad argument (out of range, null pointer, etc.) + ATCA_INVALID_ID = 0xE3, //!< invalid device id, id not set + ATCA_INVALID_SIZE = 0xE4, //!< Count value is out of range or greater than buffer size. + ATCA_BAD_CRC = 0xE5, //!< incorrect CRC received + ATCA_RX_FAIL = 0xE6, //!< Timed out while waiting for response. Number of bytes received is > 0. + ATCA_RX_NO_RESPONSE = 0xE7, //!< Not an error while the Command layer is polling for a command response. + ATCA_RESYNC_WITH_WAKEUP = 0xE8, //!< Re-synchronization succeeded, but only after generating a Wake-up + ATCA_PARITY_ERROR = 0xE9, //!< for protocols needing parity + ATCA_TX_TIMEOUT = 0xEA, //!< for Atmel PHY protocol, timeout on transmission waiting for master + ATCA_RX_TIMEOUT = 0xEB, //!< for Atmel PHY protocol, timeout on receipt waiting for master + ATCA_COMM_FAIL = 0xF0, //!< Communication with device failed. Same as in hardware dependent modules. + ATCA_TIMEOUT = 0xF1, //!< Timed out while waiting for response. Number of bytes received is 0. + ATCA_BAD_OPCODE = 0xF2, //!< opcode is not supported by the device + ATCA_WAKE_SUCCESS = 0xF3, //!< received proper wake token + ATCA_EXECUTION_ERROR = 0xF4, //!< chip was in a state where it could not execute the command, response status byte indicates command execution error (status byte = 0x0F) + ATCA_UNIMPLEMENTED = 0xF5, //!< Function or some element of it hasn't been implemented yet + ATCA_ASSERT_FAILURE = 0xF6, //!< Code failed run-time consistency check + ATCA_TX_FAIL = 0xF7, //!< Failed to write + ATCA_NOT_LOCKED = 0xF8, //!< required zone was not locked + ATCA_NO_DEVICES = 0xF9, //!< For protocols that support device discovery (kit protocol), no devices were found +} ATCA_STATUS; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/basic/README.md b/src/basic/README.md new file mode 100644 index 0000000..0a182a0 --- /dev/null +++ b/src/basic/README.md @@ -0,0 +1,13 @@ +basic directory - Purpose +========================= +The purpose of this directory is to contain the files implementing the APIs for a basic +interface to the core CryptoAuthLib library. + +High-level functions like these make it very convenient to use the library when standard configurations +and defaults are in play. They are the easiest to use when developing examples or trying to +understand the "flow" of an authentication operation without getting overwhelmed by the details. + +This makes simple jobs easy and if you need more sophistication and power, you can employ +the full power of the CryptoAuthLib object model. + +See the Doxygen documentation in cryptoauthlib/docs for details on the API of the Basic commands. diff --git a/src/basic/atca_basic.c b/src/basic/atca_basic.c new file mode 100644 index 0000000..3283291 --- /dev/null +++ b/src/basic/atca_basic.c @@ -0,0 +1,2911 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods. These methods provide a simpler way to access the core crypto + * methods. Their design center is around the most common modes and functions of each command + * rather than the complete implementation of each possible feature of the chip. If you need a feature + * not supplied in the Basic API, you can achieve the feature through the datasheet level command + * supplied through the ATCADevice and ATCACommand object. + * + * One primary assumption to all atcab_ routines is that the caller manages the wake/sleep/idle bracket + * so prior to calling the atcab_ routine, the chip should be awake; the routine will manage wake/sleep/idle + * within the function and leave the chip awake upon return. + * + * \copyright Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#include "atca_basic.h" +#include "host/atca_host.h" + +char atca_version[] = { "20160108" }; // change for each release, yyyymmdd + +/** \brief returns a version string for the CryptoAuthLib release. + * The format of the version string returned is "yyyymmdd" + * \param[out] verstr ptr to space to receive version string + * \return ATCA_STATUS + */ + +ATCA_STATUS atcab_version( char *verstr ) +{ + strcpy( verstr, atca_version ); + return ATCA_SUCCESS; +} + +/** \brief basic API methods are all prefixed with atcab_ (Atmel CryptoAuth Basic) + * the fundamental premise of the basic API is it is based on a single interface + * instance and that instance is global, so all basic API commands assume that + * one global device is the one to operate on. + */ + +ATCADevice _gDevice = NULL; +ATCACommand _gCommandObj = NULL; +ATCAIface _gIface = NULL; + +/** \brief atcab_init is called once for the life of the application and creates a global ATCADevice object used by Basic API. + * This method builds a global ATCADevice instance behinds the scenes that's used for all Basic API operations + * \param[in] cfg is a pointer to an interface configuration. This is usually a predefined configuration found in atca_cfgs.h + * \return ATCA_STATUS + * \see atcab_init_device() + */ +ATCA_STATUS atcab_init( ATCAIfaceCfg *cfg ) +{ + if ( _gDevice ) // if there's already a device created, release it + atcab_release(); + + _gDevice = newATCADevice( cfg ); + if ( _gDevice == NULL ) + return ATCA_GEN_FAIL; // Device creation failed + + _gCommandObj = atGetCommands( _gDevice ); + _gIface = atGetIFace( _gDevice ); + + if ( _gCommandObj == NULL || _gIface == NULL ) + return ATCA_GEN_FAIL; // More of an assert to make everything was constructed properly + + return ATCA_SUCCESS; +} + + +/** \brief atcab_init_device can be used to initialize the global ATCADevice object to point to one of your choosing + * for use with all the atcab_ basic API. + * \param[in] cadevice ATCADevice instance to use as the global Basic API crypto device instance + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_init_device( ATCADevice cadevice ) +{ + if ( cadevice == NULL ) + return ATCA_BAD_PARAM; + + if ( _gDevice ) // if there's already a device created, release it + atcab_release(); + + _gDevice = cadevice; + _gCommandObj = atGetCommands( _gDevice ); + _gIface = atGetIFace(_gDevice); + + if ( _gCommandObj == NULL || _gIface == NULL ) + return ATCA_GEN_FAIL; + + return ATCA_SUCCESS; +} + +/** \brief release (free) the global ATCADevice instance. + * This must be called in order to release or free up the interface. + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_release( void ) +{ + deleteATCADevice(&_gDevice); + return ATCA_SUCCESS; +} + +/** \brief a way to get the global device object. Generally for more sophisticated users of atca + * \return instance of global ATCADevice + */ + +ATCADevice atcab_getDevice(void) +{ + return _gDevice; +} + + +/** \brief wakeup the CryptoAuth device + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_wakeup(void) +{ + if ( _gDevice == NULL ) + return ATCA_GEN_FAIL; + + return atwake(_gIface); +} + +/** \brief idle the CryptoAuth device + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_idle(void) +{ + if ( _gDevice == NULL ) + return ATCA_GEN_FAIL; + + return atidle(_gIface); +} + +/** \brief invoke sleep on the CryptoAuth device + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_sleep(void) +{ + if ( _gDevice == NULL ) + return ATCA_GEN_FAIL; + + return atsleep(_gIface); +} + + +/** \brief auto discovery of crypto auth devices + * + * Calls interface discovery functions and fills in cfgArray up to the maximum + * number of configurations either found or the size of the array. The cfgArray + * can have a mixture of interface types (ie: some I2C, some SWI or UART) depending upon + * which interfaces you've enabled + * + * \param[out] cfgArray, ptr to an array of interface configs + * \param[in] max, maximum size of cfgArray + * \return ATCA_STATUS + */ + +#define MAX_BUSES 4 + +ATCA_STATUS atcab_cfg_discover( ATCAIfaceCfg cfgArray[], int maxIfaces) +{ + int ifaceNum = 0, i; + int found = 0; + + // this cumulatively gathers all the interfaces enabled by #defines + +#ifdef ATCA_HAL_I2C + hal_i2c_discover_devices(0, cfgArray, &found); +#endif + +#ifdef ATCA_HAL_SWI + int swi_buses[MAX_BUSES]; + memset( swi_buses, -1, sizeof(swi_buses)); + hal_swi_discover_buses(swi_buses, MAX_BUSES); + for ( i = 0; i < MAX_BUSES && ifaceNum < maxIfaces; i++ ) { + if ( swi_buses[i] != -1 ) { + hal_swi_discover_devices( swi_buses[i], &cfgArray[ifaceNum], &found); + ifaceNum += found; + } + } + +#endif + +#ifdef ATCA_HAL_UART + int uart_buses[MAX_BUSES]; + memset( uart_buses, -1, sizeof(uart_buses)); + hal_uart_discover_buses(uart_buses, MAX_BUSES); + for ( i = 0; i < MAX_BUSES && ifaceNum < maxIfaces; i++ ) { + if ( uart_buses[i] != -1 ) { + hal_uart_discover_devices( uart_buses[i], &cfgArray[ifaceNum], &found); + ifaceNum += found; + } + } +#endif + +#ifdef ATCA_HAL_KIT_CDC + int cdc_buses[MAX_BUSES]; + memset( cdc_buses, -1, sizeof(cdc_buses)); + hal_kit_cdc_discover_buses(cdc_buses, MAX_BUSES); + for ( i = 0; i < MAX_BUSES && ifaceNum < maxIfaces; i++ ) { + if ( cdc_buses[i] != -1 ) { + hal_kit_cdc_discover_devices( cdc_buses[i], &cfgArray[ifaceNum++], &found ); + ifaceNum += found; + } + } +#endif + +#ifdef ATCA_HAL_KIT_HID + int hid_buses[MAX_BUSES]; + memset( hid_buses, -1, sizeof(hid_buses)); + hal_kit_hid_discover_buses(hid_buses, MAX_BUSES); + for ( i = 0; i < MAX_BUSES && ifaceNum < maxIfaces; i++ ) { + if ( hid_buses[i] != -1 ) { + hal_kit_hid_discover_devices( hid_buses[i], &cfgArray[ifaceNum++], &found); + ifaceNum += found; + } + } +#endif + + return ATCA_SUCCESS; +} + +/** \brief common cleanup code which idles the device after any operation + * \return ATCA_STATUS + */ +static ATCA_STATUS _atcab_exit(void) +{ + return atcab_idle(); +} + + +/** \brief get the device revision information + * \param[out] revision - 4-byte storage for receiving the revision number from the device + * \return ATCA_STATUS + */ + +ATCA_STATUS atcab_info( uint8_t *revision ) +{ + ATCAPacket packet; + ATCA_STATUS status = ATCA_GEN_FAIL; + uint32_t execution_time; + + if ( !_gDevice ) + return ATCA_GEN_FAIL; + + // build an info command + packet.param1 = INFO_MODE_REVISION; + packet.param2 = 0; + + do { + if ( (status = atInfo( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_INFO); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, &(packet.data[0]), &(packet.rxsize) )) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy( revision, &packet.data[1], 4 ); // don't include the receive length, only payload + } while (0); + + if ( status != ATCA_COMM_FAIL ) // don't keep shoving more stuff at the chip if there's something wrong with comm + _atcab_exit(); + + return status; +} + +/** \brief Get a 32 byte random number from the CryptoAuth device + * \param[out] rand_out ptr to 32 bytes of storage for random number + * \return status of the operation + */ +ATCA_STATUS atcab_random(uint8_t *rand_out) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + if ( !_gDevice ) + return ATCA_GEN_FAIL; + + // build an random command + packet.param1 = RANDOM_SEED_UPDATE; + packet.param2 = 0x0000; + status = atRandom( _gCommandObj, &packet ); + execution_time = atGetExecTime( _gCommandObj, CMD_RANDOM); + + do { + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy( rand_out, &packet.data[1], 32 ); // data[0] is the length byte of the response + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief generate a key on given slot + * \param[in] slot slot number where ECC key is configured + * \param[out] pubkey 64 bytes of returned public key for given slot + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_genkey( int slot, uint8_t *pubkey ) +{ + ATCAPacket packet; + uint16_t execution_time = 0; + ATCA_STATUS status = ATCA_GEN_FAIL; + + // build a genkey command + packet.param1 = GENKEY_MODE_PRIVATE_KEY_GENERATE; // a random private key is generated and stored in slot keyID + packet.param2 = (uint16_t)slot; // slot and KeyID are the same thing + + do { + if ( (status = atGenKey( _gCommandObj, &packet, false )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_GENKEY); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize) )) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy(pubkey, &packet.data[1], 64 ); + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Execute a pass-through Nonce command to initialize TempKey to the specified value + * \param[in] tempkey - pointer to 32 bytes of data which will be used to initialize TempKey + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_nonce(const uint8_t *tempkey) +{ + return atcab_challenge(tempkey); +} + +/** \brief Initialize TempKey with a random Nonce + * \param[in] seed - pointer to 20 bytes of data which will be used to calculate TempKey + * \param[out] rand_out - pointer to 32 bytes of data that is the output of the Nonce command + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_nonce_rand(const uint8_t *seed, uint8_t* rand_out) +{ + return atcab_challenge_seed_update(seed, rand_out); +} + +/** \brief send a challenge to the device (a pass-through nonce) + * \param[in] challenge - pointer to 32 bytes of data which will be sent as the challenge + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_challenge(const uint8_t *challenge) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + // Verify the inputs + if (challenge == NULL) { + status = ATCA_BAD_PARAM; + break; + } + + // build a nonce command (pass through mode) + packet.param1 = NONCE_MODE_PASSTHROUGH; + packet.param2 = 0x0000; + memcpy( packet.data, challenge, 32 ); + + if ((status = atNonce( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_NONCE); + + if ((status = atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ((status = atsend( _gIface, (uint8_t*)&packet, packet.txsize)) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ((status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief send a challenge to the device (a seed update nonce) + * \param[in] seed - pointer to 32 bytes of data which will be sent as the challenge + * \param[out] rand_out - points to space to receive random number + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_challenge_seed_update( const uint8_t *seed, uint8_t* rand_out ) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + // Verify the inputs + if (seed == NULL || rand_out == NULL) { + status = ATCA_BAD_PARAM; + break; + } + + // build a nonce command (pass through mode) + packet.param1 = NONCE_MODE_SEED_UPDATE; + packet.param2 = 0x0000; + memcpy( packet.data, seed, 20 ); + + if ((status = atNonce(_gCommandObj, &packet)) != ATCA_SUCCESS) break; + + execution_time = atGetExecTime(_gCommandObj, CMD_NONCE); + + if ((status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize)) != ATCA_SUCCESS ) break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ((status = atreceive(_gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS) break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ((status = isATCAError(packet.data)) != ATCA_SUCCESS) break; + + memcpy(&rand_out[0], &packet.data[ATCA_RSP_DATA_IDX], 32); + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief read the serial number of the device + * \param[out] serial_number pointer to space to receive serial number. This space should be 9 bytes long + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_read_serial_number(uint8_t* serial_number) +{ + // read config zone bytes 0-3 and 4-7, concatenate the two bits into serial_number + uint8_t status = ATCA_GEN_FAIL; + uint8_t bytes_read[ATCA_BLOCK_SIZE]; + uint8_t block = 0; + uint8_t cpyIndex = 0; + uint8_t offset = 0; + + do { + memset(serial_number, 0x00, ATCA_SERIAL_NUM_SIZE); + // Read first 32 byte block. Copy the bytes into the config_data buffer + block = 0; + offset = 0; + if ( (status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, block, offset, bytes_read, ATCA_WORD_SIZE)) != ATCA_SUCCESS ) + break; + + memcpy(&serial_number[cpyIndex], bytes_read, ATCA_WORD_SIZE); + cpyIndex += ATCA_WORD_SIZE; + + block = 0; + offset = 2; + if ( (status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, block, offset, bytes_read, ATCA_WORD_SIZE)) != ATCA_SUCCESS ) + break; + + memcpy(&serial_number[cpyIndex], bytes_read, ATCA_WORD_SIZE); + cpyIndex += ATCA_WORD_SIZE; + + block = 0; + offset = 3; + if ( (status = atcab_read_zone(ATCA_ZONE_CONFIG, 0, block, offset, bytes_read, ATCA_WORD_SIZE)) != ATCA_SUCCESS ) + break; + + memcpy(&serial_number[cpyIndex], bytes_read, 1); + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief verify a signature using CryptoAuth hardware (as opposed to an ECDSA software implementation) + * \param[in] message pointer + * \param[in] signature pointer + * \param[in] pubkey pointer + * \param[out] verified boolean whether or not the challenge/signature/pubkey verified + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_verify_extern(const uint8_t *message, const uint8_t *signature, const uint8_t *pubkey, bool *verified) +{ + ATCA_STATUS status; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + *verified = false; + + // nonce passthrough + if ( (status = atcab_challenge(message)) != ATCA_SUCCESS ) + break; + + // build a verify command + packet.param1 = VERIFY_MODE_EXTERNAL; //verify the signature + packet.param2 = VERIFY_KEY_P256; + memcpy( &packet.data[0], signature, ATCA_SIG_SIZE); + memcpy( &packet.data[64], pubkey, ATCA_PUB_KEY_SIZE); + + if ( (status = atVerify( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_VERIFY ); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize) )) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + status = isATCAError(packet.data); + *verified = (status == 0); + if (status == ATCA_CHECKMAC_VERIFY_FAILED) + status = ATCA_SUCCESS; // Verify failed, but command succeeded + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief issues ecdh command + * \param[in] key_id slot of key for ECDH computation + * \param[in] pubkey public key + * \param[out] ret_ecdh - computed ECDH key - A buffer with size of ATCA_KEY_SIZE + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_ecdh(uint16_t key_id, const uint8_t* pubkey, uint8_t* ret_ecdh) +{ + ATCA_STATUS status; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + if (pubkey == NULL || ret_ecdh == NULL) { + status = ATCA_BAD_PARAM; + break; + } + memset(ret_ecdh, 0, ATCA_KEY_SIZE); + + // build a ecdh command + packet.param1 = ECDH_PREFIX_MODE; + packet.param2 = key_id; + memcpy( packet.data, pubkey, ATCA_PUB_KEY_SIZE ); + + if ( (status = atECDH( _gCommandObj, &packet )) != ATCA_SUCCESS ) break; + + execution_time = atGetExecTime( _gCommandObj, CMD_ECDH); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + if ( (status = atsend(_gIface, (uint8_t*)&packet, packet.txsize)) != ATCA_SUCCESS ) break; + + atca_delay_ms(execution_time); + + if ((status = atreceive(_gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS) break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) break; + + // The ECDH command may return a single byte. Then the CRC is copied into indices [1:2] + memcpy(ret_ecdh, &packet.data[ATCA_RSP_DATA_IDX], ATCA_KEY_SIZE); + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief issues ecdh command + * \param[in] slotid slot of key for ECDH computation + * \param[in] pubkey public key + * \param[out] ret_ecdh - computed ECDH key - A buffer with size of ATCA_KEY_SIZE + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_ecdh_enc(uint16_t slotid, const uint8_t* pubkey, uint8_t* ret_ecdh, const uint8_t* enckey, const uint8_t enckeyid) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t cmpBuf[ATCA_WORD_SIZE]; + uint8_t block = 0; + + do { + // Check the inputs + if (pubkey == NULL || ret_ecdh == NULL || enckey == NULL) { + status = ATCA_BAD_PARAM; + BREAK(status, "Bad input parameters"); + } + // Send the ECDH command with the public key provided + if ((status = atcab_ecdh(slotid, pubkey, ret_ecdh)) != ATCA_SUCCESS) BREAK(status, "ECDH Failed"); + + // ECDH may return a key or a single byte. The atcab_ecdh() function performs a memset to 00 on ecdhRsp. + memset(cmpBuf, 0, ATCA_WORD_SIZE); + + // Compare arbitrary bytes to see if they are 00 + if (memcmp(cmpBuf, &ret_ecdh[18], ATCA_WORD_SIZE) == 0) { + // There is no ecdh key, check the value of the first byte for success + if (ret_ecdh[0] != CMD_STATUS_SUCCESS) BREAK(status, "ECDH Command Execution Failure"); + + // ECDH succeeded, perform an encrypted read from the n+1 slot. + if ((status = atcab_read_enc(slotid + 1, block, ret_ecdh, enckey, enckeyid)) != ATCA_SUCCESS) BREAK(status, "Encrypte read failed"); + } + } while (0); + + return status; +} + + +/** \brief Compute the address given the zone, slot, block, and offset + * \param[in] zone + * \param[in] slot + * \param[in] block + * \param[in] offset + * \param[in] addr + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_get_addr(uint8_t zone, uint8_t slot, uint8_t block, uint8_t offset, uint16_t* addr) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t memzone = zone & 0x03; + + if (addr == NULL) + return ATCA_BAD_PARAM; + if ((memzone != ATCA_ZONE_CONFIG) && (memzone != ATCA_ZONE_DATA) && (memzone != ATCA_ZONE_OTP)) + return ATCA_BAD_PARAM; + do { + // Initialize the addr to 00 + *addr = 0; + // Mask the offset + offset = offset & (uint8_t)0x07; + if ((memzone == ATCA_ZONE_CONFIG) || (memzone == ATCA_ZONE_OTP)) { + *addr = block << 3; + *addr |= offset; + }else { // ATCA_ZONE_DATA + *addr = slot << 3; + *addr |= offset; + *addr |= block << 8; + } + } while (0); + + return status; +} + + + +/** \brief Query to see if the specified slot is locked + * \param[in] slot The slot to query for locked (slot 0-15) + * \param[out] islocked true if the specified slot is locked + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_is_slot_locked(uint8_t slot, bool *islocked) +{ + uint8_t ret = ATCA_GEN_FAIL; + uint8_t slotLock_data[ATCA_WORD_SIZE]; + uint8_t lockable_data[ATCA_WORD_SIZE]; + uint8_t slotLock_idx = 0; + uint8_t lockBit_idx = 0; + uint8_t keyConfig_idx = 0; + uint8_t lockableBit_idx = 5; + + do { + // Read the word with the lock bytes ( SlotLock[2], RFU[2] ) (config block = 2, word offset = 6) + if ( (ret = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 2 /*block*/, 6 /*offset*/, slotLock_data, ATCA_WORD_SIZE)) != ATCA_SUCCESS ) + break; + + // Determine the slotlock and lockbit index into the word_data (slotLocked byte) based on the slot we are querying for + if (slot < 8) { + slotLock_idx = 0; + lockBit_idx = slot; + }else if ((slot > 8) && (slot <= ATCA_KEY_ID_MAX)) { + slotLock_idx = 1; + lockBit_idx = slot - 8; + }else + return ATCA_BAD_PARAM; + + // check the slotLocked[] bit is set to zero + if ( ((slotLock_data[slotLock_idx] >> lockBit_idx) & 0x01) == 0x00 ) + *islocked = true; + else{ + keyConfig_idx = (slot % 2) ? 2 : 0; + // Read the word with the lockable bytes in keyConfig block (config block = 3, word offset = depending on the slot) + if ( (ret = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 3 /*block*/, (slot >> 1) /*offset*/, lockable_data, ATCA_WORD_SIZE)) != ATCA_SUCCESS ) + break; + + if (((lockable_data[keyConfig_idx] >> lockableBit_idx) & 0x01) == 0x00) + *islocked = true; + else + *islocked = false; + } + } while (0); + + // all atcab commands within this method follow the wake/idle pattern, no non-atcab methods called, so don't need to _atcab_exit() + return ret; +} + +/** \brief Query to see if the specified zone is locked + * \param[in] zone The zone to query for locked (use LOCK_ZONE_CONFIG or LOCK_ZONE_DATA) + * \param[out] islocked true if the specified zone is locked + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_is_locked(uint8_t zone, bool *islocked) +{ + uint8_t ret = ATCA_GEN_FAIL; + uint8_t word_data[ATCA_WORD_SIZE]; + uint8_t zone_idx = 2; + + do { + // Read the word with the lock bytes (UserExtra, Selector, LockValue, LockConfig) (config block = 2, word offset = 5) + if ( (ret = atcab_read_zone(ATCA_ZONE_CONFIG, 0, 2 /*block*/, 5 /*offset*/, word_data, ATCA_WORD_SIZE)) != ATCA_SUCCESS ) + break; + + // Determine the index into the word_data based on the zone we are querying for + if (zone == LOCK_ZONE_DATA) zone_idx = 2; + if (zone == LOCK_ZONE_CONFIG) zone_idx = 3; + + // Set the locked return variable base on the value. + if (word_data[zone_idx] == 0) + *islocked = true; + else + *islocked = false; + + } while (0); + + return ret; +} + +/** \brief Write either 4 or 32 bytes of data into a device zone. + * + * See ECC108A datasheet, datazone address values, table 9-8 + * + * \param[in] zone Device zone to write to (0=config, 1=OTP, 2=data). + * \param[in] slot If writing to the data zone, whit is the slot to write to, otherwise it should be 0. + * \param[in] block 32-byte block to write to. + * \param[in] offset 4-byte word within the specified block to write to. If performing a 32-byte write, this should + * be 0. + * \param[in] data Data to be written. + * \param[in] len Number of bytes to be written. Must be either 4 or 32. + * \return ATCA_SUCCESS on success + */ +ATCA_STATUS atcab_write_zone(uint8_t zone, uint8_t slot, uint8_t block, uint8_t offset, const uint8_t *data, uint8_t len) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t addr; + uint16_t execution_time = 0; + + // Check the input parameters + if (data == NULL) + return ATCA_BAD_PARAM; + + if ( len != 4 && len != 32 ) + return ATCA_BAD_PARAM; + + do { + // The get address function checks the remaining variables + if ( (status = atcab_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS ) + break; + + // If there are 32 bytes to write, then xor the bit into the mode + if (len == ATCA_BLOCK_SIZE) + zone = zone | ATCA_ZONE_READWRITE_32; + + // build a write command + packet.param1 = zone; + packet.param2 = addr; + memcpy( packet.data, data, len ); + + if ( (status = atWrite( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_WRITEMEM); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize) )) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + status = isATCAError(packet.data); + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief read either 4 or 32 bytes of data into given slot + * + * for 32 byte read, offset is ignored + * data receives the contents read from the slot + * + * data zone must be locked and the slot configuration must not be secret for a slot to be successfully read + * + * \param[in] zone + * \param[in] slot + * \param[in] block + * \param[in] offset + * \param[in] data + * \param[in] len Must be either 4 or 32 + * returns ATCA_STATUS + */ +ATCA_STATUS atcab_read_zone(uint8_t zone, uint8_t slot, uint8_t block, uint8_t offset, uint8_t *data, uint8_t len) +{ + ATCA_STATUS status = ATCA_SUCCESS; + ATCAPacket packet; + uint16_t addr; + uint16_t execution_time = 0; + + do { + // Check the input parameters + if (data == NULL) + return ATCA_BAD_PARAM; + + if ( len != 4 && len != 32 ) + return ATCA_BAD_PARAM; + + // The get address function checks the remaining variables + if ( (status = atcab_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS ) + break; + + // If there are 32 bytes to write, then xor the bit into the mode + if (len == ATCA_BLOCK_SIZE) + zone = zone | ATCA_ZONE_READWRITE_32; + + // build a read command + packet.param1 = zone; + packet.param2 = addr; + + if ( (status = atRead( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_READMEM); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize) )) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy( data, &packet.data[1], len ); + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Read 32 bytes of data from the given slot. + * The function returns clear text bytes. Encrypted bytes are read over the wire, then subsequently decrypted + * Data zone must be locked and the slot configuration must be set to encrypted read for the block to be successfully read + * \param[in] slotid The slot id for the encrypted read + * \param[in] block The block id in the specified slot + * \param[out] data The 32 bytes of clear text data that was read encrypted from the slot, then decrypted + * \param[in] enckey The key to encrypt with for writing + * \param[in] enckeyid The keyid of the parent encryption key + * returns ATCA_STATUS + */ +ATCA_STATUS atcab_read_enc(uint8_t slotid, uint8_t block, uint8_t *data, const uint8_t* enckey, const uint16_t enckeyid) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t zone = ATCA_ZONE_DATA | ATCA_ZONE_READWRITE_32; + atca_nonce_in_out_t nonceParam; + atca_gen_dig_in_out_t genDigParam; + atca_temp_key_t tempkey; + uint8_t numin[NONCE_NUMIN_SIZE] = { 0 }; + uint8_t randout[RANDOM_NUM_SIZE] = { 0 }; + int i = 0; + + do { + // Verify inputs parameters + if (data == NULL || enckey == NULL) { + status = ATCA_BAD_PARAM; + break; + } + + // Random Nonce inputs + nonceParam.mode = NONCE_MODE_SEED_UPDATE; + nonceParam.num_in = (uint8_t*)&numin; + nonceParam.rand_out = (uint8_t*)&randout; + nonceParam.temp_key = &tempkey; + + // Send the random Nonce command + if ((status = atcab_nonce_rand(numin, randout)) != ATCA_SUCCESS) BREAK(status, "Nonce failed"); + + // Calculate Tempkey + if ((status = atcah_nonce(&nonceParam)) != ATCA_SUCCESS) BREAK(status, "Calc TempKey failed"); + + // GenDig inputs + genDigParam.key_id = enckeyid; + genDigParam.stored_value = enckey; + genDigParam.zone = GENDIG_ZONE_DATA; + genDigParam.temp_key = &tempkey; + + // Send the GenDig command + if ((status = atcab_gendig(GENDIG_ZONE_DATA, enckeyid)) != ATCA_SUCCESS) BREAK(status, "GenDig failed"); + + // Calculate Tempkey + if ((status = atcah_gen_dig(&genDigParam)) != ATCA_SUCCESS) BREAK(status, ""); + + // Read Encrypted + if ((status = atcab_read_zone(zone, slotid, block, 0, data, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS) BREAK(status, "Read encrypted failed"); + + // Decrypt + for (i = 0; i < ATCA_BLOCK_SIZE; i++) + data[i] = data[i] ^ tempkey.value[i]; + + status = ATCA_SUCCESS; + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Write 32 bytes of data into given slot. + * The function takes clear text bytes, but encrypts them for writing over the wire + * Data zone must be locked and the slot configuration must be set to encrypted write for the block to be successfully written + * \param[in] slotid + * \param[in] block + * \param[in] data The 32 bytes of clear text data to be written to the slot + * \param[in] enckey The key to encrypt with for writing + * \param[in] enckeyid The keyid of the parent encryption key + * returns ATCA_STATUS + */ +ATCA_STATUS atcab_write_enc(uint8_t slotid, uint8_t block, const uint8_t *data, const uint8_t* enckey, const uint16_t enckeyid) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t i = 0; + uint8_t zone = ATCA_ZONE_DATA | ATCA_ZONE_READWRITE_32; + atca_nonce_in_out_t nonceParam; + atca_gen_dig_in_out_t genDigParam; + atca_temp_key_t tempkey; + uint8_t numin[NONCE_NUMIN_SIZE] = { 0 }; + uint8_t randout[RANDOM_NUM_SIZE] = { 0 }; + uint8_t cipher_text[ATCA_KEY_SIZE] = { 0 }; + ATCAPacket packet; + uint16_t addr; + uint16_t execution_time = 0; + + do { + // Verify inputs parameters + if (data == NULL || enckey == NULL) { + status = ATCA_BAD_PARAM; + break; + } + // Random Nonce inputs + nonceParam.mode = NONCE_MODE_SEED_UPDATE; + nonceParam.num_in = (uint8_t*)&numin; + nonceParam.rand_out = (uint8_t*)&randout; + nonceParam.temp_key = &tempkey; + + // Send the random Nonce command + if ((status = atcab_nonce_rand(numin, randout)) != ATCA_SUCCESS) BREAK(status, "Nonce failed"); + + // Calculate Tempkey + if ((status = atcah_nonce(&nonceParam)) != ATCA_SUCCESS) BREAK(status, "Calc TempKey failed"); + + // GenDig inputs + genDigParam.key_id = enckeyid; + genDigParam.stored_value = (uint8_t*)enckey; + genDigParam.zone = GENDIG_ZONE_DATA; + genDigParam.temp_key = &tempkey; + + // Send the GenDig command + if ((status = atcab_gendig(GENDIG_ZONE_DATA, enckeyid)) != ATCA_SUCCESS) BREAK(status, "GenDig failed"); + + // Calculate Tempkey + if ((status = atcah_gen_dig(&genDigParam)) != ATCA_SUCCESS) BREAK(status, ""); + + // Xoring plain text with session key + for (i = 0; i < ATCA_KEY_SIZE; i++) + cipher_text[i] = data[i] ^ tempkey.value[i]; + + // The get address function checks the remaining variables + if ((status = atcab_get_addr(ATCA_ZONE_DATA, slotid, block, 0, &addr)) != ATCA_SUCCESS) BREAK(status, "Get address failed"); + + // Calculate Auth MAC + genDigParam.zone = zone; + genDigParam.key_id = addr; + genDigParam.stored_value = (uint8_t*)data; + genDigParam.temp_key = &tempkey; + + if ((status = atcah_gen_mac(&genDigParam)) != ATCA_SUCCESS) BREAK(status, "Calculate Auth MAC failed"); + + // build a write command for encrypted writes + packet.param1 = zone; + packet.param2 = addr; + memcpy(packet.data, cipher_text, ATCA_KEY_SIZE); + memcpy(&packet.data[ATCA_KEY_SIZE], tempkey.value, ATCA_KEY_SIZE); + + if ((status = atWriteEnc(_gCommandObj, &packet)) != ATCA_SUCCESS) BREAK(status, "format write command bytes failed"); + + execution_time = atGetExecTime(_gCommandObj, CMD_WRITEMEM); + + if ((status = atcab_wakeup()) != ATCA_SUCCESS) BREAK(status, "wakeup failed"); + + // send the command + if ((status = atsend(_gIface, (uint8_t*)&packet, packet.txsize)) != ATCA_SUCCESS) BREAK(status, "send write command bytes failed"); + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ((status = atreceive(_gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS) BREAK(status, "receive write command bytes failed"); + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + status = isATCAError(packet.data); + + } while (0); + + _atcab_exit(); + return status; +} + + +/** \brief read the config zone by block by block + * for 32 byte read, offset is ignored + * data receives the contents read from the slot + * Config zone can be read regardless of it being locked or unlocked + * \param[in] config_data pointer to buffer containing a contiguous set of bytes to read from the config zone + * returns ATCA_STATUS + */ +ATCA_STATUS atcab_read_ecc_config_zone(uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + uint8_t zone = 0, block = 0, offset = 0, slot = 0, index = 0; + uint16_t addr = 0x0000; + + //reading the zone block by block until word 16 (block 2, offset 6) + do { + if ((block == 2) && (offset <= 7)) { + // read 32 bytes at once + packet.param1 = ATCA_ZONE_CONFIG; + + // compute the word addr and build the read command + if ( (status = atcab_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS ) + break; + + packet.param2 = addr; + status = atRead(_gCommandObj, &packet); + execution_time = atGetExecTime( _gCommandObj, CMD_READMEM); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + memset(packet.data, 0x00, 130); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = atcab_idle()) != ATCA_SUCCESS ) + break; + + // check for error in response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + // update the word address after reading each block + ++offset; + if ((block == 2) && (offset > 7)) + block = 3; + + // copy the contents to a config data buffer + memcpy(&config_data[index], &packet.data[1], ATCA_WORD_SIZE ); + index += ATCA_WORD_SIZE; + }else { + // build a read command (read from the start of zone) + offset = 0; + // read 32 bytes at once + packet.param1 = ATCA_ZONE_CONFIG | ATCA_ZONE_READWRITE_32; + + // compute the word addr and build the read command + if ( (status = atcab_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS ) + break; + + packet.param2 = addr; + status = atRead(_gCommandObj, &packet); + execution_time = atGetExecTime( _gCommandObj, CMD_READMEM); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + memset(packet.data, 0x00, sizeof(packet.data)); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = atcab_idle()) != ATCA_SUCCESS ) + break; + + // check for error in response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + // update the word address after reading each block + ++block; + + // copy the contents to a config data buffer + memcpy(&config_data[index], &packet.data[1], ATCA_BLOCK_SIZE ); + index += ATCA_BLOCK_SIZE; + } + + } while (block <= 3); + + _atcab_exit(); + return status; +} + +/** \brief given an ECC configuration zone buffer, write its parts to the device's config zone + * \param[in] config_data pointer to buffer containing a contiguous set of bytes to write to the config zone + * \returns ATCA_STATUS + */ +ATCA_STATUS atcab_write_ecc_config_zone(const uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + uint8_t zone = 0, block = 0, offset = 0, slot = 0, index = 0; + uint16_t addr = 0; + + // write the ecc zone one block at a time starting after address 0x04 (block 0, offset 4) + offset = 4; + do { + if ((block == 0) || (block == 2)) { + + if (offset <= 7) { + memset(packet.data, 0x00, 130); + // read 4 bytes at once + packet.param1 = ATCA_ZONE_CONFIG; + // build a write command (write from the start) + if ( (status = atcab_get_addr(zone, slot, block, offset, &addr)) != ATCA_SUCCESS ) + break; + + packet.param2 = addr; + memcpy(&packet.data[0], &config_data[index + 16], ATCA_WORD_SIZE); + index += ATCA_WORD_SIZE; + status = atWrite(_gCommandObj, &packet); + execution_time = atGetExecTime( _gCommandObj, CMD_WRITEMEM); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = atcab_idle()) != ATCA_SUCCESS ) break; + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + // update the offset address after reading each block + ++offset; + if ((block == 2) && (offset == 5)) { + // words above (block 2 offset 5 cant be written) + ++offset; index += ATCA_WORD_SIZE; + } + }else { + // update the word address after completely reading each block + ++block; offset = 0; + } + }else { + memset(packet.data, 0x00, 130); + // read 32 bytes at once + packet.param1 = ATCA_ZONE_CONFIG | ATCA_ZONE_READWRITE_32; + // build a write command (write from the start) + atcab_get_addr(zone, slot, block, offset, &addr); + packet.param2 = addr; + memcpy(&packet.data[0], &config_data[index + 16], ATCA_BLOCK_SIZE); + index += ATCA_BLOCK_SIZE; + if ( (status = atWrite(_gCommandObj, &packet)) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_WRITEMEM); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = atcab_idle()) != ATCA_SUCCESS ) break; + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + // update the word address after completely reading each block + ++block; offset = 0; + } + + } while (block <= 3); + + _atcab_exit(); + return status; +} + +/** \brief given an SHA configuration zone buffer, read its parts from the device's config zone + * \param[out] config_data pointer to buffer containing a contiguous set of bytes to write to the config zone + * \returns ATCA_STATUS + */ +ATCA_STATUS atcab_read_sha_config_zone(uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + do { + + // Verify the inputs + if ( config_data == NULL ) { + status = ATCA_BAD_PARAM; + break; + } + + status = atcab_read_bytes_zone(ATSHA204A, ATCA_ZONE_CONFIG, 0x00, ATCA_SHA_CONFIG_SIZE, config_data); + if ( status != ATCA_SUCCESS ) + break; + + } while (0); + + return status; +} + +/** \brief given an SHA configuration zone buffer, write its parts to the device's config zone + * \param[in] config_data pointer to buffer containing a contiguous set of bytes to write to the config zone + * \returns ATCA_STATUS + */ +ATCA_STATUS atcab_write_sha_config_zone(const uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + do { + + // Verify the inputs + if ( config_data == NULL ) { + status = ATCA_BAD_PARAM; + break; + } + + status = atcab_write_bytes_zone(ATSHA204A, ATCA_ZONE_CONFIG, 0x10, &config_data[16], 68); + if ( status != ATCA_SUCCESS ) + break; + + } while (0); + + return status; +} + +/** \brief given an SHA configuration zone buffer and dev type, read its parts from the device's config zone + * \param[in] dev_type device type + * \param[out] config_data pointer to buffer containing a contiguous set of bytes to write to the config zone + * \returns ATCA_STATUS + */ +ATCA_STATUS atcab_read_config_zone(ATCADeviceType dev_type, uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + do { + + // Verify the inputs + if ( config_data == NULL ) { + status = ATCA_BAD_PARAM; + break; + } + + if (dev_type == ATSHA204A) + status = atcab_read_bytes_zone(dev_type, ATCA_ZONE_CONFIG, 0x00, ATCA_SHA_CONFIG_SIZE, config_data); + else + status = atcab_read_bytes_zone(dev_type, ATCA_ZONE_CONFIG, 0x00, ATCA_CONFIG_SIZE, config_data); + + if ( status != ATCA_SUCCESS ) + break; + + } while (0); + + return status; +} + +/** \brief given an SHA configuration zone buffer and dev type, write its parts to the device's config zone + * \param[in] config_data pointer to buffer containing a contiguous set of bytes to write to the config zone + * \returns ATCA_STATUS + */ +ATCA_STATUS atcab_write_config_zone(ATCADeviceType dev_type, const uint8_t* config_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + do { + + // Verify the inputs + if ( config_data == NULL ) { + status = ATCA_BAD_PARAM; + break; + } + + if (dev_type == ATSHA204A) + status = atcab_write_bytes_zone(dev_type, ATCA_ZONE_CONFIG, 0x00, config_data, ATCA_SHA_CONFIG_SIZE); + else + status = atcab_write_bytes_zone(dev_type, ATCA_ZONE_CONFIG, 0x00, config_data, ATCA_CONFIG_SIZE); + + if ( status != ATCA_SUCCESS ) + break; + + } while (0); + + return status; +} + +/** \brief This function compares all writable bytes in the configuration zone that is passed in to the bytes on the device + * + * \param[in] config_data pointer to all 128 bytes in configuration zone. Not used if NULL. + * \param[out] same_config pointer to boolean status whether config data passed in matches the actual config zone + * \return ATCA_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_CONFIG_SIZE]; + + do { + // Check the inputs + if ((config_data == NULL) || (same_config == NULL)) { + status = ATCA_BAD_PARAM; + BREAK(status, "Invalid Parameters"); + } + // Set the boolean to false + *same_config = false; + + // Read all of the configuration bytes from the device + if ((status = atcab_read_ecc_config_zone(device_config_data)) != ATCA_SUCCESS) BREAK(status, "Read config zone failed"); + + // Compare writable bytes 16-51 & writable bytes 90-127. + // Skip the counter & LastKeyUse bytes [52-83] + if (memcmp(&device_config_data[16], &config_data[16], 52 - 16) == 0 + && memcmp(&device_config_data[90], &config_data[90], 128 - 90) == 0) { + *same_config = true; + break; + } + } while (0); + return status; +} + + +/** \brief lock the ATCA ECC config zone. config zone must be unlocked for the zone to be successfully locked + * + * \param[in] lock_response + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_lock_config_zone(uint8_t* lock_response) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + // build command for lock zone and send + packet.param1 = LOCK_ZONE_NO_CRC | LOCK_ZONE_CONFIG; + + do { + if ( (status = atLock(_gCommandObj, &packet)) != ATCA_SUCCESS ) break; + + execution_time = atGetExecTime( _gCommandObj, CMD_LOCK); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + //check the response for error + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy(lock_response, &packet.data[1], 1); + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief lock the ATCA ECC Data zone. + * + * ConfigZone must be locked and DataZone must be unlocked for the zone to be successfully locked + * + * \param[in] lock_response + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_lock_data_zone(uint8_t* lock_response) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + // build command for lock zone and send + packet.param1 = LOCK_ZONE_NO_CRC | LOCK_ZONE_DATA; + packet.param2 = 0x0000; + + do { + status = atLock(_gCommandObj, &packet); + execution_time = atGetExecTime( _gCommandObj, CMD_LOCK); + + if ((status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ((status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ((status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + //check the response for error + if ((status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy(lock_response, &packet.data[1], 1); + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief lock the ATCA ECC Data Slot + * ConfigZone must be locked and DataZone may or may not be locked for a individual data slot to be locked + * + * \param[in] slot to be locked in data zone + * \param[in] lock_response pointer to the lock response from the chip - 0 is successful lock + * \return ATAC_STATUS + */ +ATCA_STATUS atcab_lock_data_slot(uint8_t slot, uint8_t* lock_response) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + // build command for lock slot and send + packet.param1 = (slot << 2) | LOCK_ZONE_DATA_SLOT; + packet.param2 = 0x0000; + + do { + if ( (status = atLock(_gCommandObj, &packet)) != ATCA_SUCCESS ) break; + + execution_time = atGetExecTime( _gCommandObj, CMD_LOCK); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + //check the response for error + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy(lock_response, &packet.data[1], 1); + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief sign a buffer using private key in given slot, stuff the signature + * \param[in] slot + * \param[in] msg should point to a 32 byte buffer + * \param[out] signature of msg. signature should point to buffer SIGN_RSP_SIZE big + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_sign(uint16_t slot, const uint8_t *msg, uint8_t *signature) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + uint8_t randomnum[64]; + + if ( !_gDevice ) + return ATCA_GEN_FAIL; + + do { + if ( (status = atcab_random(randomnum)) != ATCA_SUCCESS ) break; + if ( (status = atcab_challenge( msg )) != ATCA_SUCCESS ) break; + + // build sign command + packet.param1 = SIGN_MODE_EXTERNAL; + packet.param2 = slot; + if ( (status = atSign( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_SIGN); + + if ( (status != atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + // check for response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy( signature, &packet.data[1], ATCA_SIG_SIZE ); + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Issues a GenDig command to SHA256 hash the source data indicated by zone with the + * contents of TempKey. See the CryptoAuth datasheet for your chip to see what the values of zone + * correspond to. + * \param[in] zone - designates the source of the data to hash with TempKey + * \param[in] key_id - indicates the key, OTP block or message order for shared nonce mode + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_gendig(uint8_t zone, uint16_t key_id) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + uint8_t otherDat[GENDIG_OTHER_DATA_SIZE] = { 0 }; + + do { + // Verify that we a valid device is present + if (!_gDevice) return ATCA_GEN_FAIL; + + // Call the atcab_gendig_host() function + if ((status = atcab_gendig_host(zone, key_id, otherDat, GENDIG_OTHER_DATA_SIZE)) != ATCA_SUCCESS ) BREAK(status, "GenDig failed"); + + } while (0); + return status; +} + +/** \brief Similar to atcab_gendig except this method does the operation in software on the host. + * \param[in] zone - designates the source of the data to hash with TempKey + * \param[in] key_id - indicates the key, OTP block or message order for shared nonce mode + * \param[in] other_data - pointer to 4 or 32 bytes of data depending upon the mode + * \param[in] len - length of data + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_gendig_host(uint8_t zone, uint16_t key_id, uint8_t *other_data, uint8_t len) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + bool hasMACKey = 0; + + if ( !_gDevice || other_data == NULL ) + return ATCA_GEN_FAIL; + + do { + + // build gendig command + packet.param1 = zone; + packet.param2 = key_id; + + if ( packet.param1 == 0x03 && len == 0x20) + memcpy(&packet.data[0], &other_data[0], ATCA_WORD_SIZE); + else if ( packet.param1 == 0x02 && len == 0x20) { + memcpy(&packet.data[0], &other_data[0], ATCA_WORD_SIZE); + hasMACKey = true; + } + + if ( (status = atGenDig( _gCommandObj, &packet, hasMACKey)) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_GENDIG); + + if ( (status != atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + // check for response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief reads a signature found in one of slots 8 through F. + * \param[in] slot8toF - which slot to read + * \param[out] sig - pointer to the space to receive the signature found in the slot + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_read_sig(uint8_t slot8toF, uint8_t *sig) +{ + uint8_t ret = ATCA_GEN_FAIL; + uint8_t read_buf[ATCA_BLOCK_SIZE]; + uint8_t block = 0; + uint8_t offset = 0; + uint8_t cpyIndex = 0; + + do { + // Check the pointers + if (sig == NULL) break; + + // Check the value of the slot + if (slot8toF < 8 || slot8toF > 0xF) break; + + // Read the first block + block = 0; + if ( (ret = atcab_read_zone(ATCA_ZONE_DATA, slot8toF, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS ) + break; + + // Copy. first 32 bytes + memcpy(&sig[cpyIndex], &read_buf[0], ATCA_BLOCK_SIZE); + cpyIndex += ATCA_BLOCK_SIZE; + + // Read the second block + block = 1; + if ( (ret = atcab_read_zone(ATCA_ZONE_DATA, slot8toF, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS ) + break; + + // Copy. next 32 bytes + memcpy(&sig[cpyIndex], &read_buf[0], ATCA_BLOCK_SIZE); + cpyIndex += ATCA_BLOCK_SIZE; + + } while (0); + + return ret; +} + +/** \brief returns a public key found in a designated slot. The slot must be configured as a slot with a private key. + * This method will use GenKey t geenrate the corresponding public key from the private key in the given slot. + * \param[in] privSlotId ID of the private key slot + * \param[out] pubkey - pointer to space receiving the contents of the public key that was generated + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_calc_pubkey(uint8_t privSlotId, uint8_t *pubkey) +{ + return atcab_get_pubkey(privSlotId, pubkey); +} + +/** \brief returns a public key found in a designated slot. The slot must be configured as a slot with a private key. + * This method will use GenKey t geenrate the corresponding public key from the private key in the given slot. + * \param[in] privSlotId ID of the private key slot + * \param[out] pubkey - pointer to space receiving the contents of the public key that was generated + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_get_pubkey(uint8_t privSlotId, uint8_t *pubkey) +{ + ATCAPacket packet; + uint16_t execution_time = 0; + ATCA_STATUS status = ATCA_GEN_FAIL; + + do { + // build a genkey command + packet.param1 = GENKEY_MODE_PUBLIC; + packet.param2 = (uint16_t)(privSlotId); + + if ( (status = atGenKey( _gCommandObj, &packet, false )) != ATCA_SUCCESS ) break; + + execution_time = atGetExecTime( _gCommandObj, CMD_GENKEY); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize) )) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + // copy the response public key data + memcpy(pubkey, &packet.data[1], 64 ); + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief write a P256 private key in given slot using mac computation + * \param[in] slot + * \param[in] priv_key first 4 bytes of 36 bytes should be zero + * \param[in] write_key_slot slot to make a session key + * \param[in] write_key key to make a session key + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_priv_write(uint8_t slot, const uint8_t priv_key[36], uint8_t write_key_slot, const uint8_t write_key[32]) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + atca_nonce_in_out_t nonceParam; + atca_gen_dig_in_out_t genDigParam; + atca_write_mac_in_out_t hostMacParam; + atca_temp_key_t tempkey; + uint8_t numin[NONCE_NUMIN_SIZE] = { 0 }; + uint8_t randout[RANDOM_NUM_SIZE] = { 0 }; + uint8_t cipher_text[36] = { 0 }; + uint8_t host_mac[MAC_SIZE] = { 0 }; + uint16_t execution_time = 0; + uint8_t privKey[36]; + uint8_t writeKey[32]; + + if (slot > 15 || priv_key == NULL) + return ATCA_BAD_PARAM; + + do { + + if (write_key == NULL) { + // Caller requested an unencrypted PrivWrite, which is only allowed when the data zone is unlocked + // build an PrivWrite command + packet.param1 = 0x00; // Mode is unencrypted write + packet.param2 = slot; // Key ID + memcpy(&packet.data[0], priv_key, 36); // Private key + memset(&packet.data[36], 0, 32); // MAC (ignored for unencrypted write) + }else { + // Copy the buffers to honor the const designation + memcpy(privKey, priv_key, 36); + memcpy(writeKey, write_key, 32); + + // Send the random Nonce command + if ((status = atcab_nonce_rand(numin, randout)) != ATCA_SUCCESS) + break; + + // Calculate Tempkey + nonceParam.mode = NONCE_MODE_SEED_UPDATE; + nonceParam.num_in = numin; + nonceParam.rand_out = randout; + nonceParam.temp_key = &tempkey; + if ((status = atcah_nonce(&nonceParam)) != ATCA_SUCCESS) + break; + + // Send the GenDig command + if ((status = atcab_gendig_host(GENDIG_ZONE_DATA, write_key_slot, tempkey.value, 32)) != ATCA_SUCCESS) + break; + + // Calculate Tempkey + genDigParam.zone = GENDIG_ZONE_DATA; + genDigParam.key_id = write_key_slot; + genDigParam.stored_value = writeKey; + genDigParam.temp_key = &tempkey; + if ((status = atcah_gen_dig(&genDigParam)) != ATCA_SUCCESS) + break; + + // Calculate Auth MAC and cipher text + hostMacParam.zone = PRIVWRITE_MODE_ENCRYPT; + hostMacParam.key_id = slot; + hostMacParam.encryption_key = &privKey[4]; + hostMacParam.input_data = privKey; + hostMacParam.encrypted_data = cipher_text; + hostMacParam.auth_mac = host_mac; + hostMacParam.temp_key = &tempkey; + if ((status = atcah_privwrite_auth_mac(&hostMacParam)) != ATCA_SUCCESS) + break; + + // build a write command for encrypted writes + packet.param1 = PRIVWRITE_MODE_ENCRYPT; // Mode is encrypted write + packet.param2 = slot; // Key ID + memcpy(&packet.data[0], cipher_text, sizeof(cipher_text)); + memcpy(&packet.data[36], host_mac, sizeof(host_mac)); + } + + if ((status = atPrivWrite(_gCommandObj, &packet)) != ATCA_SUCCESS) + break; + + execution_time = atGetExecTime(_gCommandObj, CMD_PRIVWRITE); + + if ( (status = atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ((status = atsend(_gIface, (uint8_t*)&packet, packet.txsize)) != ATCA_SUCCESS) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ((status = atreceive(_gIface, packet.data, &packet.rxsize)) != ATCA_SUCCESS) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Writes a pub key from to a data slot + * \param[in] slot8toF Slot number to write, expected value is 0x8 through 0xF + * \param[out] pubkey The public key to write into the slot specified + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_write_pubkey(uint8_t slot8toF, uint8_t *pubkey) +{ + ATCA_STATUS status = ATCA_SUCCESS; + uint8_t write_block[ATCA_BLOCK_SIZE]; + uint8_t block = 0; + uint8_t offset = 0; + uint8_t cpyIndex = 0; + uint8_t cpySize = 0; + uint8_t writeIndex = 0; + + do { + // Check the pointers + if (pubkey == NULL) { + status = ATCA_BAD_PARAM; + break; + } + // Check the value of the slot + if (slot8toF < 8 || slot8toF > 0xF) { + status = ATCA_BAD_PARAM; + break; + } + // The 64 byte P256 public key gets written to a 72 byte slot in the following pattern + // | Block 1 | Block 2 | Block 3 | + // | Pad: 4 Bytes | PubKey[0:27] | PubKey[28:31] | Pad: 4 Bytes | PubKey[32:55] | PubKey[56:63] | + + // Setup the first write block accounting for the 4 byte pad + block = 0; + writeIndex = ATCA_PUB_KEY_PAD; + memset(write_block, 0, sizeof(write_block)); + cpySize = ATCA_BLOCK_SIZE - ATCA_PUB_KEY_PAD; + memcpy(&write_block[writeIndex], &pubkey[cpyIndex], cpySize); + cpyIndex += cpySize; + // Write the first block + status = atcab_write_zone(ATCA_ZONE_DATA, slot8toF, block, offset, write_block, ATCA_BLOCK_SIZE); + if (status != ATCA_SUCCESS) break; + + // Setup the second write block accounting for the 4 byte pad + block = 1; + writeIndex = 0; + memset(write_block, 0, sizeof(write_block)); + // Setup for write 4 bytes starting at 0 + cpySize = ATCA_PUB_KEY_PAD; + memcpy(&write_block[writeIndex], &pubkey[cpyIndex], cpySize); + cpyIndex += cpySize; + // Setup for write skip 4 bytes and fill the remaining block + writeIndex += cpySize + ATCA_PUB_KEY_PAD; + cpySize = ATCA_BLOCK_SIZE - writeIndex; + memcpy(&write_block[writeIndex], &pubkey[cpyIndex], cpySize); + cpyIndex += cpySize; + // Write the second block + status = atcab_write_zone(ATCA_ZONE_DATA, slot8toF, block, offset, write_block, ATCA_BLOCK_SIZE); + if (status != ATCA_SUCCESS) break; + + // Setup the third write block + block = 2; + writeIndex = 0; + memset(write_block, 0, sizeof(write_block)); + // Setup for write 8 bytes starting at 0 + cpySize = ATCA_PUB_KEY_PAD + ATCA_PUB_KEY_PAD; + memcpy(&write_block[writeIndex], &pubkey[cpyIndex], cpySize); + // Write the third block + status = atcab_write_zone(ATCA_ZONE_DATA, slot8toF, block, offset, write_block, ATCA_BLOCK_SIZE); + if (status != ATCA_SUCCESS) break; + + } while (0); + + return status; +} + +/** \brief reads a pub key from a readable data slot versus atcab_get_pubkey which generates a pubkey from a private key slot + * \param[in] slot8toF - slot number to read, expected value is 0x8 through 0xF + * \param[out] pubkey - space to receive read pubkey + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_read_pubkey(uint8_t slot8toF, uint8_t *pubkey) +{ + uint8_t ret = ATCA_GEN_FAIL; + uint8_t read_buf[ATCA_BLOCK_SIZE]; + uint8_t block = 0; + uint8_t offset = 0; + uint8_t cpyIndex = 0; + uint8_t cpySize = 0; + uint8_t readIndex = 0; + + // Check the pointers + if (pubkey == NULL) + return ATCA_BAD_PARAM; + // Check the value of the slot + if (slot8toF < 8 || slot8toF > 0xF) + return ATCA_BAD_PARAM; + + do { + // The 64 byte P256 public key gets written to a 72 byte slot in the following pattern + // | Block 1 | Block 2 | Block 3 | + // | Pad: 4 Bytes | PubKey[0:27] | PubKey[28:31] | Pad: 4 Bytes | PubKey[32:55] | PubKey[56:63] | + + // Read the block + block = 0; + if ( (ret = atcab_read_zone(ATCA_ZONE_DATA, slot8toF, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS ) + break; + + // Copy. Account for 4 byte pad + cpySize = ATCA_BLOCK_SIZE - ATCA_PUB_KEY_PAD; + readIndex = ATCA_PUB_KEY_PAD; + memcpy(&pubkey[cpyIndex], &read_buf[readIndex], cpySize); + cpyIndex += cpySize; + + // Read the next block + block = 1; + if ( (ret = atcab_read_zone(ATCA_ZONE_DATA, slot8toF, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS ) + break; + + // Copy. First four bytes + cpySize = ATCA_PUB_KEY_PAD; + readIndex = 0; + memcpy(&pubkey[cpyIndex], &read_buf[readIndex], cpySize); + cpyIndex += cpySize; + // Copy. Skip four bytes + readIndex = ATCA_PUB_KEY_PAD + ATCA_PUB_KEY_PAD; + cpySize = ATCA_BLOCK_SIZE - readIndex; + memcpy(&pubkey[cpyIndex], &read_buf[readIndex], cpySize); + cpyIndex += cpySize; + + // Read the next block + block = 2; + if ( (ret = atcab_read_zone(ATCA_ZONE_DATA, slot8toF, block, offset, read_buf, ATCA_BLOCK_SIZE)) != ATCA_SUCCESS ) + break; + + // Copy. The remaining 8 bytes + cpySize = ATCA_PUB_KEY_PAD + ATCA_PUB_KEY_PAD; + readIndex = 0; + memcpy(&pubkey[cpyIndex], &read_buf[readIndex], cpySize); + + } while (0); + + return ret; +} + +/** \brief write data into given slot of data zone with offset address + * \param[in] slot to write data + * \param[in] offset of pointed slot + * \param[in] data pointer to write data + * \param[in] data length corresponding to data + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_write_bytes_slot(uint8_t slot, uint16_t offset, const uint8_t *data, uint8_t len) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + uint16_t currAddress = offset; + uint8_t currBlock = currAddress / ATCA_BLOCK_SIZE; + uint8_t prevBlock = currBlock; + uint8_t currOffset = (currAddress - (currBlock * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + uint16_t writeIdx = 0; + + if (data == NULL || slot > 15) + return ATCA_BAD_PARAM; + + do { + status = atcab_write_zone(ATCA_ZONE_DATA, slot, currBlock, currOffset, &data[writeIdx], ATCA_BLOCK_SIZE); + if (status != ATCA_SUCCESS) break; + + currAddress += ATCA_BLOCK_SIZE; + currBlock = currAddress / ATCA_BLOCK_SIZE; + + if ( prevBlock == currBlock) + currOffset++; + else { + currOffset = 0; + prevBlock = currBlock; + } + + writeIdx += ATCA_BLOCK_SIZE; + } while (0); + + return status; +} + +/** \brief write data into config, otp or data zone with given zone and offset + * \param[in] dev_type to identify device + * \param[in] zone to write data + * \param[in] address to pointed zone + * \param[in] data pointer of to write data + * \param[in] len data length corresponding to data + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_write_bytes_zone(ATCADeviceType dev_type, uint8_t zone, uint16_t address, const uint8_t *data, uint8_t len) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + uint8_t dataSlot = 0; + uint16_t currAddress = address, writeIdx = 0; + uint8_t currBlock, prevBlock, currOffset; + const static uint16_t slot8_addr = 288, slot9_addr = 704; + + if (data == NULL || zone > ATCA_ZONE_DATA) + return ATCA_BAD_PARAM; + + if (zone == ATCA_ZONE_CONFIG) { + + currBlock = currAddress / ATCA_BLOCK_SIZE; + prevBlock = currBlock; + currOffset = (currAddress - (currBlock * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + + while ( writeIdx < len) { + + if (!(currBlock == 0 && (currOffset == 0 || currOffset == 1 || currOffset == 2 || currOffset == 3)) + && !(currBlock == 2 && (currOffset == 5 || currOffset == 6)) + ) { + status = atcab_write_zone(zone, 0, currBlock, currOffset, &data[writeIdx], ATCA_WORD_SIZE); + if (status != ATCA_SUCCESS) break; + } + + currAddress += ATCA_WORD_SIZE; + currBlock = currAddress / ATCA_BLOCK_SIZE; + + if ( prevBlock == currBlock) + currOffset++; + else { + currOffset = 0; + prevBlock = currBlock; + } + + writeIdx += ATCA_WORD_SIZE; + } + + } else if (zone == ATCA_ZONE_OTP) { + + currBlock = currAddress / ATCA_BLOCK_SIZE; + prevBlock = currBlock; + currOffset = (currAddress - (currBlock * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + + while ( writeIdx < len) { + + status = atcab_write_zone(zone, 0, currBlock, currOffset, &data[writeIdx], ATCA_WORD_SIZE); + if (status != ATCA_SUCCESS) break; + + currAddress += ATCA_WORD_SIZE; + currBlock = currAddress / ATCA_BLOCK_SIZE; + + if ( prevBlock == currBlock) + currOffset++; + else { + currOffset = 0; + prevBlock = currBlock; + } + + writeIdx += ATCA_WORD_SIZE; + } + + } else { + + if (dev_type == ATECC508A || dev_type == ATECC108A ) { + + if (currAddress < slot8_addr) { + dataSlot = currAddress / 36; + currBlock = (currAddress - (dataSlot * 36)) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - (dataSlot * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + currAddress = currAddress - (dataSlot * 36); + } else if (currAddress < slot9_addr) { + dataSlot = 8; + currBlock = (currAddress - slot8_addr) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - slot8_addr) / ATCA_WORD_SIZE; + currAddress = currAddress - slot8_addr; + } else { + dataSlot = (currAddress - slot9_addr) / 72; + currBlock = (currAddress - slot9_addr) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - slot9_addr) / ATCA_WORD_SIZE; + currAddress = currAddress - slot9_addr; + } + + prevBlock = currBlock; + + } else { + + dataSlot = currAddress / ATCA_BLOCK_SIZE; + currBlock = (currAddress - (dataSlot * ATCA_BLOCK_SIZE)) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - (dataSlot * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + currAddress = currAddress - (dataSlot * ATCA_BLOCK_SIZE); + prevBlock = currBlock; + } + + while ( writeIdx < len) { + + status = atcab_write_zone(ATCA_ZONE_DATA, dataSlot, currBlock, currOffset, &data[writeIdx], ATCA_WORD_SIZE); + if (status != ATCA_SUCCESS) break; + + currAddress += ATCA_WORD_SIZE; + currBlock = currAddress / ATCA_BLOCK_SIZE; + + if ( prevBlock == currBlock) + currOffset++; + else { + currOffset = 0; + prevBlock = currBlock; + } + + writeIdx += ATCA_WORD_SIZE; + } + + } + + return status; +} + +/** \brief read data from config, otp or data zone with given zone, offset and len + * \param[in] dev_type to identify device + * \param[in] zone to write data + * \param[in] address of pointed zone + * \param[in] len length to be read + * \param[out] data buffer to be read data + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_read_bytes_zone(ATCADeviceType dev_type, uint8_t zone, uint16_t address, uint8_t len, uint8_t *data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + uint8_t dataSlot = 0; + uint16_t currAddress = address, readIdx = 0; + uint8_t currBlock, prevBlock, currOffset; + const static uint16_t slot8_addr = 288, slot9_addr = 704; + + if (data == NULL || zone > ATCA_ZONE_DATA) + return ATCA_BAD_PARAM; + + if (zone == ATCA_ZONE_CONFIG || zone == ATCA_ZONE_OTP) { + + currBlock = currAddress / ATCA_BLOCK_SIZE; + prevBlock = currBlock; + currOffset = (currAddress - (currBlock * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + + while ( readIdx < len) { + + status = atcab_read_zone(zone, 0, currBlock, currOffset, &data[readIdx], ATCA_WORD_SIZE); + if (status != ATCA_SUCCESS) break; + + currAddress += ATCA_WORD_SIZE; + currBlock = currAddress / ATCA_BLOCK_SIZE; + + if ( prevBlock == currBlock) + currOffset++; + else { + currOffset = 0; + prevBlock = currBlock; + } + + readIdx += ATCA_WORD_SIZE; + } + + } else { + + if (dev_type == ATECC508A || dev_type == ATECC108A ) { + + if (currAddress < slot8_addr) { + dataSlot = currAddress / 36; + currBlock = (currAddress - (dataSlot * 36)) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - (dataSlot * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + currAddress = currAddress - (dataSlot * 36); + } else if (currAddress < slot9_addr) { + dataSlot = 8; + currBlock = (currAddress - slot8_addr) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - slot8_addr) / ATCA_WORD_SIZE; + currAddress = currAddress - slot8_addr; + } else { + dataSlot = (currAddress - slot9_addr) / 72; + currBlock = (currAddress - slot9_addr) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - slot9_addr) / ATCA_WORD_SIZE; + currAddress = currAddress - slot9_addr; + } + + prevBlock = currBlock; + + } else { + + dataSlot = currAddress / ATCA_BLOCK_SIZE; + currBlock = (currAddress - (dataSlot * ATCA_BLOCK_SIZE)) / ATCA_BLOCK_SIZE; + currOffset = (currAddress - (dataSlot * ATCA_BLOCK_SIZE)) / ATCA_WORD_SIZE; + currAddress = currAddress - (dataSlot * ATCA_BLOCK_SIZE); + prevBlock = currBlock; + } + + while ( readIdx < len) { + + status = atcab_read_zone(ATCA_ZONE_DATA, dataSlot, currBlock, currOffset, &data[readIdx], ATCA_WORD_SIZE); + if (status != ATCA_SUCCESS) break; + + currAddress += ATCA_WORD_SIZE; + currBlock = currAddress / ATCA_BLOCK_SIZE; + + if ( prevBlock == currBlock) + currOffset++; + else { + currOffset = 0; + prevBlock = currBlock; + } + + readIdx += ATCA_WORD_SIZE; + } + + } + + return status; +} + + +/** \brief Get a 32 byte MAC from the CryptoAuth device given a key ID and a challenge + * \param[in] mode Controls which fields within the device are used in the message + * \param[in] key_id The key in the CryptoAuth device to use for the MAC + * \param[in] challenge The 32 byte challenge number + * \param[out] digest The response of the MAC command using the given challenge + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_mac( uint8_t mode, uint16_t key_id, const uint8_t* challenge, uint8_t* digest ) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + + // Verify the inputs + if ( challenge == NULL || digest == NULL ) { + status = ATCA_BAD_PARAM; + break; + } + + // build mac command + packet.param1 = mode; + packet.param2 = key_id; + memcpy( &packet.data[0], challenge, 32 ); // a 32-byte challenge + + if ( (status = atMAC( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_MAC); + + if ( (status != atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms(execution_time); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + // check for response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy( digest, &packet.data[ATCA_RSP_DATA_IDX], MAC_SIZE ); + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Compares a MAC response with input values + * \param[in] mode Controls which fields within the device are used in the message + * \param[in] key_id The key in the CryptoAuth device to use for the MAC + * \param[in] challenge The 32 byte challenge number + * \param[in] response The 32 byte mac response number + * \param[in] other_data The 13 byte other data number + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_checkmac( uint8_t mode, uint16_t key_id, const uint8_t *challenge, const uint8_t *response, const uint8_t *other_data) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + + // Verify the inputs + if ( challenge == NULL || response == NULL || other_data == NULL ) { + status = ATCA_BAD_PARAM; + break; + } + + // build checkmac command + packet.param1 = mode; + packet.param2 = key_id; + memcpy( &packet.data[0], challenge, CHECKMAC_CLIENT_CHALLENGE_SIZE ); + memcpy( &packet.data[32], response, CHECKMAC_CLIENT_RESPONSE_SIZE ); + memcpy( &packet.data[64], other_data, CHECKMAC_OTHER_DATA_SIZE ); + + if ( (status = atCheckMAC( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_CHECKMAC); + + if ( (status != atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms( execution_time ); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + // check for response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Initialize SHA-256 calculation engine + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_sha_start(void) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + + // build checkmac command + packet.param1 = SHA_SHA256_START_MASK; + packet.param2 = 0; + + if ( (status = atSHA( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_SHA); + + if ( (status != atcab_wakeup()) != ATCA_SUCCESS ) + break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms( execution_time ); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + // check for response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Adds the message to be digested + * \param[in] length The number of bytes in the Message parameter + * \param[in] message up to 64 bytes of data to be included into the hash operation. + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_sha_update(uint16_t length, const uint8_t *message) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + do { + + // Verify the inputs + if ( message == NULL || length > SHA_BLOCK_SIZE ) { + status = ATCA_BAD_PARAM; + break; + } + + // build checkmac command + packet.param1 = SHA_SHA256_UPDATE_MASK; + packet.param2 = length; + memcpy(&packet.data[0], message, length); + + if ( (status = atSHA( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_SHA); + + if ( (status != atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms( execution_time ); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + // check for response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief The SHA-256 calculation is complete + * \param[out] digest The SHA256 digest that is calculated + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_sha_end(uint8_t *digest, uint16_t length, const uint8_t *message) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + ATCAPacket packet; + uint16_t execution_time = 0; + + if ( length > 63 || digest == NULL ) + return ATCA_BAD_PARAM; + + if ( length > 0 && message == NULL ) + return ATCA_BAD_PARAM; + + do { + + // Verify the inputs + if ( digest == NULL ) { + status = ATCA_BAD_PARAM; + break; + } + + // build SHA command + packet.param1 = SHA_SHA256_END_MASK; + packet.param2 = length; + if ( length > 0 ) + memcpy(&packet.data[0], message, length); + + if ( (status = atSHA( _gCommandObj, &packet )) != ATCA_SUCCESS ) + break; + + execution_time = atGetExecTime( _gCommandObj, CMD_SHA); + + if ( (status != atcab_wakeup()) != ATCA_SUCCESS ) break; + + // send the command + if ( (status = atsend( _gIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) + break; + + // delay the appropriate amount of time for command to execute + atca_delay_ms( execution_time ); + + // receive the response + if ( (status = atreceive( _gIface, packet.data, &(packet.rxsize))) != ATCA_SUCCESS ) + break; + + // Check response size + if (packet.rxsize < 4) { + if (packet.rxsize > 0) + status = ATCA_RX_FAIL; + else + status = ATCA_RX_NO_RESPONSE; + break; + } + + // check for response + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) + break; + + memcpy( digest, &packet.data[ATCA_RSP_DATA_IDX], ATCA_SHA_DIGEST_SIZE ); + + } while (0); + + _atcab_exit(); + return status; +} + +/** \brief Computes a SHA-256 digest + * \param[in] length The number of bytes in the message parameter + * \param[in] message - pointer to variable length message + * \param[out] digest The SHA256 digest + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_sha(uint16_t length, const uint8_t *message, uint8_t *digest) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + int blocks = 0, remainder = 0, msgIndex = 0; + + if ( length == 0 || message == NULL || digest == NULL ) + return ATCA_BAD_PARAM; + + do { + + blocks = length / SHA_BLOCK_SIZE; + remainder = length % SHA_BLOCK_SIZE; + + status = atcab_sha_start(); + if ( status != ATCA_SUCCESS ) + break; + + while ( blocks-- > 0 ) { + status = atcab_sha_update(SHA_BLOCK_SIZE, &message[msgIndex]); + if ( status != ATCA_SUCCESS ) + break; + msgIndex += SHA_BLOCK_SIZE; + } + + status = atcab_sha_end(digest, remainder, &message[msgIndex]); + + if ( status != ATCA_SUCCESS ) + break; + + } while (0); + + return status; +} diff --git a/src/basic/atca_basic.h b/src/basic/atca_basic.h new file mode 100644 index 0000000..741f797 --- /dev/null +++ b/src/basic/atca_basic.h @@ -0,0 +1,137 @@ +/** + * \file + * \brief CryptoAuthLib Basic API methods - a simple crypto authentication api. + * These methods manage a global ATCADevice object behind the scenes. They also + * manage the wake/idle state transitions so callers don't need to. + * + * \copyright Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include "cryptoauthlib.h" + +#ifndef ATCA_BASIC_H_ +#define ATCA_BASIC_H_ + +#define TBD void + +/** \defgroup atcab_ Basic Crypto API methods (atcab_) + * + * \brief + * These methods provide the most convenient, simple API to CryptoAuth chips + * + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +// basic global device object methods +ATCA_STATUS atcab_version( char *verstr ); +ATCA_STATUS atcab_init(ATCAIfaceCfg *cfg); +ATCA_STATUS atcab_init_device(ATCADevice cadevice); +ATCA_STATUS atcab_release(void); +ATCADevice atcab_getDevice(void); + +ATCA_STATUS atcab_wakeup(void); +ATCA_STATUS atcab_idle(void); +ATCA_STATUS atcab_sleep(void); + +// discovery +ATCA_STATUS atcab_cfg_discover( ATCAIfaceCfg cfgArray[], int max); + +// basic crypto API +ATCA_STATUS atcab_info(uint8_t *revision); +ATCA_STATUS atcab_challenge(const uint8_t *challenge); +ATCA_STATUS atcab_challenge_seed_update(const uint8_t *seed, uint8_t* rand_out); +ATCA_STATUS atcab_nonce(const uint8_t *tempkey); +ATCA_STATUS atcab_nonce_rand(const uint8_t *seed, uint8_t* rand_out); +ATCA_STATUS atcab_random(uint8_t *rand_out); + +ATCA_STATUS atcab_is_locked(uint8_t zone, bool *lock_state); +ATCA_STATUS atcab_is_slot_locked(uint8_t slot, bool *lock_state); + +ATCA_STATUS atcab_get_addr(uint8_t zone, uint8_t slot, uint8_t block, uint8_t offset, uint16_t* addr); +ATCA_STATUS atcab_read_zone(uint8_t zone, uint8_t slot, uint8_t block, uint8_t offset, uint8_t *data, uint8_t len); +ATCA_STATUS atcab_write_zone(uint8_t zone, uint8_t slot, uint8_t block, uint8_t offset, const uint8_t *data, uint8_t len); +ATCA_STATUS atcab_write_bytes_slot(uint8_t slot, uint16_t offset, const uint8_t *data, uint8_t len); +ATCA_STATUS atcab_write_bytes_zone(ATCADeviceType dev_type, uint8_t zone, uint16_t address, const uint8_t *data, uint8_t len); +ATCA_STATUS atcab_read_bytes_zone(ATCADeviceType dev_type, uint8_t zone, uint16_t address, uint8_t len, uint8_t *data); + +ATCA_STATUS atcab_read_serial_number(uint8_t* serial_number); +ATCA_STATUS atcab_read_pubkey(uint8_t slot8toF, uint8_t *pubkey); +ATCA_STATUS atcab_write_pubkey(uint8_t slot8toF, uint8_t *pubkey); +ATCA_STATUS atcab_read_sig(uint8_t slot8toF, uint8_t *sig); +ATCA_STATUS atcab_read_ecc_config_zone(uint8_t* config_data); +ATCA_STATUS atcab_write_ecc_config_zone(const uint8_t* config_data); +ATCA_STATUS atcab_read_sha_config_zone( uint8_t* config_data); +ATCA_STATUS atcab_write_sha_config_zone(const uint8_t* config_data); +ATCA_STATUS atcab_read_config_zone(ATCADeviceType dev_type, uint8_t* config_data); +ATCA_STATUS atcab_write_config_zone(ATCADeviceType dev_type, const uint8_t* config_data); +ATCA_STATUS atcab_cmp_config_zone(uint8_t* config_data, bool* same_config); + +ATCA_STATUS atcab_read_enc(uint8_t slotid, uint8_t block, uint8_t *data, const uint8_t* enckey, const uint16_t enckeyid); +ATCA_STATUS atcab_write_enc(uint8_t slotid, uint8_t block, const uint8_t *data, const uint8_t* enckey, const uint16_t enckeyid); + +ATCA_STATUS atcab_lock_config_zone(uint8_t* lock_response); +ATCA_STATUS atcab_lock_data_zone(uint8_t* lock_response); +ATCA_STATUS atcab_lock_data_slot(uint8_t slot, uint8_t* lock_response); + +ATCA_STATUS atcab_priv_write(uint8_t slot, const uint8_t priv_key[36], uint8_t write_key_slot, const uint8_t write_key[32]); +ATCA_STATUS atcab_genkey( int slot, uint8_t *pubkey ); +ATCA_STATUS atcab_get_pubkey(uint8_t privSlotId, uint8_t *pubkey); +ATCA_STATUS atcab_calc_pubkey(uint8_t privSlotId, uint8_t *pubkey); +ATCA_STATUS atcab_sign(uint16_t slot, const uint8_t *msg, uint8_t *signature); +ATCA_STATUS atcab_verify_extern(const uint8_t *message, const uint8_t *signature, const uint8_t *pubkey, bool *verified); +ATCA_STATUS atcab_ecdh(uint16_t key_id, const uint8_t* pub_key, uint8_t* ret_ecdh); +ATCA_STATUS atcab_ecdh_enc(uint16_t slotid, const uint8_t* pubkey, uint8_t* ret_ecdh, const uint8_t* enckey, const uint8_t enckeyid); +ATCA_STATUS atcab_gendig(uint8_t zone, uint16_t key_id); +ATCA_STATUS atcab_gendig_host(uint8_t zone, uint16_t key_id, uint8_t *other_data, uint8_t len); +ATCA_STATUS atcab_mac( uint8_t mode, uint16_t key_id, const uint8_t* challenge, uint8_t* digest ); +ATCA_STATUS atcab_checkmac( uint8_t mode, uint16_t key_id, const uint8_t *challenge, const uint8_t *response, const uint8_t *other_data); + +ATCA_STATUS atcab_sha_start(void); +ATCA_STATUS atcab_sha_update(uint16_t length, const uint8_t *message); +ATCA_STATUS atcab_sha_end(uint8_t *digest, uint16_t length, const uint8_t *message); +ATCA_STATUS atcab_sha(uint16_t length, const uint8_t *message, uint8_t *digest); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ATCA_BASIC_H_ */ \ No newline at end of file diff --git a/src/basic/atca_helpers.c b/src/basic/atca_helpers.c new file mode 100644 index 0000000..3bef654 --- /dev/null +++ b/src/basic/atca_helpers.c @@ -0,0 +1,222 @@ +/** + * \file + * \brief Helpers to support the CryptoAuthLib Basic API methods + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include "atca_helpers.h" +#include + + +#ifdef ATCAPRINTF + +#include + +/** \brief convert a binary buffer to a hex string suitable for human reading + * \param[in] binary input buffer to convert + * \param[in] binLen length of buffer to convert + * \param[out] asciihex buffer that receives hex string + * \param[out] hexlen the length of the asciihex buffer + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_bin2hex(const uint8_t* binary, int binLen, char* asciihex, int* asciihexlen) +{ + return atcab_bin2hex_(binary, binLen, asciihex, asciihexlen, true); +} + +/** \brief convert a binary buffer to a hex string suitable for human reading + * \param[in] inbuff input buffer to convert + * \param[in] inbuffLen length of buffer to convert + * \param[out] asciihex buffer that receives hex string + * \param[inout] asciihexlen the length of the asciihex buffer + * \param[inout] addspace indicates whether spaces and returns should be added for pretty printing + * \return ATCA_STATUS + */ +ATCA_STATUS atcab_bin2hex_(const uint8_t* binary, int binLen, char* asciihex, int* asciihexlen, bool addspace) +{ + int i; + int hexlen = 0; + + // Verify the inputs + if ((binary == NULL) || (asciihex == NULL) || (asciihexlen == NULL)) + return ATCA_BAD_PARAM; + + // Initialize the return bytes to all 0s + memset(asciihex, 0, *asciihexlen); + + // Convert one byte at a time + for (i = 0; i < binLen; i++) { + if (hexlen > *asciihexlen) break; + if ((i % 16 == 0 && i != 0) && addspace) { + sprintf(&asciihex[hexlen], "\r\n"); + hexlen += 2; + } + if (addspace) { + sprintf(&asciihex[hexlen], "%02X ", *binary++); + hexlen += 3; + }else { + sprintf(&asciihex[hexlen], "%02X", *binary++); + hexlen += 2; + } + } + *asciihexlen = (int)strlen(asciihex); + + return ATCA_SUCCESS; +} + +/** \brief convert a binary buffer to a hex string suitable for human reading + * \param[in] inbuff input buffer to convert + * \param[in] inbuffLen length of buffer to convert + * \param[out] outbuff buffer that receives hex string + * \return string length of the output buffer + */ +ATCA_STATUS atcab_hex2bin(const char* asciiHex, int asciiHexLen, uint8_t* binary, int* binLen) +{ + int i = 0; + int j = 0; + uint32_t byt; + char* packedHex = NULL; + int packedLen = asciiHexLen; + char hexByte[3]; + + // Verify the inputs + if ((binary == NULL) || (asciiHex == NULL) || (binLen == NULL)) + return ATCA_BAD_PARAM; + + // Pack the bytes (remove white space & make even number of characters) + packedHex = (char*)malloc(packedLen); + memset(packedHex, 0, packedLen); + packHex(asciiHex, asciiHexLen, packedHex, &packedLen); + + // Initialize the binary buffer to all 0s + memset(binary, 0, *binLen); + memset(hexByte, 0, 3); + + // Convert the ascii bytes to binary + for (i = 0, j = 0; i < packedLen; i += 2, j++) { + if (i > packedLen || j > *binLen) break; + // Copy two characters to be scanned + memcpy(hexByte, &packedHex[i], 2); + sscanf(hexByte, "%x", (unsigned int*)&byt); + // take the msb of the uint32_t + binary[j] = byt; + } + *binLen = j; + free(packedHex); + return ATCA_SUCCESS; +} + +//#else + + +#endif + +#if 0 +/** + * \brief Checks to see if a character is an ASCII representation of a digit ((c ge '0') and (c le '9')) + * \param[in] c character to check + * \return True if the character is a digit + */ +bool isDigit(char c) +{ + return (c >= '0') && (c <= '9'); +} + +/** + * \brief Checks to see if a character is whitespace ((c == '\n') || (c == '\r') || (c == '\t') || (c == ' ')) + * \param[in] c character to check + * \return True if the character is whitespace + */ +bool isWhiteSpace(char c) +{ + return (c == '\n') || (c == '\r') || (c == '\t') || (c == ' '); +} + +/** + * \brief Checks to see if a character is an ASCII representation of hex ((c ge 'A') and (c le 'F')) || ((c ge 'a') and (c le 'f')) + * \param[in] c character to check + * \return True if the character is a hex + */ +bool isHexAlpha(char c) +{ + return ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')); +} + +/** + * \brief Returns true if this character is a valid hex character or if this is whitespace (The character can be + * included in a valid hexstring). + * \param[in] c character to check + * \return True if the character can be included in a valid hexstring + */ +bool isHex(char c) +{ + return isDigit(c) || isWhiteSpace(c) || isHexAlpha(c); +} + +/** + * \brief Returns true if this character is a valid hex character. + * \param[in] c character to check + * \return True if the character can be included in a valid hexstring + */ +bool isHexDigit(char c) +{ + return isDigit(c) || isHexAlpha(c); +} +#endif + +ATCA_STATUS packHex(const char* asciiHex, int asciiHexLen, char* packedHex, int* packedLen) +{ + int i = 0; + int j = 0; + + // Verify the inputs + if ((asciiHex == NULL) || (packedHex == NULL) || (packedLen == NULL)) + return ATCA_BAD_PARAM; + + // Loop through each character and only add the hex characters + for (i = 0; i < asciiHexLen; i++) { + if (isHexDigit(asciiHex[i])) { + if (j > *packedLen) break; + packedHex[j++] = asciiHex[i]; + } + } + // If there are not an even number of characters, then pad with a '0' + + return ATCA_SUCCESS; +} + diff --git a/src/basic/atca_helpers.h b/src/basic/atca_helpers.h new file mode 100644 index 0000000..01ded68 --- /dev/null +++ b/src/basic/atca_helpers.h @@ -0,0 +1,82 @@ +/** + * \file + * \brief Helpers to support the CryptoAuthLib Basic API methods + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_HELPERS_H_ +#define ATCA_HELPERS_H_ + +#include "cryptoauthlib.h" + +/** \defgroup atcab_ Basic Crypto API methods (atcab_) + * + * \brief + * These methods provide the most convenient, simple API to CryptoAuth chips + * + @{ */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ATCAPRINTF +ATCA_STATUS atcab_bin2hex(const uint8_t* binary, int binLen, char* asciiHex, int* asciiHexLen); +ATCA_STATUS atcab_bin2hex_(const uint8_t* binary, int binLen, char* asciiHex, int* asciiHexLen, bool addSpace); +ATCA_STATUS atcab_hex2bin(const char* asciiHex, int asciiHexLen, uint8_t* binary, int* binLen); +#else + +#define atcab_bin2hex + +#endif + +ATCA_STATUS packHex(const char* asciiHex, int asciiHexLen, char* packedHex, int* packedLen); +#if 0 +bool isDigit(char c); +bool isWhiteSpace(char c); +bool isHexAlpha(char c); +bool isHex(char c); +bool isHexDigit(char c); +#endif + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* ATCA_HELPERS_H_ */ diff --git a/src/crypto/README.md b/src/crypto/README.md new file mode 100644 index 0000000..bee8884 --- /dev/null +++ b/src/crypto/README.md @@ -0,0 +1,6 @@ +crypto directory - Purpose +=========================== +This directory contains software implementations of cryptographics functions. The functions at the +base level are wrappers that will point to the final implementations of the software crypto +functions. + diff --git a/src/crypto/atca_crypto_sw.h b/src/crypto/atca_crypto_sw.h new file mode 100644 index 0000000..a7ae29f --- /dev/null +++ b/src/crypto/atca_crypto_sw.h @@ -0,0 +1,47 @@ +/** + * \file + * \brief Common defines for CryptoAuthLib software crypto wrappers. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_CRYPTO_SW_H +#define ATCA_CRYPTO_SW_H + +#include "atca_status.h" + +#endif \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_ecdsa.c b/src/crypto/atca_crypto_sw_ecdsa.c new file mode 100644 index 0000000..ab3258e --- /dev/null +++ b/src/crypto/atca_crypto_sw_ecdsa.c @@ -0,0 +1,58 @@ +/** + * \file + * \brief API wrapper for software ECDSA verify. Currently unimplemented but could be + * implemented via a 3rd party library such as MicroECC. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#include "atca_crypto_sw_ecdsa.h" + +/** \brief return software generated ECDSA verification result + * \param[in] msg ptr to message or challenge + * \param[in] signature ptr to the signature to verify + * \param[in] public_key ptr to public key of device which signed the challenge + * return ATCA_STATUS + */ + +int atcac_sw_ecdsa_verify_p256( const uint8_t msg[ATCA_ECC_P256_FIELD_SIZE], + const uint8_t signature[ATCA_ECC_P256_SIGNATURE_SIZE], + const uint8_t public_key[ATCA_ECC_P256_PUBLIC_KEY_SIZE]) +{ + return ATCA_UNIMPLEMENTED; +} \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_ecdsa.h b/src/crypto/atca_crypto_sw_ecdsa.h new file mode 100644 index 0000000..311b1b9 --- /dev/null +++ b/src/crypto/atca_crypto_sw_ecdsa.h @@ -0,0 +1,76 @@ +/** + * \file + * \brief + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#ifndef ATCA_CRYPTO_SW_ECDSA_H +#define ATCA_CRYPTO_SW_ECDSA_H + +#include "atca_crypto_sw.h" +#include +#include + +/** \defgroup atcac_ Software crypto methods (atcac_) + * + * \brief + * These methods provide a software implementation of various crypto + * algorithms + * + @{ */ + +#define ATCA_ECC_P256_FIELD_SIZE (256 / 8) +#define ATCA_ECC_P256_PRIVATE_KEY_SIZE (ATCA_ECC_P256_FIELD_SIZE) +#define ATCA_ECC_P256_PUBLIC_KEY_SIZE (ATCA_ECC_P256_FIELD_SIZE * 2) +#define ATCA_ECC_P256_SIGNATURE_SIZE (ATCA_ECC_P256_FIELD_SIZE * 2) + +#ifdef __cplusplus +extern "C" { +#endif + +int atcac_sw_ecdsa_verify_p256( const uint8_t msg[ATCA_ECC_P256_FIELD_SIZE], + const uint8_t signature[ATCA_ECC_P256_SIGNATURE_SIZE], + const uint8_t public_key[ATCA_ECC_P256_PUBLIC_KEY_SIZE]); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_rand.c b/src/crypto/atca_crypto_sw_rand.c new file mode 100644 index 0000000..29a49c9 --- /dev/null +++ b/src/crypto/atca_crypto_sw_rand.c @@ -0,0 +1,53 @@ +/** + * \file + * \brief API wrapper for software random + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include "atca_crypto_sw_rand.h" + +/** \brief return software generated random number + * \param[out] data ptr to space to receive the random number + * \param[in] data_size size of data buffer + * return ATCA_STATUS + */ + +int atcac_sw_random(uint8_t* data, size_t data_size) +{ + return ATCA_UNIMPLEMENTED; +} \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_rand.h b/src/crypto/atca_crypto_sw_rand.h new file mode 100644 index 0000000..1f1b964 --- /dev/null +++ b/src/crypto/atca_crypto_sw_rand.h @@ -0,0 +1,67 @@ +/** + * \file + * \brief + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_CRYPTO_SW_RAND_H +#define ATCA_CRYPTO_SW_RAND_H + +#include "atca_crypto_sw.h" +#include +#include + +/** \defgroup atcac_ Software crypto methods (atcac_) + * + * \brief + * These methods provide a software implementation of various crypto + * algorithms + * + @{ */ +#ifdef __cplusplus +extern "C" { +#endif + +int atcac_sw_random(uint8_t* data, size_t data_size); + +#ifdef __cplusplus +} +#endif +/** @} */ + +#endif \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_sha1.c b/src/crypto/atca_crypto_sw_sha1.c new file mode 100644 index 0000000..2b6e081 --- /dev/null +++ b/src/crypto/atca_crypto_sw_sha1.c @@ -0,0 +1,87 @@ +/** + * \file + * \brief Wrapper API for SHA 1 routines + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#include "atca_crypto_sw_sha1.h" +#include "hashes/sha1_routines.h" + +int atcac_sw_sha1_init(atcac_sha1_ctx* ctx) +{ + if (sizeof(CL_HashContext) > sizeof(atcac_sha1_ctx)) + return ATCA_ASSERT_FAILURE; // atcac_sha1_ctx isn't large enough for this implementation + CL_hashInit((CL_HashContext*)ctx); + + return ATCA_SUCCESS; +} + +int atcac_sw_sha1_update(atcac_sha1_ctx* ctx, const uint8_t* data, size_t data_size) +{ + CL_hashUpdate((CL_HashContext*)ctx, data, (int)data_size); + + return ATCA_SUCCESS; +} + +int atcac_sw_sha1_finish(atcac_sha1_ctx* ctx, uint8_t digest[ATCA_SHA1_DIGEST_SIZE]) +{ + CL_hashFinal((CL_HashContext*)ctx, digest); + + return ATCA_SUCCESS; +} + +int atcac_sw_sha1(const uint8_t* data, size_t data_size, uint8_t digest[ATCA_SHA1_DIGEST_SIZE]) +{ + int ret; + atcac_sha1_ctx ctx; + + ret = atcac_sw_sha1_init(&ctx); + if (ret != ATCA_SUCCESS) + return ret; + + ret = atcac_sw_sha1_update(&ctx, data, data_size); + if (ret != ATCA_SUCCESS) + return ret; + + ret = atcac_sw_sha1_finish(&ctx, digest); + if (ret != ATCA_SUCCESS) + return ret; + + return ATCA_SUCCESS; +} \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_sha1.h b/src/crypto/atca_crypto_sw_sha1.h new file mode 100644 index 0000000..e2991f4 --- /dev/null +++ b/src/crypto/atca_crypto_sw_sha1.h @@ -0,0 +1,77 @@ +/** + * \file + * \brief Wrapper API for SHA 1 routines + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_CRYPTO_SW_SHA1_H +#define ATCA_CRYPTO_SW_SHA1_H + +#include "atca_crypto_sw.h" +#include +#include + +/** \defgroup atcac_ Software crypto methods (atcac_) + * + * \brief + * These methods provide a software implementation of various crypto + * algorithms + * + @{ */ + +#define ATCA_SHA1_DIGEST_SIZE (20) + +typedef struct { + uint32_t pad[32]; //!< Filler value to make sure the actual implementation has enough room to store its context. uint32_t is used to remove some alignment warnings. +} atcac_sha1_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +int atcac_sw_sha1_init(atcac_sha1_ctx* ctx); +int atcac_sw_sha1_update(atcac_sha1_ctx* ctx, const uint8_t* data, size_t data_size); +int atcac_sw_sha1_finish(atcac_sha1_ctx * ctx, uint8_t digest[ATCA_SHA1_DIGEST_SIZE]); +int atcac_sw_sha1(const uint8_t * data, size_t data_size, uint8_t digest[ATCA_SHA1_DIGEST_SIZE]); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_sha2.c b/src/crypto/atca_crypto_sw_sha2.c new file mode 100644 index 0000000..6ad7e23 --- /dev/null +++ b/src/crypto/atca_crypto_sw_sha2.c @@ -0,0 +1,113 @@ +/** + * \file + * \brief Wrapper API for software SHA 256 routines + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include "atca_crypto_sw_sha2.h" +#include "hashes/sha2_routines.h" + +/** \brief initializes the SHA256 software + * \param[in] ctx ptr to context data structure + * \return ATCA_STATUS value + */ + +int atcac_sw_sha2_256_init(atcac_sha2_256_ctx* ctx) +{ + if (sizeof(sw_sha256_ctx) > sizeof(atcac_sha2_256_ctx)) + return ATCA_ASSERT_FAILURE; // atcac_sha1_ctx isn't large enough for this implementation + sw_sha256_init((sw_sha256_ctx*)ctx); + + return ATCA_SUCCESS; +} + +/** \brief updates the running hash with the next block of data, called iteratively for the entire + stream of data to be hashed + \param[in] ctx ptr to SHA context data structure + \param[in] data ptr to next block of data to hash + \param[in] data_size size amount of data to hash in the given block, in bytes + \return ATCA_STATUS + */ + +int atcac_sw_sha2_256_update(atcac_sha2_256_ctx* ctx, const uint8_t* data, size_t data_size) +{ + sw_sha256_update((sw_sha256_ctx*)ctx, data, (uint32_t)data_size); + + return ATCA_SUCCESS; +} + +/** \brief completes the final SHA calculation and returns the final digest/hash + * \param[in] ctx ptr to context data structure + * \param[out] digest receives the computed digest of the SHA 256 has + * \return ATCA_STATUS + */ + +int atcac_sw_sha2_256_finish(atcac_sha2_256_ctx* ctx, uint8_t digest[ATCA_SHA2_256_DIGEST_SIZE]) +{ + sw_sha256_final((sw_sha256_ctx*)ctx, digest); + + return ATCA_SUCCESS; +} + + +/** \brief single call convenience function to comput SHA256 of given data + * \param[in] data pointer to stream of data to hash + * \param[in] data_size size of data stream to hash + * \param[out] digest result + * \return ATCA_STATUS + */ + +int atcac_sw_sha2_256(const uint8_t* data, size_t data_size, uint8_t digest[ATCA_SHA2_256_DIGEST_SIZE]) +{ + int ret; + atcac_sha2_256_ctx ctx; + + ret = atcac_sw_sha2_256_init(&ctx); + if (ret != ATCA_SUCCESS) + return ret; + + ret = atcac_sw_sha2_256_update(&ctx, data, data_size); + if (ret != ATCA_SUCCESS) + return ret; + + ret = atcac_sw_sha2_256_finish(&ctx, digest); + if (ret != ATCA_SUCCESS) + return ret; + + return ATCA_SUCCESS; +} \ No newline at end of file diff --git a/src/crypto/atca_crypto_sw_sha2.h b/src/crypto/atca_crypto_sw_sha2.h new file mode 100644 index 0000000..8b9afa0 --- /dev/null +++ b/src/crypto/atca_crypto_sw_sha2.h @@ -0,0 +1,77 @@ +/** + * \file + * \brief Wrapper API for software SHA 256 routines + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef ATCA_CRYPTO_SW_SHA2_H +#define ATCA_CRYPTO_SW_SHA2_H + +#include "atca_crypto_sw.h" +#include +#include + +/** \defgroup atcac_ Software crypto methods (atcac_) + * + * \brief + * These methods provide a software implementation of various crypto + * algorithms + * + @{ */ + +#define ATCA_SHA2_256_DIGEST_SIZE (32) + +typedef struct { + uint32_t pad[48]; //!< Filler value to make sure the actual implementation has enough room to store its context. uint32_t is used to remove some alignment warnings. +} atcac_sha2_256_ctx; + +#ifdef __cplusplus +extern "C" { +#endif + +int atcac_sw_sha2_256_init(atcac_sha2_256_ctx* ctx); +int atcac_sw_sha2_256_update(atcac_sha2_256_ctx* ctx, const uint8_t* data, size_t data_size); +int atcac_sw_sha2_256_finish(atcac_sha2_256_ctx * ctx, uint8_t digest[ATCA_SHA2_256_DIGEST_SIZE]); +int atcac_sw_sha2_256(const uint8_t * data, size_t data_size, uint8_t digest[ATCA_SHA2_256_DIGEST_SIZE]); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif \ No newline at end of file diff --git a/src/crypto/hashes/sha1_routines.c b/src/crypto/hashes/sha1_routines.c new file mode 100644 index 0000000..d281d90 --- /dev/null +++ b/src/crypto/hashes/sha1_routines.c @@ -0,0 +1,295 @@ +/** + * \file + * \brief Software implementation of the SHA1 algorithm. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include "sha1_routines.h" +#include + +void CL_hashInit(CL_HashContext *ctx) +{ + static const U32 hashContext_h_init[] = { + 0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476, + 0xc3d2e1f0 + }; + + // Initialize context + memset(ctx, 0, sizeof(*ctx)); + memcpy_P(ctx->h, hashContext_h_init, sizeof(ctx->h)); +} + +void CL_hashUpdate(CL_HashContext *ctx, const U8 *src, int nbytes) +{ + + /* + Digest src bytes, updating context. + */ + + U8 i, freeBytes; + U32 temp32; + + typedef struct { + U8 buf[64]; + } Buf64; + + // We are counting on the fact that Buf64 is 64 bytes long. In + // principle the compiler may make Buf64 bigger 64 bytes, but this + // seems unlikely. Add an assertion check to be sure. Beware that + // assert may not be active in release versions. + // + //assert(sizeof(Buf64) == 64); + + // Get number of free bytes in the buf + freeBytes = (U8)(ctx->byteCount); + freeBytes &= 63; + freeBytes = (U8)(64 - freeBytes); + + while (nbytes > 0) { + + // Get i, number of bytes to transfer from src + i = freeBytes; + if (nbytes < i) i = (U8)nbytes; + + // Copy src bytes to buf + if (i == 64) + // This seems to be much faster on IAR than memcpy(). + *(Buf64*)(ctx->buf) = *(Buf64*)src; + else + // Have to use memcpy, size is other than 64 bytes. + memcpy(((U8*)ctx->buf) + 64 - freeBytes, src, i); + + // Adjust for transferred bytes + src += i; + nbytes -= i; + freeBytes -= i; + + // Do SHA crunch if buf is full + if (freeBytes == 0) + shaEngine(ctx->buf, ctx->h); + + // Update 64-bit byte count + temp32 = (ctx->byteCount += i); + if (temp32 == 0) ++ctx->byteCountHi; + + // Set up for next iteration + freeBytes = 64; + } +} + +void CL_hashFinal(CL_HashContext *ctx, U8 *dest) +{ + + /* + Finish a hash calculation and put result in dest. + */ + + U8 i; + U8 nbytes; + U32 temp; + U8 *ptr; + + /* Append pad byte, clear trailing bytes */ + nbytes = (U8)(ctx->byteCount) & 63; + ((U8*)ctx->buf)[nbytes] = 0x80; + for (i = (nbytes + 1); i < 64; i++) ((U8*)ctx->buf)[i] = 0; + + /* + If no room for an 8-byte count at end of buf, digest the buf, + then clear it + */ + if (nbytes > (64 - 9)) { + shaEngine(ctx->buf, ctx->h); + memset(ctx->buf, 0, 64); + } + + /* + Put the 8-byte bit count at end of buf. We have been tracking + bytes, not bits, so we left-shift our byte count by 3 as we do + this. + */ + temp = ctx->byteCount << 3; // low 4 bytes of bit count + ptr = &((U8*)ctx->buf)[63]; // point to low byte of bit count + for (i = 0; i < 4; i++) { + *ptr-- = (U8)temp; + temp >>= 8; + } + // + temp = ctx->byteCountHi << 3; + temp |= ctx->byteCount >> (32 - 3); // high 4 bytes of bit count + for (i = 0; i < 4; i++) { + *ptr-- = (U8)temp; + temp >>= 8; + } + //show("final SHA crunch", ctx->buf, 64); + + /* Final digestion */ + shaEngine(ctx->buf, ctx->h); + + /* Unpack chaining variables to dest bytes. */ + memcpy(dest, ctx->h, 20); + for (i = 0; i < 5; i++) { + dest[i * 4 + 0] = (ctx->h[i] >> 24) & 0xFF; + dest[i * 4 + 1] = (ctx->h[i] >> 16) & 0xFF; + dest[i * 4 + 2] = (ctx->h[i] >> 8) & 0xFF; + dest[i * 4 + 3] = (ctx->h[i] >> 0) & 0xFF; + } +} + + +void CL_hash(U8 *msg, int msgBytes, U8 *dest) +{ + CL_HashContext ctx; + + CL_hashInit(&ctx); + CL_hashUpdate(&ctx, msg, msgBytes); + CL_hashFinal(&ctx, dest); +} + +void shaEngine(U32 *buf, U32 *h) +{ + + /* + SHA-1 Engine. From FIPS 180. + + On entry, buf[64] contains the 64 bytes to digest. These bytes + are destroyed. + + _H[20] contains the 5 chaining variables. They must have the + proper value on entry and are updated on exit. + + The order of bytes in buf[] and _h[] matches that used by the + hardware SHA engine. + */ + + U8 t; + U32 a, b, c, d, e; + U32 temp = 0; + U8 *p; + U32 *w = (U32*)buf; + + /* + Pack first 64 bytes of buf into w[0,...,15]. Within a word, + bytes are big-endian. Do this in place -- buf[0,...,63] + overlays w[0,...,15]. + */ + p = (U8*)w; + for (t = 0; t < 16; t++) { + temp = (temp << 8) | *p++; + temp = (temp << 8) | *p++; + temp = (temp << 8) | *p++; + temp = (temp << 8) | *p++; + w[t] = temp; + } + + /* + Pack the 20 bytes of _h[] into h[0,...,4]. Do in place using + same convention as for buidling w[]. + */ + //p = (U8*)h; + //for (t = 0; t < 5; t++) { + //temp = (temp << 8) | *p++; + //temp = (temp << 8) | *p++; + //temp = (temp << 8) | *p++; + //temp = (temp << 8) | *p++; + //h[t] = temp; + //} + + /* Copy the chaining variables to a, b, c, d, e */ + a = h[0]; + b = h[1]; + c = h[2]; + d = h[3]; + e = h[4]; + + /* Now do the 80 rounds */ + for (t = 0; t < 80; t++) { + + temp = a; + leftRotate(temp, 5); + temp += e; + temp += w[t & 0xf]; + + if (t < 20) { + temp += (b & c) | (~b & d); + temp += 0x5a827999L; + }else if (t < 40) { + temp += b ^ c ^ d; + temp += 0x6ed9eba1L; + }else if (t < 60) { + temp += (b & c) | (b & d) | (c & d); + temp += 0x8f1bbcdcL; + }else { + temp += b ^ c ^ d; + temp += 0xca62c1d6L; + } + + e = d; + d = c; + c = b; leftRotate(c, 30); + b = a; + a = temp; + + temp = w[t & 0xf] ^ w[(t - 3) & 0xf] ^ w[(t - 8) & 0xf] ^ w[(t - 14) & 0xf]; + leftRotate(temp, 1); + w[t & 0xf] = temp; + + } + + /* Update the chaining variables */ + h[0] += a; + h[1] += b; + h[2] += c; + h[3] += d; + h[4] += e; + + /* Unpack the chaining variables into _h[] buffer. */ + //p = (U8*)h; + //for (t = 0; t < 5; t++) { + //temp = h[t]; + //p[3] = (U8)temp; temp >>= 8; + //p[2] = (U8)temp; temp >>= 8; + //p[1] = (U8)temp; temp >>= 8; + //p[0] = (U8)temp; + //p += 4; + //} + +} \ No newline at end of file diff --git a/src/crypto/hashes/sha1_routines.h b/src/crypto/hashes/sha1_routines.h new file mode 100644 index 0000000..9d096b3 --- /dev/null +++ b/src/crypto/hashes/sha1_routines.h @@ -0,0 +1,99 @@ +/** + * \file + * \brief Software implementation of the SHA1 algorithm. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef __SHA1_ROUTINES_DOT_H__ +#define __SHA1_ROUTINES_DOT_H__ + +#include +#include +#include + +#ifdef WIN32 +#include +#include +#endif + +#include + + +#ifndef U8 +#define U8 uint8_t +#endif + +#ifndef U16 +#define U16 uint16_t +#endif + +#ifndef U32 +#define U32 uint32_t +#endif + + +#ifndef memcpy_P +#define memcpy_P memmove +#endif + +#ifndef strcpy_P +#define strcpy_P strcpy +#endif + +#ifndef _WDRESET +#define _WDRESET() +#define _NOP() +#endif + +typedef struct { + U32 h[20 / 4]; // Ensure it's word aligned + U32 buf[64 / 4]; // Ensure it's word aligned + U32 byteCount; + U32 byteCountHi; +} CL_HashContext; + +#define leftRotate(x, n) (x) = (((x) << (n)) | ((x) >> (32 - (n)))) + +void shaEngine(U32 *buf, U32 *h); +void CL_hashInit(CL_HashContext *ctx); +void CL_hashUpdate(CL_HashContext *ctx, const U8 *src, int nbytes); +void CL_hashFinal(CL_HashContext *ctx, U8 *dest); +void CL_hash(U8 *msg, int msgBytes, U8 *dest); + +#endif // __SHA1_ROUTINES_DOT_H__ + diff --git a/src/crypto/hashes/sha2_routines.c b/src/crypto/hashes/sha2_routines.c new file mode 100644 index 0000000..aee7399 --- /dev/null +++ b/src/crypto/hashes/sha2_routines.c @@ -0,0 +1,228 @@ +/** + * \file + * \brief Software implementation of the SHA256 algorithm. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include +#include "sha2_routines.h" + +#define rotate_right(value, places) ((value >> places) | (value << (32 - places))) + +/** + * \brief Processes whole blocks (64 bytes) of data. + * + * \param[in] ctx SAH256 hash context + * \param[in] blocks Raw blocks to be processed + * \param[in] block_count Number of 64-byte blocks to process + */ +static void sw_sha256_process(sw_sha256_ctx* ctx, const uint8_t* blocks, uint32_t block_count) +{ + int i = 0; + uint32_t block = 0; + + union { + uint32_t w_word[SHA256_BLOCK_SIZE]; + uint8_t w_byte[SHA256_BLOCK_SIZE * sizeof(uint32_t)]; + } w_union; + + static const uint32_t k[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + // Loop through all the blocks to process + for (block = 0; block < block_count; block++) { + uint32_t w_index; + uint32_t word_value; + uint32_t s0, s1; + uint32_t t1, t2; + uint32_t maj, ch; + uint32_t rotate_register[8]; + const uint8_t* cur_msg_block = &blocks[block * SHA256_BLOCK_SIZE]; + + // Swap word bytes + for (i = 0; i < SHA256_BLOCK_SIZE; i += 4) { + w_union.w_byte[i + 3] = cur_msg_block[i + 0]; + w_union.w_byte[i + 2] = cur_msg_block[i + 1]; + w_union.w_byte[i + 1] = cur_msg_block[i + 2]; + w_union.w_byte[i + 0] = cur_msg_block[i + 3]; + } + + w_index = 16; + while (w_index < SHA256_BLOCK_SIZE) { + // right rotate for 32-bit variable in C: (value >> places) | (value << 32 - places) + word_value = w_union.w_word[w_index - 15]; + s0 = rotate_right(word_value, 7) ^ rotate_right(word_value, 18) ^ (word_value >> 3); + + word_value = w_union.w_word[w_index - 2]; + s1 = rotate_right(word_value, 17) ^ rotate_right(word_value, 19) ^ (word_value >> 10); + + w_union.w_word[w_index] = w_union.w_word[w_index - 16] + s0 + w_union.w_word[w_index - 7] + s1; + + w_index++; + } + + // Initialize hash value for this chunk. + for (i = 0; i < 8; i++) + rotate_register[i] = ctx->hash[i]; + + // hash calculation loop + for (i = 0; i < SHA256_BLOCK_SIZE; i++) { + s0 = rotate_right(rotate_register[0], 2) + ^ rotate_right(rotate_register[0], 13) + ^ rotate_right(rotate_register[0], 22); + maj = (rotate_register[0] & rotate_register[1]) + ^ (rotate_register[0] & rotate_register[2]) + ^ (rotate_register[1] & rotate_register[2]); + t2 = s0 + maj; + s1 = rotate_right(rotate_register[4], 6) + ^ rotate_right(rotate_register[4], 11) + ^ rotate_right(rotate_register[4], 25); + ch = (rotate_register[4] & rotate_register[5]) + ^ (~rotate_register[4] & rotate_register[6]); + t1 = rotate_register[7] + s1 + ch + k[i] + w_union.w_word[i]; + + rotate_register[7] = rotate_register[6]; + rotate_register[6] = rotate_register[5]; + rotate_register[5] = rotate_register[4]; + rotate_register[4] = rotate_register[3] + t1; + rotate_register[3] = rotate_register[2]; + rotate_register[2] = rotate_register[1]; + rotate_register[1] = rotate_register[0]; + rotate_register[0] = t1 + t2; + } + + // Add the hash of this block to current result. + for (i = 0; i < 8; i++) + ctx->hash[i] += rotate_register[i]; + } +} + +void sw_sha256_init(sw_sha256_ctx* ctx) +{ + static const uint32_t hash_init[] = { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + }; + int i; + + memset(ctx, 0, sizeof(*ctx)); + for (i = 0; i < 8; i++) + ctx->hash[i] = hash_init[i]; +} + +void sw_sha256_update(sw_sha256_ctx* ctx, const uint8_t* msg, uint32_t msg_size) +{ + uint32_t block_count; + uint32_t rem_size = SHA256_BLOCK_SIZE - ctx->block_size; + uint32_t copy_size = msg_size > rem_size ? rem_size : msg_size; + + // Copy data into current block + memcpy(&ctx->block[ctx->block_size], msg, copy_size); + + if (ctx->block_size + msg_size < SHA256_BLOCK_SIZE) { + // Not enough data to finish off the current block + ctx->block_size += msg_size; + return; + } + + // Process the current block + sw_sha256_process(ctx, ctx->block, 1); + + // Process any additional blocks + msg_size -= copy_size; // Adjust to the remaining message bytes + block_count = msg_size / SHA256_BLOCK_SIZE; + sw_sha256_process(ctx, &msg[copy_size], block_count); + + // Save any remaining data + ctx->total_msg_size += (block_count + 1) * SHA256_BLOCK_SIZE; + ctx->block_size = msg_size % SHA256_BLOCK_SIZE; + memcpy(ctx->block, &msg[copy_size + block_count * SHA256_BLOCK_SIZE], ctx->block_size); +} + +void sw_sha256_final(sw_sha256_ctx* ctx, uint8_t digest[SHA256_DIGEST_SIZE]) +{ + int i, j; + uint32_t msg_size_bits; + uint32_t pad_zero_count; + + // Calculate the total message size in bits + ctx->total_msg_size += ctx->block_size; + msg_size_bits = ctx->total_msg_size * 8; + + // Calculate the number of padding zero bytes required between the 1 bit byte and the 64 bit message size in bits. + pad_zero_count = (SHA256_BLOCK_SIZE - ((ctx->block_size + 9) % SHA256_BLOCK_SIZE)) % SHA256_BLOCK_SIZE; + + // Append a single 1 bit + ctx->block[ctx->block_size++] = 0x80; + + // Add padding zeros plus upper 4 bytes of total msg size in bits (only supporting 32bit message bit counts) + memset(&ctx->block[ctx->block_size], 0, pad_zero_count + 4); + ctx->block_size += pad_zero_count + 4; + + // Add the total message size in bits to the end of the current block. Technically this is + // supposed to be 8 bytes. This shortcut will reduce the max message size to 536,870,911 bytes. + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 24); + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 16); + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 8); + ctx->block[ctx->block_size++] = (uint8_t)(msg_size_bits >> 0); + + sw_sha256_process(ctx, ctx->block, ctx->block_size / SHA256_BLOCK_SIZE); + + // All blocks have been processed. + // Concatenate the hashes to produce digest, MSB of every hash first. + for (i = 0; i < 8; i++) + for (j = sizeof(int32_t) - 1; j >= 0; j--, ctx->hash[i] >>= 8) + digest[i * sizeof(int32_t) + j] = ctx->hash[i] & 0xFF; +} + +void sw_sha256(const uint8_t* message, unsigned int len, uint8_t digest[SHA256_DIGEST_SIZE]) +{ + sw_sha256_ctx ctx; + + sw_sha256_init(&ctx); + sw_sha256_update(&ctx, message, len); + sw_sha256_final(&ctx, digest); +} \ No newline at end of file diff --git a/src/crypto/hashes/sha2_routines.h b/src/crypto/hashes/sha2_routines.h new file mode 100644 index 0000000..eb7f7b9 --- /dev/null +++ b/src/crypto/hashes/sha2_routines.h @@ -0,0 +1,74 @@ +/** + * \file + * \brief Software implementation of the SHA256 algorithm. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#ifndef SHA2_ROUTINES_H +#define SHA2_ROUTINES_H + +#include + +#define SHA256_DIGEST_SIZE (32) +#define SHA256_BLOCK_SIZE (64) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint32_t total_msg_size; //!< Total number of message bytes processed + uint32_t block_size; //!< Number of bytes in current block + uint8_t block[SHA256_BLOCK_SIZE * 2]; //!< Unprocessed message storage + uint32_t hash[8]; //!< Hash state +} sw_sha256_ctx; + +void sw_sha256_init(sw_sha256_ctx* ctx); + +void sw_sha256_update(sw_sha256_ctx* ctx, const uint8_t* message, uint32_t len); + +void sw_sha256_final(sw_sha256_ctx * ctx, uint8_t digest[SHA256_DIGEST_SIZE]); + +void sw_sha256(const uint8_t * message, unsigned int len, uint8_t digest[SHA256_DIGEST_SIZE]); + +#ifdef __cplusplus +} +#endif + +#endif // SHA2_ROUTINES_H + diff --git a/src/hal/atca_hal.c b/src/hal/atca_hal.c new file mode 100644 index 0000000..0c2f57b --- /dev/null +++ b/src/hal/atca_hal.c @@ -0,0 +1,179 @@ +/** + * \file + * \brief low-level HAL - methods used to setup indirection to physical layer interface. + * this level does the dirty work of abstracting the higher level ATCAIFace methods from the + * low-level physical interfaces. Its main goal is to keep low-level details from bleeding into + * the logical interface implemetation. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +/* when incorporating ATCA HAL into your application, you need to adjust the #defines in atca_hal.h to include + * and exclude appropriate interfaces - this optimizes memory use when not using a specific iface implementation in your application */ + +#include "cryptoauthlib.h" +#include "atca_hal.h" + +/** \brief Standard HAL API for ATCA to initialize a physical interface + * \param[in] cfg pointer to ATCAIfaceCfg object + * \param[in] hal pointer to ATCAHAL_t intermediate datastructure + */ + +ATCA_STATUS hal_iface_init( ATCAIfaceCfg *cfg, ATCAHAL_t *hal ) +{ + // Because C isn't a real object oriented language or dynamically typed, some switch in the overall system is unavoidable + // The key here is to provide the flexibility to include just the types of interfaces you want/need without breaking the + // object model. The former is needed so in an embedded, constrained memory environment, you don't have to pay the price + // (in terms of memory) for interfaces you don't use in your application. + ATCA_STATUS status = ATCA_COMM_FAIL; + + switch (cfg->iface_type) { + case ATCA_I2C_IFACE: + #ifdef ATCA_HAL_I2C + hal->halinit = &hal_i2c_init; + hal->halpostinit = &hal_i2c_post_init; + hal->halreceive = &hal_i2c_receive; + hal->halsend = &hal_i2c_send; + hal->halsleep = &hal_i2c_sleep; + hal->halwake = &hal_i2c_wake; + hal->halidle = &hal_i2c_idle; + hal->halrelease = &hal_i2c_release; + hal->hal_data = NULL; + + status = ATCA_SUCCESS; + #endif + break; + case ATCA_SWI_IFACE: + #ifdef ATCA_HAL_SWI + hal->halinit = &hal_swi_init; + hal->halpostinit = &hal_swi_post_init; + hal->halreceive = &hal_swi_receive; + hal->halsend = &hal_swi_send; + hal->halsleep = &hal_swi_sleep; + hal->halwake = &hal_swi_wake; + hal->halidle = &hal_swi_idle; + hal->halrelease = &hal_swi_release; + hal->hal_data = NULL; + + status = ATCA_SUCCESS; + #endif + break; + case ATCA_UART_IFACE: + #ifdef ATCA_HAL_UART + // TODO - initialize UART iface + #endif + #ifdef ATCA_HAL_KIT_CDC + hal->halinit = &hal_kit_cdc_init; + hal->halpostinit = &hal_kit_cdc_post_init; + hal->halreceive = &hal_kit_cdc_receive; + hal->halsend = &hal_kit_cdc_send; + hal->halsleep = &hal_kit_cdc_sleep; + hal->halwake = &hal_kit_cdc_wake; + hal->halidle = &hal_kit_cdc_idle; + hal->halrelease = &hal_kit_cdc_release; + hal->hal_data = NULL; + + status = ATCA_SUCCESS; + #endif + break; + case ATCA_SPI_IFACE: + #ifdef ATCA_HAL_SPI + // TODO - initialize SPI iface + #endif + break; + case ATCA_HID_IFACE: + #ifdef ATCA_HAL_KIT_HID + hal->halinit = &hal_kit_hid_init; + hal->halpostinit = &hal_kit_hid_post_init; + hal->halreceive = &hal_kit_hid_receive; + hal->halsend = &hal_kit_hid_send; + hal->halsleep = &hal_kit_hid_sleep; + hal->halwake = &hal_kit_hid_wake; + hal->halidle = &hal_kit_hid_idle; + hal->halrelease = &hal_kit_hid_release; + hal->hal_data = NULL; + + status = ATCA_SUCCESS; + #endif + break; + } + return status; +} + +/** \brief releases a physical interface, HAL knows how to interpret hal_data + * \param[in] ifacetype - the type of physical interface to release + * \param[in] hal_data - pointer to opaque hal data maintained by HAL implementation for this interface type + */ + +ATCA_STATUS hal_iface_release( ATCAIfaceType ifacetype, void *hal_data ) +{ + ATCA_STATUS status = ATCA_GEN_FAIL; + + switch (ifacetype) { + case ATCA_I2C_IFACE: + #ifdef ATCA_HAL_I2C + status = hal_i2c_release(hal_data); + #endif + break; + case ATCA_SWI_IFACE: + #ifdef ATCA_HAL_SWI + status = hal_swi_release(hal_data); + #endif + break; + case ATCA_UART_IFACE: + #ifdef ATCA_HAL_UART + // TODO - release HAL UART + #endif + #ifdef ATCA_HAL_KIT_CDC + status = hal_kit_cdc_release(hal_data); + #endif + break; + case ATCA_SPI_IFACE: + #ifdef ATCA_HAL_SPI + // TODO - release HAL SPI + #endif + break; + case ATCA_HID_IFACE: + #ifdef ATCA_HAL_KIT_HID + status = hal_kit_hid_release(hal_data); + #endif + break; + } + + return status; +} diff --git a/src/hal/atca_hal.h b/src/hal/atca_hal.h new file mode 100644 index 0000000..c7398e6 --- /dev/null +++ b/src/hal/atca_hal.h @@ -0,0 +1,177 @@ +/** + * \file + * \brief low-level HAL - methods used to setup indirection to physical layer interface + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#ifndef ATCA_HAL_H_ +#define ATCA_HAL_H_ + +#include "atca_status.h" +#include "atca_iface.h" +#include "atca_start_config.h" +#include "atca_start_iface.h" + +/** \defgroup hal_ Hardware abstraction layer (hal_) + * + * \brief + * These methods define the hardware abstraction layer for communicating with a CryptoAuth device + * + @{ */ + +/** \brief an intermediary data structure to allow the HAL layer to point the standard API functions + used by the upper layers to the HAL implementation for the interface. This isolates the upper layers + and loosely couples the ATCAIface object from the physical implementation. + */ + +typedef struct { + // interface is a group of function pointers to a specific HAL implementation for this interface type + // so these function pointers are initialized in the HAL layer in order to help keep the ATCAIface object + // from needing to know the low-level details, including global naming of HAL methods and physical implementation. + ATCA_STATUS (*halinit)(void *hal, ATCAIfaceCfg *cfg); + ATCA_STATUS (*halpostinit)(ATCAIface iface); + ATCA_STATUS (*halsend)(ATCAIface iface, uint8_t *txdata, int txlength); + ATCA_STATUS (*halreceive)(ATCAIface iface, uint8_t* rxdata, uint16_t* rxlength); + ATCA_STATUS (*halwake)(ATCAIface iface); + ATCA_STATUS (*halidle)(ATCAIface iface); + ATCA_STATUS (*halsleep)(ATCAIface iface); + ATCA_STATUS (*halrelease)(void* hal_data); + + void *hal_data; // points to whatever the HAL implementation for this interface wants it to, HAL manages. +} ATCAHAL_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern ATCA_STATUS hal_iface_init(ATCAIfaceCfg *, ATCAHAL_t* hal); +extern ATCA_STATUS hal_iface_release(ATCAIfaceType, void* hal_data); + +// Added one or more of the following defines to your compiler's defines to include add support for +// that particular interface in your application. For example, if you're writing an I2C to SWI +// bridge, add both ATCA_HAL_I2C and ATCA_HAL_SWI defines to your compiler settings and then +// include implementations for both interfaces in the HAL. + +// At least one of these symbols will be defined in the project or makefile for each application +//#define ATCA_HAL_I2C +//#define ATCA_HAL_SWI +//#define ATCA_HAL_SPI +//#define ATCA_HAL_UART +//#define ATCA_HAL_KIT_HID +//#define ATCA_HAL_KIT_CDC + +// forward declare known physical layer APIs that must be implemented by the HAL layer (./hal/xyz) for this interface type + +#ifdef ATCA_HAL_I2C +ATCA_STATUS hal_i2c_init( void *hal, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_i2c_post_init(ATCAIface iface); +ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength); +ATCA_STATUS hal_i2c_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_i2c_wake(ATCAIface iface); +ATCA_STATUS hal_i2c_idle(ATCAIface iface); +ATCA_STATUS hal_i2c_sleep(ATCAIface iface); +ATCA_STATUS hal_i2c_release(void *hal_data ); +ATCA_STATUS hal_i2c_discover_buses(int i2c_buses[], int max_buses); +ATCA_STATUS hal_i2c_discover_devices(int busNum, ATCAIfaceCfg *cfg, int *found ); +#endif + +#ifdef ATCA_HAL_SWI +ATCA_STATUS hal_swi_init(void *hal, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_swi_post_init(ATCAIface iface); +ATCA_STATUS hal_swi_send(ATCAIface iface, uint8_t *txdata, int txlength); +ATCA_STATUS hal_swi_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_swi_wake(ATCAIface iface); +ATCA_STATUS hal_swi_idle(ATCAIface iface); +ATCA_STATUS hal_swi_sleep(ATCAIface iface); +ATCA_STATUS hal_swi_release(void *hal_data ); +ATCA_STATUS hal_swi_discover_buses(int swi_buses[], int max_buses); +ATCA_STATUS hal_swi_discover_devices(int busNum, ATCAIfaceCfg *cfg, int *found); +#endif + +#ifdef ATCA_HAL_UART +ATCA_STATUS hal_uart_init(void *hal, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_uart_post_init(ATCAIface iface); +ATCA_STATUS hal_uart_send(ATCAIface iface, uint8_t *txdata, int txlength); +ATCA_STATUS hal_uart_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_uart_wake(ATCAIface iface); +ATCA_STATUS hal_uart_idle(ATCAIface iface); +ATCA_STATUS hal_uart_sleep(ATCAIface iface); +ATCA_STATUS hal_uart_release(ATCAIface iface); +ATCA_STATUS hal_uart_discover_buses(int uart_buses[], int max_buses); +ATCA_STATUS hal_uart_discover_devices(int busNum, ATCAIfaceCfg *cfg, int *found); +#endif + +#ifdef ATCA_HAL_KIT_CDC +ATCA_STATUS hal_kit_cdc_init(void *hal, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_kit_cdc_post_init(ATCAIface iface); +ATCA_STATUS hal_kit_cdc_send(ATCAIface iface, uint8_t *txdata, int txlength); +ATCA_STATUS hal_kit_cdc_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_kit_cdc_wake(ATCAIface iface); +ATCA_STATUS hal_kit_cdc_idle(ATCAIface iface); +ATCA_STATUS hal_kit_cdc_sleep(ATCAIface iface); +ATCA_STATUS hal_kit_cdc_release(void *hal_data); +ATCA_STATUS hal_kit_cdc_discover_buses(int i2c_buses[], int max_buses); +ATCA_STATUS hal_kit_cdc_discover_devices(int busNum, ATCAIfaceCfg *cfg, int *found); +#endif + +#ifdef ATCA_HAL_KIT_HID +ATCA_STATUS hal_kit_hid_init(void *hal, ATCAIfaceCfg *cfg); +ATCA_STATUS hal_kit_hid_post_init(ATCAIface iface); +ATCA_STATUS hal_kit_hid_send(ATCAIface iface, uint8_t *txdata, int txlength); +ATCA_STATUS hal_kit_hid_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength); +ATCA_STATUS hal_kit_hid_wake(ATCAIface iface); +ATCA_STATUS hal_kit_hid_idle(ATCAIface iface); +ATCA_STATUS hal_kit_hid_sleep(ATCAIface iface); +ATCA_STATUS hal_kit_hid_release(void *hal_data); +ATCA_STATUS hal_kit_hid_discover_buses(int i2c_buses[], int max_buses); +ATCA_STATUS hal_kit_hid_discover_devices(int busNum, ATCAIfaceCfg *cfg, int *found); +#endif + +/** \brief Timer API implemented at the HAL level */ +void atca_delay_us(uint32_t delay); +void atca_delay_10us(uint32_t delay); +void atca_delay_ms(uint32_t delay); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif /* ATCA_HAL_H_ */ \ No newline at end of file diff --git a/src/hal/atca_start_config.h b/src/hal/atca_start_config.h new file mode 100644 index 0000000..0dd4ce0 --- /dev/null +++ b/src/hal/atca_start_config.h @@ -0,0 +1,6 @@ +/* + this is a placeholder include used to satisfy the include + + when used with Atmel START, this file will be overwritten + with the user configuration generated by Atmel START + */ diff --git a/src/hal/atca_start_iface.h b/src/hal/atca_start_iface.h new file mode 100644 index 0000000..c290da9 --- /dev/null +++ b/src/hal/atca_start_iface.h @@ -0,0 +1,6 @@ +/* + this is a placeholder include used to satisfy the include + + when used with Atmel START, this file will be overwritten + with the user configuration generated by Atmel START + */ \ No newline at end of file diff --git a/src/hal/hal_samd21_i2c_wire.cpp b/src/hal/hal_samd21_i2c_wire.cpp new file mode 100644 index 0000000..4eb30e2 --- /dev/null +++ b/src/hal/hal_samd21_i2c_wire.cpp @@ -0,0 +1,258 @@ +#include +#include +#include +#include + +#include "atca_hal.h" +#include "atca_device.h" +#include "hal_samd21_i2c_wire.h" + +#define DEBUG_LOG( x ) + +extern "C" ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg); +extern "C" ATCA_STATUS hal_i2c_wake(ATCAIface iface); +extern "C" ATCA_STATUS hal_i2c_idle(ATCAIface iface); +extern "C" ATCA_STATUS hal_i2c_release(void *hal_data); + + +static bool wake_complete = false; + +static uint8_t revs508[1][4] = { { 0x00, 0x00, 0x50, 0x00 } }; +static uint8_t revs108[2][4] = { { 0x80, 0x00, 0x10, 0x01 }, + { 0x00, 0x00, 0x10, 0x05 } }; +static uint8_t revs204[3][4] = { { 0x00, 0x02, 0x00, 0x08 }, + { 0x00, 0x02, 0x00, 0x09 }, + { 0x00, 0x04, 0x05, 0x00 } }; + +extern "C" ATCA_STATUS hal_i2c_discover_devices(int busNum, ATCAIfaceCfg *cfg, int *found) +{ + ATCAIfaceCfg *head = cfg; + uint8_t slaveAddress = 0x01; + ATCADevice device; + ATCAIface discoverIface; + ATCACommand command; + ATCAPacket packet; + uint32_t execution_time; + ATCA_STATUS status; + int i; + + ATCAIfaceCfg discoverCfg; + discoverCfg.iface_type = ATCA_I2C_IFACE; + discoverCfg.devtype = ATECC508A; + discoverCfg.wake_delay = 800; + discoverCfg.rx_retries = 3; + discoverCfg.atcai2c = { + .slave_address = 0x07, + .bus = busNum, + .baud = 400000 + }; + + ATCAHAL_t hal; + + hal_i2c_init( &hal, &discoverCfg ); + device = newATCADevice( &discoverCfg ); + discoverIface = atGetIFace( device ); + command = atGetCommands( device ); + + *found = 0; + for ( slaveAddress = 0x07; slaveAddress <= 0x78; slaveAddress++ ) { + discoverCfg.atcai2c.slave_address = slaveAddress << 1; + + if ( hal_i2c_wake( discoverIface ) == ATCA_SUCCESS ) { + (*found)++; + memcpy( (uint8_t*)head, (uint8_t*)&discoverCfg, sizeof(ATCAIfaceCfg)); + head->devtype = ATCA_DEV_UNKNOWN; + + memset( packet.data, 0x00, sizeof(packet.data)); + + atInfo( command, &packet ); + execution_time = atGetExecTime(command, CMD_INFO) + 1; + + if ( (status = atsend( discoverIface, (uint8_t*)&packet, packet.txsize )) != ATCA_SUCCESS ) { + Serial.println("packet send error"); + continue; + } + + atca_delay_ms(execution_time); + + if ( (status = atreceive( discoverIface, &(packet.data[0]), &(packet.rxsize) )) != ATCA_SUCCESS ) + continue; + + if ( (status = isATCAError(packet.data)) != ATCA_SUCCESS ) { + Serial.println("command response error\r\n"); + continue; + } + + for ( i = 0; i < (int)sizeof(revs508) / 4; i++ ) { + if ( memcmp( &packet.data[1], &revs508[i], 4) == 0 ) { + head->devtype = ATECC508A; + break; + } + } + + for ( i = 0; i < (int)sizeof(revs204) / 4; i++ ) { + if ( memcmp( &packet.data[1], &revs204[i], 4) == 0 ) { + head->devtype = ATSHA204A; + break; + } + } + + for ( i = 0; i < (int)sizeof(revs108) / 4; i++ ) { + if ( memcmp( &packet.data[1], &revs108[i], 4) == 0 ) { + head->devtype = ATECC108A; + break; + } + } + + atca_delay_ms(15); + head++; + } + + hal_i2c_idle(discoverIface); + } + + hal_i2c_release(&hal); + + return ATCA_SUCCESS; +} + +extern "C" ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg) +{ + return ATCA_SUCCESS; +} + +extern "C" ATCA_STATUS hal_i2c_post_init(ATCAIface iface) +{ + return ATCA_SUCCESS; +} + +extern "C" ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength) +{ + ATCAIfaceCfg *cfg = atgetifacecfg(iface); + + DEBUG_LOG( Serial.print("> "); ) + DEBUG_LOG( Serial.println(cfg->atcai2c.slave_address >> 1, HEX); ) + + txdata[0] = 0x03; // insert the Word Address Value, Command token + txlength++; + + // txdata has ATCAPacket format + Wire.beginTransmission(cfg->atcai2c.slave_address >> 1); + for (int i = 0; i < txlength; i++) + Wire.write(txdata[i]); + Wire.endTransmission(); + + return ATCA_SUCCESS; +} + +extern "C" ATCA_STATUS hal_i2c_receive( ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength) +{ + uint16_t i; + ATCAIfaceCfg *cfg = atgetifacecfg(iface); + + DEBUG_LOG( Serial.print(cfg->atcai2c.slave_address >> 1, HEX); ) + DEBUG_LOG( Serial.print(" < "); ) + + // Get length of response + Wire.requestFrom(cfg->atcai2c.slave_address >> 1, 1); + if (Wire.available() != 1) { + Serial.println("no count"); + return ATCA_COMM_FAIL; + } + rxdata[0] = Wire.read(); + + Wire.requestFrom(cfg->atcai2c.slave_address >> 1, rxdata[0]-1); + if (Wire.available() != (rxdata[0]-1)) { + Serial.println("no data"); + return ATCA_COMM_FAIL; + } + + for (int i = 1; i < rxdata[0] && i < *rxlength; i++) { + rxdata[i] = Wire.read(); + DEBUG_LOG( Serial.print(":"); ) + DEBUG_LOG( Serial.print(rxdata[i], HEX); ) + } + DEBUG_LOG( Serial.println(); ) + + return ATCA_SUCCESS; +} + +extern "C" ATCA_STATUS hal_i2c_wake(ATCAIface iface) +{ + int status; + ATCAIfaceCfg *cfg = atgetifacecfg(iface); + int retries = cfg->rx_retries; + uint8_t data[4], expected[4] = {0x04, 0x11, 0x33, 0x43}; + + if (wake_complete) + return ATCA_SUCCESS; + + DEBUG_LOG( Serial.print("wake "); ) + DEBUG_LOG( Serial.println(cfg->atcai2c.slave_address >> 1, HEX); ) + + Wire.beginTransmission(0x00); + Wire.endTransmission(); + + atca_delay_us(cfg->wake_delay); + + while (Wire.requestFrom(cfg->atcai2c.slave_address >> 1, 4) == 0 && + retries > 0) + retries--; + + if (Wire.available() != 4) { + Serial.print("invalid response "); + Serial.println(Wire.available()); + return ATCA_COMM_FAIL; + } + + wake_complete = true; + + for (int i = 0; i < 4; i++) + data[i] = Wire.read(); + if (memcmp(data, expected, 4) == 0) + return ATCA_SUCCESS; + + Serial.print("incorrect response "); + for (int i = 0; i < 4; i++) { + Serial.print(":"); + Serial.print(data[i], HEX); + } + Serial.println(""); + + return ATCA_COMM_FAIL; +} + +extern "C" ATCA_STATUS hal_i2c_idle(ATCAIface iface) +{ + ATCAIfaceCfg *cfg = atgetifacecfg(iface); + + DEBUG_LOG( Serial.print("idle "); ) + DEBUG_LOG( Serial.println(cfg->atcai2c.slave_address >> 1, HEX); ) + + Wire.beginTransmission(cfg->atcai2c.slave_address >> 1); + Wire.write(0x02); // idle word address value + Wire.endTransmission(); + wake_complete = false; + + return ATCA_SUCCESS; +} + +extern "C" ATCA_STATUS hal_i2c_sleep(ATCAIface iface) +{ + ATCAIfaceCfg *cfg = atgetifacecfg(iface); + + DEBUG_LOG( Serial.print("sleep "); ) + DEBUG_LOG( Serial.println(cfg->atcai2c.slave_address >> 1, HEX); ) + + Wire.beginTransmission(cfg->atcai2c.slave_address >> 1); + Wire.write(0x01); // sleep word address value + Wire.endTransmission(); + wake_complete = false; + + return ATCA_SUCCESS; +} + +extern "C" ATCA_STATUS hal_i2c_release( void *hal_data ) +{ + return ATCA_SUCCESS; +} diff --git a/src/hal/hal_samd21_i2c_wire.h b/src/hal/hal_samd21_i2c_wire.h new file mode 100644 index 0000000..c748e47 --- /dev/null +++ b/src/hal/hal_samd21_i2c_wire.h @@ -0,0 +1,14 @@ +#ifndef HAL_SAMD21_I2C_WIRE_H_ +#define HAL_SAMD21_I2C_WIRE_H_ + +#define MAX_I2C_BUSES 1 + +typedef struct atcaI2Cmaster { + int ref_ct; + int bus_index; +} ATCAI2CMaster_t; + +void change_i2c_speed( ATCAIface iface, uint32_t speed ); + +/** @} */ +#endif /* HAL_SAMD21_I2C_WIRE_H_ */ diff --git a/src/hal/hal_samd21_timer_wire.cpp b/src/hal/hal_samd21_timer_wire.cpp new file mode 100644 index 0000000..4a6bd81 --- /dev/null +++ b/src/hal/hal_samd21_timer_wire.cpp @@ -0,0 +1,12 @@ +#include +#include "atca_hal.h" + +extern "C" void atca_delay_ms(uint32_t ms) +{ + delay(ms); +} + +extern "C" void atca_delay_us(uint32_t us) +{ + delayMicroseconds(us); +} diff --git a/src/host/atca_host.c b/src/host/atca_host.c new file mode 100644 index 0000000..d73aca9 --- /dev/null +++ b/src/host/atca_host.c @@ -0,0 +1,1038 @@ +/** + * \file + * \brief Host side methods to support CryptoAuth computations + * + * \copyright Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + +#include "atca_host.h" +#include "crypto/atca_crypto_sw_sha2.h" + + +/** \brief This function copies otp and sn data into a command buffer. + * + * \param[in, out] param pointer to parameter structure + * \return pointer to command buffer byte that was copied last + */ +uint8_t *atcah_include_data(struct atca_include_data_in_out *param) +{ + if (param->mode & MAC_MODE_INCLUDE_OTP_88) { + memcpy(param->p_temp, param->otp, ATCA_OTP_SIZE_8 + ATCA_OTP_SIZE_3); // use OTP[0:10], Mode:5 is overridden + param->p_temp += ATCA_OTP_SIZE_8 + ATCA_OTP_SIZE_3; + }else { + if (param->mode & MAC_MODE_INCLUDE_OTP_64) + memcpy(param->p_temp, param->otp, ATCA_OTP_SIZE_8); // use 8 bytes OTP[0:7] for (6) + else + memset(param->p_temp, 0, ATCA_OTP_SIZE_8); // use 8 zeros for (6) + param->p_temp += ATCA_OTP_SIZE_8; + + memset(param->p_temp, 0, ATCA_OTP_SIZE_3); // use 3 zeros for (7) + param->p_temp += ATCA_OTP_SIZE_3; + } + + // (8) 1 byte SN[8] = 0xEE + *param->p_temp++ = ATCA_SN_8; + + // (9) 4 bytes SN[4:7] or zeros + if (param->mode & MAC_MODE_INCLUDE_SN) + memcpy(param->p_temp, ¶m->sn[4], ATCA_SN_SIZE_4); //use SN[4:7] for (9) + else + memset(param->p_temp, 0, ATCA_SN_SIZE_4); //use zeros for (9) + param->p_temp += ATCA_SN_SIZE_4; + + // (10) 2 bytes SN[0:1] = 0x0123 + *param->p_temp++ = ATCA_SN_0; + *param->p_temp++ = ATCA_SN_1; + + // (11) 2 bytes SN[2:3] or zeros + if (param->mode & MAC_MODE_INCLUDE_SN) + memcpy(param->p_temp, ¶m->sn[2], ATCA_SN_SIZE_2); //use SN[2:3] for (11) + else + memset(param->p_temp, 0, ATCA_SN_SIZE_2); //use zeros for (9) + param->p_temp += ATCA_SN_SIZE_2; + + return param->p_temp; +} + +/** \brief This function calculates a 32-byte nonce based on a 20-byte input value (param->num_in) and 32-byte random number (param->rand_out). + + This nonce will match with the nonce generated in the device when executing a Nonce command. + To use this function, an application first sends a Nonce command with a chosen param->num_in to the device. + Nonce Mode parameter must be set to use random nonce (mode 0 or 1).\n + The device generates a nonce, stores it in its TempKey, and outputs the random number param->rand_out it used in the hash calculation to the host. + The values of param->rand_out and param->num_in are passed to this nonce calculation function. The function calculates the nonce and returns it. + This function can also be used to fill in the nonce directly to TempKey (pass-through mode). The flags will automatically be set according to the mode used. + \param[in, out] param pointer to parameter structure + \return status of the operation + */ +ATCA_STATUS atcah_nonce(struct atca_nonce_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_NONCE]; + uint8_t *p_temp; + + // Check parameters + if (!param->temp_key || !param->num_in || (param->mode > NONCE_MODE_PASSTHROUGH) || (param->mode == NONCE_MODE_INVALID) + || (((param->mode == NONCE_MODE_SEED_UPDATE || (param->mode == NONCE_MODE_NO_SEED_UPDATE)) && !param->rand_out))) + return ATCA_BAD_PARAM; + + // Calculate or pass-through the nonce to TempKey->Value + if ((param->mode == NONCE_MODE_SEED_UPDATE) || (param->mode == NONCE_MODE_NO_SEED_UPDATE)) { + // Calculate nonce using SHA-256 (refer to data sheet) + p_temp = temporary; + + memcpy(p_temp, param->rand_out, NONCE_RSP_SIZE_LONG - ATCA_PACKET_OVERHEAD); + p_temp += NONCE_RSP_SIZE_LONG - ATCA_PACKET_OVERHEAD; + + memcpy(p_temp, param->num_in, NONCE_NUMIN_SIZE); + p_temp += NONCE_NUMIN_SIZE; + + *p_temp++ = ATCA_NONCE; + *p_temp++ = param->mode; + *p_temp++ = 0x00; + + // Calculate SHA256 to get the nonce + atcah_sha256(ATCA_MSG_SIZE_NONCE, temporary, param->temp_key->value); + + // Update TempKey->SourceFlag to 0 (random) + param->temp_key->source_flag = 0; + }else if (param->mode == NONCE_MODE_PASSTHROUGH) { + // Pass-through mode + memcpy(param->temp_key->value, param->num_in, NONCE_NUMIN_SIZE_PASSTHROUGH); + + // Update TempKey->SourceFlag to 1 (not random) + param->temp_key->source_flag = 1; + } + + // Update TempKey fields + param->temp_key->key_id = 0; + param->temp_key->gen_data = 0; + param->temp_key->check_flag = 0; + param->temp_key->valid = 1; + + return ATCA_SUCCESS; +} + + +/** \brief This function generates an SHA-256 digest (MAC) of a key, challenge, and other information. + + The resulting digest will match with the one generated by the device when executing a MAC command. + The TempKey (if used) should be valid (temp_key.valid = 1) before executing this function. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_mac(struct atca_mac_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_MAC]; + uint8_t *p_temp; + struct atca_include_data_in_out include_data; + + // Initialize struct + include_data.otp = param->otp; + include_data.sn = param->sn; + include_data.mode = param->mode; + + // Check parameters + if (!param->response + || (param->mode & ~MAC_MODE_MASK) + || (!(param->mode & MAC_MODE_BLOCK1_TEMPKEY) && !param->key) + || (!(param->mode & MAC_MODE_BLOCK2_TEMPKEY) && !param->challenge) + || ((param->mode & MAC_MODE_USE_TEMPKEY_MASK) && !param->temp_key) + || (((param->mode & MAC_MODE_INCLUDE_OTP_64) || (param->mode & MAC_MODE_INCLUDE_OTP_88)) && !param->otp) + || ((param->mode & MAC_MODE_INCLUDE_SN) && !param->sn) + ) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity if TempKey is used + if (((param->mode & MAC_MODE_USE_TEMPKEY_MASK) != 0) + // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + && (param->temp_key->check_flag || (param->temp_key->valid != 1) + // If either mode parameter bit 0 or bit 1 are set, mode parameter bit 2 must match temp_key.source_flag. + // Logical not (!) is used to evaluate the expression to TRUE / FALSE first before comparison (!=). + || (!(param->mode & MAC_MODE_SOURCE_FLAG_MATCH) != !(param->temp_key->source_flag))) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) first 32 bytes + memcpy(p_temp, param->mode & MAC_MODE_BLOCK1_TEMPKEY ? param->temp_key->value : param->key, ATCA_KEY_SIZE); // use Key[KeyID] + p_temp += ATCA_KEY_SIZE; + + // (2) second 32 bytes + memcpy(p_temp, param->mode & MAC_MODE_BLOCK2_TEMPKEY ? param->temp_key->value : param->challenge, ATCA_KEY_SIZE); // use Key[KeyID] + p_temp += ATCA_KEY_SIZE; + + // (3) 1 byte opcode + *p_temp++ = ATCA_MAC; + + // (4) 1 byte mode parameter + *p_temp++ = param->mode; + + // (5) 2 bytes keyID + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + include_data.p_temp = p_temp; + atcah_include_data(&include_data); + + // Calculate SHA256 to get the MAC digest + atcah_sha256(ATCA_MSG_SIZE_MAC, temporary, param->response); + + // Update TempKey fields + if (param->temp_key) + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} + + +/** \brief This function calculates a SHA-256 digest (MAC) of a password and other information, to be verified using the CheckMac device command. + + This password checking operation is described in Atmel ATSHA204 [DATASHEET]. + Before performing password checking operation, TempKey should contain a randomly generated nonce. The TempKey in the device has to match the one in the application. + A user enters the password to be verified by an application. + The application passes this password to the CheckMac calculation function, along with 13 bytes of OtherData, a 32-byte target key, and optionally 11 bytes of OTP. + The function calculates a 32-byte ClientResp, returns it to Application. The function also replaces the current TempKey value with the target key. + The application passes the calculated ClientResp along with OtherData inside a CheckMac command to the device. + The device validates ClientResp, and copies the target slot to its TempKey. + + If the password is stored in an odd numbered slot, the target slot is the password slot itself, so the target_key parameter should point to the password being checked. + If the password is stored in an even numbered slot, the target slot is the next odd numbered slot (KeyID + 1), so the target_key parameter should point to a key that + is equal to the target slot in the device. + + Note that the function does not check the result of the password checking operation. + Regardless of whether the CheckMac command returns success or not, the TempKey variable of the application will hold the value of the target key. + Therefore the application has to make sure that password checking operation succeeds before using the TempKey for subsequent operations. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_check_mac(struct atca_check_mac_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_MAC]; + uint8_t *p_temp; + + // Check parameters + if (((param->mode & MAC_MODE_USE_TEMPKEY_MASK) != MAC_MODE_BLOCK2_TEMPKEY) + || !param->password || !param->other_data + || !param->target_key || !param->client_resp || !param->temp_key + || ((param->mode & MAC_MODE_INCLUDE_OTP_64) && !param->otp) + ) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity (TempKey is always used) + // TempKey.CheckFlag must be 0, TempKey.Valid must be 1, TempKey.SourceFlag must be 0 + if (param->temp_key->check_flag || (param->temp_key->valid != 1) || param->temp_key->source_flag) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) first 32 bytes + memcpy(p_temp, param->password, ATCA_KEY_SIZE); // password to be checked + p_temp += ATCA_KEY_SIZE; + + // (2) second 32 bytes + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); // use TempKey.Value + p_temp += ATCA_KEY_SIZE; + + // (3, 4, 5) 4 byte OtherData[0:3] + memcpy(p_temp, ¶m->other_data[0], ATCA_OTHER_DATA_SIZE_4); + p_temp += ATCA_OTHER_DATA_SIZE_4; + + // (6) 8 bytes OTP[0:7] or 0x00's + if (param->mode & MAC_MODE_INCLUDE_OTP_64) + memcpy(p_temp, param->otp, ATCA_OTP_SIZE_8); // use 8 bytes OTP[0:7] for (6) + else + memset(p_temp, 0, ATCA_OTP_SIZE_8); // use 8 zeros for (6) + p_temp += ATCA_OTP_SIZE_8; + + // (7) 3 byte OtherData[4:6] + memcpy(p_temp, ¶m->other_data[ATCA_OTHER_DATA_SIZE_4], ATCA_OTHER_DATA_SIZE_3); // use OtherData[4:6] for (7) + p_temp += ATCA_OTHER_DATA_SIZE_3; + + // (8) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (9) 4 byte OtherData[7:10] + memcpy(p_temp, ¶m->other_data[ATCA_OTHER_DATA_SIZE_4 + ATCA_OTHER_DATA_SIZE_3], ATCA_OTHER_DATA_SIZE_4); // use OtherData[7:10] for (9) + p_temp += ATCA_OTHER_DATA_SIZE_4; + + // (10) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // (11) 2 byte OtherData[11:12] + memcpy(p_temp, ¶m->other_data[ATCA_OTHER_DATA_SIZE_4 + ATCA_OTHER_DATA_SIZE_3 + ATCA_OTHER_DATA_SIZE_2], + ATCA_OTHER_DATA_SIZE_2); // use OtherData[11:12] for (11) + p_temp += ATCA_OTHER_DATA_SIZE_2; + + // Calculate SHA256 to get the MAC digest + atcah_sha256(ATCA_MSG_SIZE_MAC, temporary, param->client_resp); + + // Update TempKey fields + memcpy(param->temp_key->value, param->target_key, ATCA_KEY_SIZE); + param->temp_key->gen_data = 0; + param->temp_key->source_flag = 1; + param->temp_key->valid = 1; + + return ATCA_SUCCESS; +} + + +/** \brief This function generates an HMAC / SHA-256 hash of a key and other information. + + The resulting hash will match with the one generated in the device by an HMAC command. + The TempKey has to be valid (temp_key.valid = 1) before executing this function. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_hmac(struct atca_hmac_in_out *param) +{ + // Local Variables + struct atca_include_data_in_out include_data; + uint8_t temporary[ATCA_MSG_SIZE_HMAC_INNER]; + uint8_t i; + uint8_t *p_temp; + + // Initialize struct + include_data.otp = param->otp; + include_data.sn = param->sn; + include_data.mode = param->mode; + + // Check parameters + if (!param->response || !param->key || !param->temp_key + || (param->mode & ~HMAC_MODE_MASK) + || (((param->mode & MAC_MODE_INCLUDE_OTP_64) || (param->mode & MAC_MODE_INCLUDE_OTP_88)) && !param->otp) + || ((param->mode & MAC_MODE_INCLUDE_SN) && !param->sn) + ) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->check_flag || (param->temp_key->valid != 1) + // The mode parameter bit 2 must match temp_key.source_flag. + // Logical not (!) is used to evaluate the expression to TRUE / FALSE first before comparison (!=). + || (!(param->mode & MAC_MODE_SOURCE_FLAG_MATCH) != !(param->temp_key->source_flag)) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start first calculation (inner) + p_temp = temporary; + + // Refer to fips-198a.pdf, length Key = 32 bytes, Block size = 512 bits = 64 bytes. + // So the Key must be padded with zeros. + // XOR K0 with ipad, then append + for (i = 0; i < ATCA_KEY_SIZE; i++) + *p_temp++ = param->key[i] ^ 0x36; + + // XOR the remaining zeros and append + for (i = 0; i < HMAC_BLOCK_SIZE - ATCA_KEY_SIZE; i++) + *p_temp++ = 0 ^ 0x36; + + // Next append the stream of data 'text' + // (1) first 32 bytes: zeros + memset(p_temp, 0, HMAC_BLOCK_SIZE - ATCA_KEY_SIZE); + p_temp += HMAC_BLOCK_SIZE - ATCA_KEY_SIZE; + + // (2) second 32 bytes: TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (3) 1 byte opcode + *p_temp++ = ATCA_HMAC; + + // (4) 1 byte mode parameter + *p_temp++ = param->mode; + + // (5) 2 bytes keyID + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // Calculate SHA256 + // H((K0^ipad):text), use param.response for temporary storage + atcah_sha256(ATCA_MSG_SIZE_HMAC_INNER, temporary, param->response); + + // Start second calculation (outer) + p_temp = temporary; + + // XOR K0 with opad, then append + for (i = 0; i < ATCA_KEY_SIZE; i++) + *p_temp++ = param->key[i] ^ 0x5C; + + // XOR the remaining zeros and append + for (i = 0; i < HMAC_BLOCK_SIZE - ATCA_KEY_SIZE; i++) + *p_temp++ = 0 ^ 0x5C; + + // Append result from last calculation H((K0 ^ ipad): text) + memcpy(p_temp, param->response, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + include_data.p_temp = p_temp; + atcah_include_data(&include_data); + + // Calculate SHA256 to get the resulting HMAC + atcah_sha256(ATCA_MSG_SIZE_HMAC, temporary, param->response); + + // Update TempKey fields + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} + + +/** \brief This function combines the current TempKey with a stored value. + + The stored value can be a data slot, OTP page, configuration zone, or hardware transport key. + The TempKey generated by this function will match with the TempKey in the device generated + when executing a GenDig command. + The TempKey should be valid (temp_key.valid = 1) before executing this function. + To use this function, an application first sends a GenDig command with a chosen stored value to the device. + This stored value must be known by the application and is passed to this GenDig calculation function. + The function calculates a new TempKey and returns it. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_gen_dig(struct atca_gen_dig_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_GEN_DIG]; + uint8_t *p_temp; + + // Check parameters + if (!param->stored_value || !param->temp_key + || ((param->zone != GENDIG_ZONE_OTP) + && (param->zone != GENDIG_ZONE_DATA) + && (param->zone != GENDIG_ZONE_CONFIG)) + ) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->check_flag || (param->temp_key->valid != 1) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) 32 bytes inputKey + // (Config[KeyID] or OTP[KeyID] or Data.slot[KeyID] or TransportKey[KeyID]) + memcpy(p_temp, param->stored_value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_GENDIG; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (6) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_GENDIG_ZEROS_SIZE); + p_temp += ATCA_GENDIG_ZEROS_SIZE; + + // (8) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + + // Calculate SHA256 to get the new TempKey + atcah_sha256(ATCA_MSG_SIZE_GEN_DIG, temporary, param->temp_key->value); + + // Update TempKey fields + param->temp_key->valid = 1; + + if ((param->zone == GENDIG_ZONE_DATA) && (param->key_id <= 15)) { + param->temp_key->gen_data = 1; + param->temp_key->key_id = (param->key_id & 0xF); // mask lower 4-bit only + }else { + param->temp_key->gen_data = 0; + param->temp_key->key_id = 0; + } + + return ATCA_SUCCESS; +} + +/** \brief This function combines the session key with a plain text. + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_gen_mac(struct atca_gen_dig_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_GEN_DIG]; + uint8_t *p_temp; + + // Check parameters + if (!param->stored_value || !param->temp_key) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->check_flag || (param->temp_key->valid != 1) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) 32 bytes SessionKey + // (Config[KeyID] or OTP[KeyID] or Data.slot[KeyID] or TransportKey[KeyID]) + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_WRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (6) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_GENDIG_ZEROS_SIZE); + p_temp += ATCA_GENDIG_ZEROS_SIZE; + + // (8) 32 bytes PlainText + memcpy(p_temp, param->stored_value, ATCA_KEY_SIZE); + + // Calculate SHA256 to get the new TempKey + atcah_sha256(ATCA_MSG_SIZE_GEN_DIG, temporary, param->temp_key->value); + + // Update TempKey fields + param->temp_key->valid = 1; + + if ((param->zone == GENDIG_ZONE_DATA) && (param->key_id <= 15)) { + param->temp_key->gen_data = 1; + param->temp_key->key_id = (param->key_id & 0xF); // mask lower 4-bit only + }else { + param->temp_key->gen_data = 0; + param->temp_key->key_id = 0; + } + + return ATCA_SUCCESS; +} + +/** \brief This function calculates the input MAC for the PrivWrite command. + + The PrivWrite command will need an input MAC if SlotConfig.WriteConfig.Encrypt is set. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_write_auth_mac(struct atca_write_mac_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_PRIVWRITE_MAC]; + uint8_t i; + uint8_t *p_temp; + uint8_t session_key2[32]; + + // Check parameters + if (!param->input_data || !param->temp_key) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->check_flag || (param->temp_key->valid != 1) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + // Encrypt by XOR-ing Data with the TempKey + for (i = 0; i < 32; i++) + param->encrypted_data[i] = param->encryption_key[i] ^ param->temp_key->value[i]; + + // Calculate the new tempkey + atcah_sha256(32, param->temp_key->value, session_key2); + + // If the pointer *mac is provided by the caller then calculate input MAC + if (param->auth_mac) { + // Start calculation + p_temp = temporary; + + // (1) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_PRIVWRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (6) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // (7) 21 zeros + memset(p_temp, 0, ATCA_PRIVWRITE_MAC_ZEROS_SIZE); + p_temp += ATCA_PRIVWRITE_MAC_ZEROS_SIZE; + + // (8) 36 bytes PlainText : 0 0 0 0 (4bytes) | private_key (32bytes) + memcpy(p_temp, param->input_data, ATCA_PLAIN_TEXT_SIZE); + + // Calculate SHA256 to get the new TempKey + atcah_sha256(ATCA_MSG_SIZE_PRIVWRITE_MAC, temporary, param->auth_mac); + } + // Update TempKey fields + param->temp_key->valid = 1; + + return ATCA_SUCCESS; +} + +/** \brief This function calculates the input MAC for the PrivWrite command. + + The PrivWrite command will need an input MAC if SlotConfig.WriteConfig.Encrypt is set. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_privwrite_auth_mac(struct atca_write_mac_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_PRIVWRITE_MAC]; + uint8_t i; + uint8_t *p_temp; + uint8_t session_key2[32]; + + // Check parameters + if (!param->input_data || !param->temp_key) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->check_flag || (param->temp_key->valid != 1) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + + /* Encrypt by XOR-ing Data with the TempKey + */ + + // Encrypt the first 4 bytes of the cipher text, which should be 0s + for (i = 0; i < 4; i++) + param->encrypted_data[i] = 0 ^ param->temp_key->value[i]; + + // Encrypt the next 28 bytes of the cipher text, which is the first part of the private key. + for (i = 4; i < 32; i++) + param->encrypted_data[i] = param->encryption_key[i - 4] ^ param->temp_key->value[i]; + + // Calculate the new key for the last 4 bytes of the cipher text + atcah_sha256(32, param->temp_key->value, session_key2); + + // Encrypt the last 4 bytes of the cipher text, which is the remaining part of the private key + for (i = 32; i < 36; i++) + param->encrypted_data[i] = param->encryption_key[i - 4] ^ session_key2[i - 32]; + + // If the pointer *mac is provided by the caller then calculate input MAC + if (param->auth_mac) { + // Start calculation + p_temp = temporary; + + // (1) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_PRIVWRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->key_id & 0xFF; + *p_temp++ = (param->key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (6) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // (7) 21 zeros + memset(p_temp, 0, ATCA_PRIVWRITE_MAC_ZEROS_SIZE); + p_temp += ATCA_PRIVWRITE_MAC_ZEROS_SIZE; + + // (8) 36 bytes PlainText : 0 0 0 0 (4bytes) | private_key (32bytes) + memcpy(p_temp, param->input_data, ATCA_PLAIN_TEXT_SIZE); + + // Calculate SHA256 to get the new TempKey + atcah_sha256(ATCA_MSG_SIZE_PRIVWRITE_MAC, temporary, param->auth_mac); + } + + // Update TempKey fields + param->temp_key->valid = 1; + + return ATCA_SUCCESS; +} + +/** \brief This function combines a key with the TempKey. + + Used in conjunction with DeriveKey command, the key derived by this function will match the key in the device. + Two kinds of operation are supported: +
    +
  • Roll Key operation: target_key and parent_key parameters should be set to point to the same location (TargetKey).
  • +
  • Create Key operation: target_key should be set to point to TargetKey, parent_key should be set to point to ParentKey.
  • +
+ After executing this function, the initial value of target_key will be overwritten with the derived key. + The TempKey should be valid (temp_key.valid = 1) before executing this function. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_derive_key(struct atca_derive_key_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_DERIVE_KEY]; + uint8_t *p_temp; + + // Check parameters + if (!param->parent_key || !param->target_key || !param->temp_key + || (param->random & ~DERIVE_KEY_RANDOM_FLAG) || (param->target_key_id > ATCA_KEY_ID_MAX)) + return ATCA_BAD_PARAM; + + + // Check TempKey fields validity (TempKey is always used) + if ( // TempKey.CheckFlag must be 0 and TempKey.Valid must be 1 + param->temp_key->check_flag || (param->temp_key->valid != 1) + // The random parameter bit 2 must match temp_key.source_flag + // Logical not (!) is used to evaluate the expression to TRUE / FALSE first before comparison (!=). + || (!(param->random & DERIVE_KEY_RANDOM_FLAG) != !(param->temp_key->source_flag)) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Start calculation + p_temp = temporary; + + // (1) 32 bytes parent key + memcpy(p_temp, param->parent_key, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_DERIVE_KEY; + + // (3) 1 byte Param1 (random) + *p_temp++ = param->random; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->target_key_id & 0xFF; + *p_temp++ = (param->target_key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (6) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_DERIVE_KEY_ZEROS_SIZE); + p_temp += ATCA_DERIVE_KEY_ZEROS_SIZE; + + // (8) 32 bytes TempKey + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // Calculate SHA256 to get the derived key. + atcah_sha256(ATCA_MSG_SIZE_DERIVE_KEY, temporary, param->target_key); + + // Update TempKey fields + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} + + +/** \brief This function calculates the input MAC for a DeriveKey command. + + The DeriveKey command will need an input MAC if SlotConfig[TargetKey].Bit15 is set. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_derive_key_mac(struct atca_derive_key_mac_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_DERIVE_KEY_MAC]; + uint8_t *p_temp; + + // Check parameters + if (!param->parent_key || !param->mac || (param->random & ~DERIVE_KEY_RANDOM_FLAG) + || (param->target_key_id > ATCA_KEY_ID_MAX)) + return ATCA_BAD_PARAM; + + // Start calculation + p_temp = temporary; + + // (1) 32 bytes parent key + memcpy(p_temp, param->parent_key, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_DERIVE_KEY; + + // (3) 1 byte Param1 (random) + *p_temp++ = param->random; + + // (4) 2 bytes Param2 (keyID) + *p_temp++ = param->target_key_id & 0xFF; + *p_temp++ = (param->target_key_id >> 8) & 0xFF; + + // (5) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (6) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // Calculate SHA256 to get the input MAC for DeriveKey command + atcah_sha256(ATCA_MSG_SIZE_DERIVE_KEY_MAC, temporary, param->mac); + + return ATCA_SUCCESS; +} + + +/** \brief This function encrypts 32-byte plain text data to be written using Write opcode, and optionally calculates input MAC. + + To use this function, first the nonce must be valid and synchronized between device and application. + The application sends a GenDig command to the device, using a parent key. If the Data zone has been locked, this is + specified by SlotConfig.WriteKey. The device updates its TempKey when executing the command. + The application then updates its own TempKey using the GenDig calculation function, using the same key. + The application passes the plain text data to the encryption function.\n + If input MAC is needed the application must pass a valid pointer to buffer in the "mac" command parameter. + If input MAC is not needed the application can pass a NULL pointer in the "mac" command parameter. + The function encrypts the data and optionally calculates the input MAC, and returns it to the application. + Using these encrypted data and the input MAC, the application sends a Write command to the Device. The device + validates the MAC, then decrypts and writes the data.\n + The encryption function does not check whether the TempKey has been generated by the correct ParentKey for the + corresponding zone. Therefore, to get a correct result after the Data and OTP zones have been locked, the application + has to make sure that prior GenDig calculation was done using the correct ParentKey. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_encrypt(struct atca_encrypt_in_out *param) +{ + uint8_t temporary[ATCA_MSG_SIZE_ENCRYPT_MAC]; + uint8_t i; + uint8_t *p_temp; + + // Check parameters + if (!param->crypto_data || !param->temp_key || (param->zone & ~WRITE_ZONE_MASK)) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity, and illegal address + // Note that if temp_key.key_id is not checked, + // we cannot make sure if the key used in previous GenDig IS equal to + // the key pointed by SlotConfig.WriteKey in the device. + if ( // TempKey.CheckFlag must be 0 + param->temp_key->check_flag + // TempKey.Valid must be 1 + || (param->temp_key->valid != 1) + // TempKey.GenData must be 1 + || (param->temp_key->gen_data != 1) + // TempKey.SourceFlag must be 0 (random) + || param->temp_key->source_flag + // Illegal address + || (param->address & ~ATCA_ADDRESS_MASK) + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // If the pointer *mac is provided by the caller then calculate input MAC + if (param->mac) { + // Start calculation + p_temp = temporary; + + // (1) 32 bytes parent key + memcpy(p_temp, param->temp_key->value, ATCA_KEY_SIZE); + p_temp += ATCA_KEY_SIZE; + + // (2) 1 byte Opcode + *p_temp++ = ATCA_WRITE; + + // (3) 1 byte Param1 (zone) + *p_temp++ = param->zone; + + // (4) 2 bytes Param2 (address) + *p_temp++ = param->address & 0xFF; + *p_temp++ = (param->address >> 8) & 0xFF; + + // (5) 1 byte SN[8] = 0xEE + *p_temp++ = ATCA_SN_8; + + // (6) 2 bytes SN[0:1] = 0x0123 + *p_temp++ = ATCA_SN_0; + *p_temp++ = ATCA_SN_1; + + // (7) 25 zeros + memset(p_temp, 0, ATCA_GENDIG_ZEROS_SIZE); + p_temp += ATCA_GENDIG_ZEROS_SIZE; + + // (8) 32 bytes data + memcpy(p_temp, param->crypto_data, ATCA_KEY_SIZE); + + // Calculate SHA256 to get the input MAC + atcah_sha256(ATCA_MSG_SIZE_ENCRYPT_MAC, temporary, param->mac); + } + + // Encrypt by XOR-ing Data with the TempKey + for (i = 0; i < ATCA_KEY_SIZE; i++) + param->crypto_data[i] ^= param->temp_key->value[i]; + + // Update TempKey fields + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} + + +/** \brief This function decrypts 32-byte encrypted data received with the Read command. + + To use this function, first the nonce must be valid and synchronized between device and application. + The application sends a GenDig command to the Device, using a key specified by SlotConfig.ReadKey. + The device updates its TempKey. + The application then updates its own TempKey using the GenDig calculation function, using the same key. + The application sends a Read command to the device for a user zone configured with EncryptRead. + The device encrypts 32-byte zone content, and outputs it to the host. + The application passes these encrypted data to this decryption function. The function decrypts the data and returns them. + TempKey must be updated by GenDig using a ParentKey as specified by SlotConfig.ReadKey before executing this function. + The decryption function does not check whether the TempKey has been generated by a correct ParentKey for the corresponding zone. + Therefore to get a correct result, the application has to make sure that prior GenDig calculation was done using correct ParentKey. + + * \param[in, out] param pointer to parameter structure + * \return status of the operation + */ +ATCA_STATUS atcah_decrypt(struct atca_decrypt_in_out *param) +{ + uint8_t i; + + // Check parameters + if (!param->crypto_data || !param->temp_key) + return ATCA_BAD_PARAM; + + // Check TempKey fields validity + // Note that if temp_key.key_id is not checked, + // we cannot make sure if the key used in previous GenDig IS equal to + // the key pointed by SlotConfig.ReadKey in the device. + if ( // TempKey.CheckFlag must be 0 + param->temp_key->check_flag + // TempKey.Valid must be 1 + || (param->temp_key->valid != 1) + // TempKey.GenData must be 1 + || (param->temp_key->gen_data != 1) + // TempKey.SourceFlag must be 0 (random) + || param->temp_key->source_flag + ) { + // Invalidate TempKey, then return + param->temp_key->valid = 0; + return ATCA_EXECUTION_ERROR; + } + + // Decrypt by XOR-ing Data with the TempKey + for (i = 0; i < ATCA_KEY_SIZE; i++) + param->crypto_data[i] ^= param->temp_key->value[i]; + + // Update TempKey fields + param->temp_key->valid = 0; + + return ATCA_SUCCESS; +} + +/** \brief This function creates a SHA256 digest on a little-endian system. + * + * Limitations: This function was implemented with the ATSHA204 CryptoAuth device + * in mind. It will therefore only work for length values of len % 64 < 62. + * + * \param[in] len byte length of message + * \param[in] message pointer to message + * \param[out] digest SHA256 of message + */ +ATCA_STATUS atcah_sha256(int32_t len, const uint8_t *message, uint8_t *digest) +{ + return atcac_sw_sha2_256(message, len, digest); +} + diff --git a/src/host/atca_host.h b/src/host/atca_host.h new file mode 100644 index 0000000..4e5330e --- /dev/null +++ b/src/host/atca_host.h @@ -0,0 +1,455 @@ +/** + * \file + * \brief Definitions and Prototypes for ATCA Utility Functions + * \author Atmel Crypto Products + * + * \copyright Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \atmel_crypto_device_library_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel integrated circuit. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \atmel_crypto_device_library_license_stop + */ + + +#ifndef ATCA_HOST_H +# define ATCA_HOST_H + +#include "cryptoauthlib.h" // contains definitions used by chip and these routines + +/** \defgroup atcah Host side crypto methods (atcah_) + * + * \brief + * Use these functions if your system does not use an ATCADevice as a host but + * implements the host in firmware. The functions provide host-side cryptographic functionality + * for an ATECC client device. They are intended to accompany the CryptoAuthLib functions. + * They can be called directly from an application, or integrated into an API. + * + * Modern compilers can garbage-collect unused functions. If your compiler does not support this feature, + * you can just discard this module from your project if you do use an ATECC as a host. Or, if you don't, + * delete the functions you do not use. + @{ */ + +/** \name Definitions for ATECC Message Sizes to Calculate a SHA256 Hash + + * \brief "||" is the concatenation operator. + * The number in braces is the length of the hash input value in bytes. + @{ */ + +//! RandOut{32} || NumIn{20} || OpCode{1} || Mode{1} || LSB of Param2{1} +#define ATCA_MSG_SIZE_NONCE (55) + + +/** \brief (Key or TempKey){32} || (Challenge or TempKey){32} || OpCode{1} || Mode{1} || Param2{2} +|| (OTP0_7 or 0){8} || (OTP8_10 or 0){3} || SN8{1} || (SN4_7 or 0){4} || SN0_1{2} || (SN2_3 or 0){2} +*/ +#define ATCA_MSG_SIZE_MAC (88) + +/** \brief HMAC = sha(HMAC outer || HMAC inner) + HMAC inner = sha((zero-padded key ^ ipad) || message) + = sha256( + (Key{32} || 0x36{32}) + || 0{32} || Key{32} + || OpCode{1} || Mode{1} || KeyId{2} + || OTP0_7{8} || OTP8_10{3} || SN8{1} || SN4_7{4} || SN0_1{2} || SN2_3{2} + ){32} + */ +#define ATCA_MSG_SIZE_HMAC_INNER (152) + + +/** \brief HMAC = sha(HMAC outer || HMAC inner) + = sha256((Key{32} || 0x5C{32}) || HMAC inner{32}) + */ +#define ATCA_MSG_SIZE_HMAC (96) + + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2} || SN8{1} || SN0_1{2} || 0{25} || TempKey{32} +#define ATCA_MSG_SIZE_GEN_DIG (96) + + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2} || SN8{1} || SN0_1{2} || 0{25} || TempKey{32} +#define ATCA_MSG_SIZE_DERIVE_KEY (96) + + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2} || SN8{1} || SN0_1{2} +#define ATCA_MSG_SIZE_DERIVE_KEY_MAC (39) + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2}|| SN8{1} || SN0_1{2} || 0{25} || TempKey{32} +#define ATCA_MSG_SIZE_ENCRYPT_MAC (96) + +//! KeyId{32} || OpCode{1} || Param1{1} || Param2{2}|| SN8{1} || SN0_1{2} || 0{21} || PlainText{36} +#define ATCA_MSG_SIZE_PRIVWRITE_MAC (96) + +#define ATCA_COMMAND_HEADER_SIZE ( 4) +#define ATCA_GENDIG_ZEROS_SIZE (25) +#define ATCA_PRIVWRITE_MAC_ZEROS_SIZE (21) +#define ATCA_PLAIN_TEXT_SIZE (36) +#define ATCA_DERIVE_KEY_ZEROS_SIZE (25) +#define ATCA_OTP_SIZE_8 ( 8) +#define ATCA_OTP_SIZE_3 ( 3) +#define ATCA_SN_SIZE_4 ( 4) +#define ATCA_SN_SIZE_2 ( 2) +#define ATCA_OTHER_DATA_SIZE_2 ( 2) +#define ATCA_OTHER_DATA_SIZE_3 ( 3) +#define ATCA_OTHER_DATA_SIZE_4 ( 4) +#define HMAC_BLOCK_SIZE (64) +/** @} */ + +/** \name Fixed Byte Values of Serial Number (SN[0:1] and SN[8]) + @{ */ +#define ATCA_SN_0 (0x01) +#define ATCA_SN_1 (0x23) +#define ATCA_SN_8 (0xEE) +/** @} */ + + +/** \name Definition for TempKey Mode + @{ */ +//! mode mask for MAC command when using TempKey +#define MAC_MODE_USE_TEMPKEY_MASK ((uint8_t)0x03) +/** @} */ + +#define ATAC_STANDARD_KEY_SIZE 32 + +/** \struct atca_temp_key + * \brief Structure to hold TempKey fields + * \var atca_temp_key::value + * \brief The value of TempKey. Nonce (from nonce command) or Digest (from GenDig command) + * \var atca_temp_key::key_id + * \brief If TempKey was generated by GenDig (see the GenData and CheckFlag bits), these bits indicate which key was used in its computation. + * \var atca_temp_key::source_flag + * \brief The source of the randomness in TempKey: 0=Rand, 1=Input. + * \var atca_temp_key::gen_data + * \brief Indicates if TempKey has been generated by GenDig using Data zone. + * \var atca_temp_key::check_flag + * \brief Not used in the library. + * \var atca_temp_key::valid + * \brief Indicates if the information in TempKey is valid. + */ +typedef struct atca_temp_key { + uint8_t value[ATAC_STANDARD_KEY_SIZE]; + unsigned int key_id : 4; + unsigned int source_flag : 1; + unsigned int gen_data : 1; + unsigned int check_flag : 1; + unsigned int valid : 1; +} atca_temp_key_t; + + +/** \struct atca_include_data_in_out + * \brief Input / output parameters for function atca_include_data(). + * \var atca_include_data_in_out::p_temp + * \brief [out] pointer to output buffer + * \var atca_include_data_in_out::otp + * \brief [in] pointer to one-time-programming data + * \var atca_include_data_in_out::sn + * \brief [in] pointer to serial number data + */ +struct atca_include_data_in_out { + uint8_t *p_temp; + const uint8_t *otp; + const uint8_t *sn; + uint8_t mode; +}; + + +/** \struct atca_nonce_in_out + * \brief Input/output parameters for function atca_nonce(). + * \var atca_nonce_in_out::mode + * \brief [in] Mode parameter used in Nonce command (Param1). + * \var atca_nonce_in_out::num_in + * \brief [in] Pointer to 20-byte NumIn data used in Nonce command. + * \var atca_nonce_in_out::rand_out + * \brief [in] Pointer to 32-byte RandOut data from Nonce command. + * \var atca_nonce_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +typedef struct atca_nonce_in_out { + uint8_t mode; + const uint8_t *num_in; + uint8_t *rand_out; + struct atca_temp_key *temp_key; +} atca_nonce_in_out_t; + + +/** \struct atca_mac_in_out + * \brief Input/output parameters for function atca_mac(). + * \var atca_mac_in_out::mode + * \brief [in] Mode parameter used in MAC command (Param1). + * \var atca_mac_in_out::key_id + * \brief [in] KeyID parameter used in MAC command (Param2). + * \var atca_mac_in_out::challenge + * \brief [in] Pointer to 32-byte Challenge data used in MAC command, depending on mode. + * \var atca_mac_in_out::key + * \brief [in] Pointer to 32-byte key used to generate MAC digest. + * \var atca_mac_in_out::otp + * \brief [in] Pointer to 11-byte OTP, optionally included in MAC digest, depending on mode. + * \var atca_mac_in_out::sn + * \brief [in] Pointer to 9-byte SN, optionally included in MAC digest, depending on mode. + * \var atca_mac_in_out::response + * \brief [out] Pointer to 32-byte SHA-256 digest (MAC). + * \var atca_mac_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_mac_in_out { + uint8_t mode; + uint16_t key_id; + const uint8_t *challenge; + const uint8_t *key; + const uint8_t *otp; + const uint8_t *sn; + uint8_t *response; + struct atca_temp_key *temp_key; +}; + + +/** \struct atca_hmac_in_out + * \brief Input/output parameters for function atca_hmac(). + * \var atca_hmac_in_out::mode + * \brief [in] Mode parameter used in HMAC command (Param1). + * \var atca_hmac_in_out::key_id + * \brief [in] KeyID parameter used in HMAC command (Param2). + * \var atca_hmac_in_out::key + * \brief [in] Pointer to 32-byte key used to generate HMAC digest. + * \var atca_hmac_in_out::otp + * \brief [in] Pointer to 11-byte OTP, optionally included in HMAC digest, depending on mode. + * \var atca_hmac_in_out::sn + * \brief [in] Pointer to 9-byte SN, optionally included in HMAC digest, depending on mode. + * \var atca_hmac_in_out::response + * \brief [out] Pointer to 32-byte SHA-256 HMAC digest. + * \var atca_hmac_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_hmac_in_out { + uint8_t mode; + uint16_t key_id; + const uint8_t *key; + const uint8_t *otp; + const uint8_t *sn; + uint8_t *response; + struct atca_temp_key *temp_key; +}; + + +/** \struct atca_gen_dig_in_out + * \brief Input/output parameters for function atca_gen_dig(). + * \var atca_gen_dig_in_out::zone + * \brief [in] Zone parameter used in GenDig command (Param1). + * \var atca_gen_dig_in_out::key_id + * \brief [in] KeyID parameter used in GenDig command (Param2). + * \var atca_gen_dig_in_out::stored_value + * \brief [in] Pointer to 32-byte stored value, can be a data slot, OTP page, configuration zone, or hardware transport key. + * \var atca_gen_dig_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +typedef struct atca_gen_dig_in_out { + uint8_t zone; + uint16_t key_id; + const uint8_t *stored_value; + struct atca_temp_key *temp_key; +} atca_gen_dig_in_out_t; + +/** \struct atca_write_mac_in_out + * \brief Input/output parameters for function atca_auth_mac(). + * \var atca_write_mac_in_out::zone + * \brief [in] Zone parameter used in PrivWrite command (Param1). + * \var atca_write_mac_in_out::key_id + * \brief [in] KeyID parameter used in PrivWrite command (Param2). + * \var atca_write_mac_in_out::encryption_key + * \brief [in] Pointer to 32-byte key. + * \var atca_write_mac_in_out::input_data + * \brief [in] Pointer to 36-byte data value, Input cleartext data. + * \var atca_write_mac_in_out::encrypted_data + * \brief [out] Pointer to 32-byte data. Output encrypted data to MAC command. + * \var atca_write_mac_in_out::auth_mac + * \brief [out] Pointer to 32-byte Mac. + * \var atca_write_mac_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +typedef struct atca_write_mac_in_out { + uint8_t zone; + uint16_t key_id; + const uint8_t *encryption_key; + const uint8_t *input_data; + uint8_t *encrypted_data; // out + uint8_t *auth_mac; // out + struct atca_temp_key *temp_key; // in +} atca_write_mac_in_out_t; + +/** \struct atca_derive_key_in_out + * \brief Input/output parameters for function atca_derive_key(). + * \var atca_derive_key_in_out::random + * \brief [in] Random parameter used in DeriveKey command (Param1). + * \var atca_derive_key_in_out::target_key_id + * \brief [in] KeyID to be derived, TargetKey parameter used in DeriveKey command (Param2). + * \var atca_derive_key_in_out::parent_key + * \brief [in] Pointer to 32-byte ParentKey. Set equal to target_key if Roll Key operation is intended. + * \var atca_derive_key_in_out::target_key + * \brief [out] Pointer to 32-byte TargetKey. + * \var atca_derive_key_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_derive_key_in_out { + uint8_t random; + uint16_t target_key_id; + const uint8_t *parent_key; + uint8_t *target_key; + struct atca_temp_key *temp_key; +}; + + +/** \struct atca_derive_key_mac_in_out + * \brief Input/output parameters for function atca_derive_key_mac(). + * \var atca_derive_key_mac_in_out::random + * \brief [in] Random parameter used in DeriveKey command (Param1). + * \var atca_derive_key_mac_in_out::target_key_id + * \brief [in] KeyID to be derived, TargetKey parameter used in DeriveKey command (Param2). + * \var atca_derive_key_mac_in_out::parent_key + * \brief [in] Pointer to 32-byte ParentKey. ParentKey here is always SlotConfig[TargetKey].WriteKey, regardless whether the operation is Roll or Create. + * \var atca_derive_key_mac_in_out::mac + * \brief [out] Pointer to 32-byte Mac. + */ +struct atca_derive_key_mac_in_out { + uint8_t random; + uint16_t target_key_id; + const uint8_t *parent_key; + uint8_t *mac; +}; + + +/** \struct atca_encrypt_in_out + * \brief Input/output parameters for function atca_encrypt(). + * \var atca_encrypt_in_out::zone + * \brief [in] Zone parameter used in Write (Param1). + * \var atca_encrypt_in_out::address + * \brief [in] Address parameter used in Write command (Param2). + * \var atca_encrypt_in_out::crypto_data + * \brief [in,out] Pointer to 32-byte data. Input cleartext data, output encrypted data to Write command (Value field). + * \var atca_encrypt_in_out::mac + * \brief [out] Pointer to 32-byte Mac. Can be set to NULL if input MAC is not required by the Write command (write to OTP, unlocked user zone). + * \var atca_encrypt_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_encrypt_in_out { + uint8_t zone; + uint16_t address; + uint8_t *crypto_data; + uint8_t *mac; + struct atca_temp_key *temp_key; +}; + + +/** \struct atca_decrypt_in_out + * \brief Input/output parameters for function atca_decrypt(). + * \var atca_decrypt_in_out::crypto_data + * \brief [in,out] Pointer to 32-byte data. Input encrypted data from Read command (Contents field), output decrypted. + * \var atca_decrypt_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_decrypt_in_out { + uint8_t *crypto_data; + struct atca_temp_key *temp_key; +}; + + +/** \struct atca_check_mac_in_out + * \brief Input/output parameters for function atca_check_mac(). + * \var atca_check_mac_in_out::mode + * \brief [in] Mode parameter used in CheckMac command (Param1). + * \var atca_check_mac_in_out::password + * \brief [in] Pointer to 32-byte password that will be verified against Key[KeyID] in the Device. + * \var atca_check_mac_in_out::other_data + * \brief [in] Pointer to 13-byte OtherData that will be used in CheckMac command. + * \var atca_check_mac_in_out::otp + * \brief [in] Pointer to 11-byte OTP. OTP[0:7] is included in the calculation if Mode bit 5 is one. + * \var atca_check_mac_in_out::target_key + * \brief [in] Pointer to 32-byte TargetKey that will be copied to TempKey. + * \var atca_check_mac_in_out::client_resp + * \brief [out] Pointer to 32-byte ClientResp to be used in CheckMac command. + * \var atca_check_mac_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_check_mac_in_out { + uint8_t mode; + const uint8_t *password; + const uint8_t *other_data; + const uint8_t *otp; + const uint8_t *target_key; + uint8_t *client_resp; + struct atca_temp_key *temp_key; +}; + + +/** \struct atca_verify_in_out + * \brief Input/output parameters for function atca_verify(). + * \var atca_verify_in_out::curve_type + * \brief [in] Curve type used in Verify command (Param2). + * \var atca_verify_in_out::signature + * \brief [in] Pointer to ECDSA signature to be verified + * \var atca_verify_in_out::public_key + * \brief [in] Pointer to the public key to be used for verification + * \var atca_verify_in_out::temp_key + * \brief [in,out] Pointer to TempKey structure. + */ +struct atca_verify_in_out { + uint16_t curve_type; + const uint8_t *signature; + const uint8_t *public_key; + struct atca_temp_key *temp_key; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +ATCA_STATUS atcah_nonce(struct atca_nonce_in_out *param); +ATCA_STATUS atcah_mac(struct atca_mac_in_out *param); +ATCA_STATUS atcah_check_mac(struct atca_check_mac_in_out *param); +ATCA_STATUS atcah_hmac(struct atca_hmac_in_out *param); +ATCA_STATUS atcah_gen_dig(struct atca_gen_dig_in_out *param); +ATCA_STATUS atcah_gen_mac(struct atca_gen_dig_in_out *param); +ATCA_STATUS atcah_write_auth_mac(struct atca_write_mac_in_out *param); +ATCA_STATUS atcah_privwrite_auth_mac(struct atca_write_mac_in_out *param); +ATCA_STATUS atcah_derive_key(struct atca_derive_key_in_out *param); +ATCA_STATUS atcah_derive_key_mac(struct atca_derive_key_mac_in_out *param); +ATCA_STATUS atcah_encrypt(struct atca_encrypt_in_out *param); +ATCA_STATUS atcah_decrypt(struct atca_decrypt_in_out *param); +ATCA_STATUS atcah_sha256(int32_t len, const uint8_t *message, uint8_t *digest); +uint8_t *atcah_include_data(struct atca_include_data_in_out *param); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif //ATCA_HOST_H