Merge pull request #41 from fallberg/development

SHA204 library and personalization sketch
This commit is contained in:
Henrik Ekblad
2015-01-10 20:32:59 +01:00
4 changed files with 2135 additions and 0 deletions
@@ -0,0 +1,947 @@
/* SHA204 personalization sketch
by: Patrick Fallberg
date: January 10, 2015
This sketch will write factory default settings to the configuration zone
and then lock it.
It will then either
a. Generate a random value to use as a key which will be stored in
slot 0. The key is printed on UART (115200) in clear text for the user to be
able to use it as a user-supplied key in other personalization executions
where the same key is needed.
b. Use a user-supplied value to use as a key which will be stored in
slot 0.
Finally it will lock the data zone.
By default, no locking is performed. User have to manually enable the flags that
turn on the locking. Furthermore, user have to send a SPACE character on serial
console when prompted to do any locking.
Default settings use ATSHA204 on pin 7.
*/
#include <sha204_library.h>
#include <sha204_lib_return_codes.h>
// The pin the ATSHA204 is connected on
#define ATSHA204_PIN 7
// Uncomment this to enable locking the configuration zone.
// *** BE AWARE THAT THIS PREVENTS ANY FUTURE CONFIGURATION CHANGE TO THE CHIP ***
// It is still possible to change the key, and this also enable random key generation
//#define LOCK_CONFIGURATION
// Uncomment this to enable locking the data zone.
// *** BE AWARE THAT THIS PREVENTS THE KEY TO BE CHANGED ***
// It is not required to lock data, key cannot be retrieved anyway, but by locking
// data, it can be guaranteed that nobody even with physical access to the chip,
// will be able to change the key.
//#define LOCK_DATA
// Uncomment this to skip key storage (typically once key has been written once)
//#define SKIP_KEY_STORAGE
// Uncomment this to skip key data storage (once configuration is locked, key
// will aways randomize )
// Uncomment this to skip key generation and use 'user_key_data' as key instead.
//#define USER_KEY_DATA
#ifdef USER_KEY_DATA
const uint8_t user_key_data[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
#endif
const int sha204Pin = ATSHA204_PIN;
atsha204Class sha204(sha204Pin);
void halt()
{
Serial.println(F("Halting!"));
while(1);
}
uint16_t write_config_and_get_crc()
{
uint16_t crc = 0;
uint8_t config_word[4];
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
bool do_write;
// We will set default settings from datasheet on all slots. This means that we can use slot 0 for the key
// as that slot will not be readable (key will therefore be secure) and slot 8 for the payload digest
// calculationon as that slot can be written in clear text even when the datazone is locked.
// Other settings which are not relevant are kept as is.
for (int i=0; i < 88; i += 4)
{
do_write = true;
if (i == 20)
{
config_word[0] = 0x8F;
config_word[1] = 0x80;
config_word[2] = 0x80;
config_word[3] = 0xA1;
}
else if (i == 24)
{
config_word[0] = 0x82;
config_word[1] = 0xE0;
config_word[2] = 0xA3;
config_word[3] = 0x60;
}
else if (i == 28)
{
config_word[0] = 0x94;
config_word[1] = 0x40;
config_word[2] = 0xA0;
config_word[3] = 0x85;
}
else if (i == 32)
{
config_word[0] = 0x86;
config_word[1] = 0x40;
config_word[2] = 0x87;
config_word[3] = 0x07;
}
else if (i == 36)
{
config_word[0] = 0x0F;
config_word[1] = 0x00;
config_word[2] = 0x89;
config_word[3] = 0xF2;
}
else if (i == 40)
{
config_word[0] = 0x8A;
config_word[1] = 0x7A;
config_word[2] = 0x0B;
config_word[3] = 0x8B;
}
else if (i == 44)
{
config_word[0] = 0x0C;
config_word[1] = 0x4C;
config_word[2] = 0xDD;
config_word[3] = 0x4D;
}
else if (i == 48)
{
config_word[0] = 0xC2;
config_word[1] = 0x42;
config_word[2] = 0xAF;
config_word[3] = 0x8F;
}
else if (i == 52 || i == 56 || i == 60 || i == 64)
{
config_word[0] = 0xFF;
config_word[1] = 0x00;
config_word[2] = 0xFF;
config_word[3] = 0x00;
}
else if (i == 68 || i == 72 || i == 76 || i == 80)
{
config_word[0] = 0xFF;
config_word[1] = 0xFF;
config_word[2] = 0xFF;
config_word[3] = 0xFF;
}
else
{
// All other configs are untouched
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to read config. Response: ")); Serial.println(ret_code, HEX);
halt();
}
// Set config_word to the read data
config_word[0] = rx_buffer[SHA204_BUFFER_POS_DATA+0];
config_word[1] = rx_buffer[SHA204_BUFFER_POS_DATA+1];
config_word[2] = rx_buffer[SHA204_BUFFER_POS_DATA+2];
config_word[3] = rx_buffer[SHA204_BUFFER_POS_DATA+3];
do_write = false;
}
// Update crc with CRC for the current word
crc = sha204.calculateAndUpdateCrc(4, config_word, crc);
// Write config word
if (do_write)
{
ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_CONFIG,
i >> 2, 4, config_word, 0, NULL, 0, NULL,
WRITE_COUNT_SHORT, tx_buffer, WRITE_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to write config word at address ")); Serial.print(i);
Serial.print(F(". Response: ")); Serial.println(ret_code, HEX);
halt();
}
}
}
return crc;
}
void write_key(uint8_t* key)
{
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
// Write key to slot 0
ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG,
0, SHA204_ZONE_ACCESS_32, key, 0, NULL, 0, NULL,
WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to write key to slot 0. Response: ")); Serial.println(ret_code, HEX);
halt();
}
}
void dump_configuration()
{
uint8_t config_word[4];
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t ret_code;
for (int i=0; i < 88; i += 4)
{
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to read config. Response: ")); Serial.println(ret_code, HEX);
halt();
}
if (i == 0x00)
{
Serial.print(F(" SN[0:1] | SN[2:3] | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x04)
{
Serial.print(F(" Revnum | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
}
else if (i == 0x08)
{
Serial.print(F(" SN[4:7] | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
}
else if (i == 0x0C)
{
Serial.print(F(" SN[8] | Reserved13 | I2CEnable | Reserved15 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j < 3)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x10)
{
Serial.print(F(" I2CAddress | TempOffset | OTPmode | SelectorMode | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j < 3)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x14)
{
Serial.print(F(" SlotConfig00 | SlotConfig01 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x18)
{
Serial.print(F(" SlotConfig02 | SlotConfig03 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x1C)
{
Serial.print(F(" SlotConfig04 | SlotConfig05 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x20)
{
Serial.print(F(" SlotConfig06 | SlotConfig07 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x24)
{
Serial.print(F(" SlotConfig08 | SlotConfig09 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x28)
{
Serial.print(F(" SlotConfig0A | SlotConfig0B | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x2C)
{
Serial.print(F(" SlotConfig0C | SlotConfig0D | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x30)
{
Serial.print(F(" SlotConfig0E | SlotConfig0F | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j == 1)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x34)
{
Serial.print(F(" UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j < 3)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x38)
{
Serial.print(F(" UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j < 3)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x3C)
{
Serial.print(F(" UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j < 3)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x40)
{
Serial.print(F(" UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j < 3)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
else if (i == 0x44)
{
Serial.print(F(" LastKeyUse[0:3] | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
}
else if (i == 0x48)
{
Serial.print(F(" LastKeyUse[4:7] | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
}
else if (i == 0x4C)
{
Serial.print(F(" LastKeyUse[8:B] | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
}
else if (i == 0x50)
{
Serial.print(F(" LastKeyUse[C:F] | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
Serial.print(F(" "));
}
Serial.println();
}
else if (i == 0x54)
{
Serial.print(F(" UserExtra | Selector | LockValue | LockConfig | "));
for (int j=0; j<4; j++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX);
if (j < 3)
{
Serial.print(F(" | "));
}
else
{
Serial.print(F(" "));
}
}
Serial.println();
}
}
}
void setup()
{
uint8_t tx_buffer[SHA204_CMD_SIZE_MAX];
uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
uint8_t key[32];
uint8_t ret_code;
uint8_t lockConfig = 0;
uint8_t lockValue = 0;
uint16_t crc;
Serial.begin(115200);
Serial.println(F("ATSHA204 personalization sketch for MySensors usage."));
Serial.println(F("----------------------------------------------------"));
// Wake device before starting operations
ret_code = sha204.sha204c_wakeup(rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX);
halt();
}
// Output device revision on console
ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to determine device revision. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
Serial.print(F("Device revision: "));
for (int i=0; i<4; i++)
{
if (rx_buffer[SHA204_BUFFER_POS_DATA+i] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+i], HEX);
}
Serial.println();
}
// Output serial number on console
ret_code = sha204.getSerialNumber(rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
Serial.print(F("Device serial: "));
for (int i=0; i<9; i++)
{
if (rx_buffer[i] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(rx_buffer[i], HEX);
}
Serial.println();
}
// Read out lock config bits to determine if locking is possible
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
if (lockConfig != 0x00)
{
// Write config and get CRC for the updated config
crc = write_config_and_get_crc();
// List current configuration before attempting to lock
Serial.println(F("Chip configuration:"));
dump_configuration();
#ifdef LOCK_CONFIGURATION
// Purge serial input buffer
while (Serial.available())
{
Serial.read();
}
Serial.println(F("Send SPACE character now to lock the configuration..."));
while (Serial.available() == 0);
if (Serial.read() == ' ')
{
Serial.println(F("Locking configuration..."));
// Correct sequence, resync chip
ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer);
if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP)
{
Serial.print(F("Resync failed. Response: ")); Serial.println(ret_code, HEX);
halt();
}
// Lock configuration zone
ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_CONFIG,
crc, 0, NULL, 0, NULL, 0, NULL,
LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Configuration lock failed. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
Serial.println(F("Configuration locked."));
// Update lock flags after locking
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
}
}
else
{
Serial.println(F("Unexpected answer. Skipping lock."));
}
#else //LOCK_CONFIGURATION
Serial.println(F("Dry-run. Configuration not locked. Define LOCK_CONFIGURATION to lock for real."));
#endif
}
else
{
Serial.println(F("Skipping configuration write and lock (configuration already locked)."));
Serial.println(F("Chip configuration:"));
dump_configuration();
}
#ifdef SKIP_KEY_STORAGE
Serial.println(F("Disable SKIP_KEY_STORAGE to store key."));
#else
#ifdef USER_KEY_DATA
memcpy(key, user_key_data, 32);
Serial.print(F("Using this user supplied key: "));
#else
// Retrieve random value to use as key
ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Random key generation failed. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32);
}
if (lockConfig == 0x00)
{
Serial.println(F("Take note of this key, it will never be the shown again:"));
}
else
{
Serial.println(F("Key is not randomized (configuration not locked):"));
}
#endif
for (int i=0; i<32; i++)
{
if (key[i] < 0x10)
{
Serial.print('0'); // Because Serial.print does not 0-pad HEX
}
Serial.print(key[i], HEX);
}
Serial.println();
// It will not be possible to write the key if the configuration zone is unlocked
if (lockConfig == 0x00)
{
// Write the key to the appropriate slot in the data zone
Serial.println(F("Writing key to slot 0..."));
write_key(key);
}
else
{
Serial.println(F("Skipping key storage (configuration not locked)."));
Serial.println(F("The configuration must be locked to be able to write a key."));
}
#endif
if (lockValue != 0x00)
{
#ifdef LOCK_DATA
while (Serial.available())
{
Serial.read();
}
Serial.println(F("Send SPACE character to lock data..."));
while (Serial.available() == 0);
if (Serial.read() == ' ')
{
// Correct sequence, resync chip
ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer);
if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP)
{
Serial.print(F("Resync failed. Response: ")); Serial.println(ret_code, HEX);
halt();
}
// If configuration is unlocked, key is not updated. Locking data in this case will cause
// slot 0 to contain an unknown (or factory default) key, and this is in practically any
// usecase not the desired behaviour, so ask for additional confirmation in this case.
if (lockConfig != 0x00)
{
while (Serial.available())
{
Serial.read();
}
Serial.println(F("*** ATTENTION ***"));
Serial.println(F("Configuration is not locked. Are you ABSULOUTELY SURE you want to lock data?"));
Serial.println(F("Locking data at this stage will cause slot 0 to contain a factory default key"));
Serial.println(F("which cannot be change after locking is done. This is in practically any usecase"));
Serial.println(F("NOT the desired behavour. Send SPACE character now to lock data anyway..."));
while (Serial.available() == 0);
if (Serial.read() != ' ')
{
Serial.println(F("Unexpected answer. Skipping lock."));
halt();
}
}
// Lock data zone
ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_DATA | LOCK_ZONE_NO_CRC,
0x0000, 0, NULL, 0, NULL, 0, NULL,
LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Data lock failed. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
Serial.println(F("Data locked."));
// Update lock flags after locking
ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2);
if (ret_code != SHA204_SUCCESS)
{
Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX);
halt();
}
else
{
lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3];
lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2];
}
}
}
else
{
Serial.println(F("Unexpected answer. Skipping lock."));
}
#else //LOCK_DATA
Serial.println(F("Dry-run. Data not locked. Define LOCK_DATA to lock for real."));
#endif
}
else
{
Serial.println(F("Skipping OTP/data zone lock (zone already locked)."));
}
Serial.println(F("--------------------------------"));
Serial.println(F("Personalization is now complete."));
Serial.print(F("Configuration is "));
if (lockConfig == 0x00)
{
Serial.println("LOCKED");
}
else
{
Serial.println("UNLOCKED");
}
Serial.print(F("Data is "));
if (lockValue == 0x00)
{
Serial.println("LOCKED");
}
else
{
Serial.println("UNLOCKED");
}
}
void loop()
{
}
@@ -0,0 +1,48 @@
// ----------------------------------------------------------------------------
// ATMEL Microcontroller Software Support - Colorado Springs, CO -
// ----------------------------------------------------------------------------
// DISCLAIMER: 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
// 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.
// ----------------------------------------------------------------------------
/** \file
* \brief SHA204 Library Return Code Definitions
* \author Atmel Crypto Products
* \date September 27, 2010
*/
#ifndef SHA204_LIB_RETURN_CODES_H
# define SHA204_LIB_RETURN_CODES_H
#include <stddef.h> // data type definitions
/** \todo Use same values for same meanings for SHA204 and AES132.
* */
#define SHA204_SUCCESS ((uint8_t) 0x00) //!< Function succeeded.
#define SHA204_PARSE_ERROR ((uint8_t) 0xD2) //!< response status byte indicates parsing error
#define SHA204_CMD_FAIL ((uint8_t) 0xD3) //!< response status byte indicates command execution error
#define SHA204_STATUS_CRC ((uint8_t) 0xD4) //!< response status byte indicates CRC error
#define SHA204_STATUS_UNKNOWN ((uint8_t) 0xD5) //!< response status byte is unknown
#define SHA204_FUNC_FAIL ((uint8_t) 0xE0) //!< Function could not execute due to incorrect condition / state.
#define SHA204_GEN_FAIL ((uint8_t) 0xE1) //!< unspecified error
#define SHA204_BAD_PARAM ((uint8_t) 0xE2) //!< bad argument (out of range, null pointer, etc.)
#define SHA204_INVALID_ID ((uint8_t) 0xE3) //!< invalid device id, id not set
#define SHA204_INVALID_SIZE ((uint8_t) 0xE4) //!< Count value is out of range or greater than buffer size.
#define SHA204_BAD_CRC ((uint8_t) 0xE5) //!< incorrect CRC received
#define SHA204_RX_FAIL ((uint8_t) 0xE6) //!< Timed out while waiting for response. Number of bytes received is > 0.
#define SHA204_RX_NO_RESPONSE ((uint8_t) 0xE7) //!< Not an error while the Command layer is polling for a command response.
#define SHA204_RESYNC_WITH_WAKEUP ((uint8_t) 0xE8) //!< re-synchronization succeeded, but only after generating a Wake-up
#define SHA204_COMM_FAIL ((uint8_t) 0xF0) //!< Communication with device failed. Same as in hardware dependent modules.
#define SHA204_TIMEOUT ((uint8_t) 0xF1) //!< Timed out while waiting for response. Number of bytes received is 0.
#endif
+819
View File
@@ -0,0 +1,819 @@
#include "Arduino.h"
#include "sha204_library.h"
#include "sha204_includes/sha204_lib_return_codes.h"
// atsha204Class Constructor
// Feed this function the Arduino-ized pin number you want to assign to the ATSHA204's SDA pin
// This will find the DDRX, PORTX, and PINX registrs it'll need to point to to control that pin
// As well as the bit value for each of those registers
atsha204Class::atsha204Class(uint8_t pin)
{
device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin
uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers
// Point to data direction register port of pin
device_port_DDR = portModeRegister(port);
// Point to output register of pin
device_port_OUT = portOutputRegister(port);
// Point to input register of pin
device_port_IN = portInputRegister(port);
}
/* Puts a the ATSHA204's unique, 4-byte serial number in the response array
returns an SHA204 Return code */
uint8_t atsha204Class::getSerialNumber(uint8_t * response)
{
uint8_t readCommand[READ_COUNT];
uint8_t readResponse[READ_4_RSP_SIZE];
/* read from bytes 0->3 of config zone */
uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03);
if (!returnCode) // should return 0 if successful
{
for (int i=0; i<4; i++) // store bytes 0-3 into respones array
response[i] = readResponse[SHA204_BUFFER_POS_DATA+i];
/* read from bytes 8->11 of config zone */
returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47);
for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array
response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)];
if (!returnCode)
{ /* Finally if last two reads were successful, read byte 8 of the SN */
returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8);
response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE
}
}
return returnCode;
}
/* Calculates CRC16 value of provided data (and optionally including provided existing CRC16 data)
returns the calculated CRC16 value */
uint16_t atsha204Class::calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc)
{
uint8_t counter;
uint16_t crc_register = current_crc;
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;
// Shift CRC to the left by 1.
crc_register <<= 1;
if ((data_bit ^ crc_bit) != 0)
crc_register ^= polynom;
}
}
return crc_register;
}
/* SWI bit bang functions */
void atsha204Class::swi_set_signal_pin(uint8_t is_high)
{
*device_port_DDR |= device_pin;
if (is_high)
*device_port_OUT |= device_pin;
else
*device_port_OUT &= ~device_pin;
}
uint8_t atsha204Class::swi_send_bytes(uint8_t count, uint8_t *buffer)
{
uint8_t i, bit_mask;
// Disable interrupts while sending.
noInterrupts(); //swi_disable_interrupts();
// Set signal pin as output.
*device_port_OUT |= device_pin;
*device_port_DDR |= device_pin;
// Wait turn around time.
delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY;
for (i = 0; i < count; i++)
{
for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1)
{
if (bit_mask & buffer[i])
{
*device_port_OUT &= ~device_pin;
delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
*device_port_OUT |= device_pin;
delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7;
}
else
{
// Send a zero bit.
*device_port_OUT &= ~device_pin;
delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
*device_port_OUT |= device_pin;
delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
*device_port_OUT &= ~device_pin;
delayMicroseconds(BIT_DELAY); //BIT_DELAY_1;
*device_port_OUT |= device_pin;
delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5;
}
}
}
interrupts(); //swi_enable_interrupts();
return SWI_FUNCTION_RETCODE_SUCCESS;
}
uint8_t atsha204Class::swi_send_byte(uint8_t value)
{
return swi_send_bytes(1, &value);
}
uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer)
{
uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS;
uint8_t i;
uint8_t bit_mask;
uint8_t pulse_count;
uint8_t timeout_count;
// Disable interrupts while receiving.
noInterrupts(); //swi_disable_interrupts();
// Configure signal pin as input.
*device_port_DDR &= ~device_pin;
// Receive bits and store in buffer.
for (i = 0; i < count; i++)
{
for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1)
{
pulse_count = 0;
// Make sure that the variable below is big enough.
// Change it to uint16_t if 255 is too small, but be aware that
// the loop resolution decreases on an 8-bit controller in that case.
timeout_count = START_PULSE_TIME_OUT;
// Detect start bit.
while (--timeout_count > 0)
{
// Wait for falling edge.
if ((*device_port_IN & device_pin) == 0)
break;
}
if (timeout_count == 0)
{
status = SWI_FUNCTION_RETCODE_TIMEOUT;
break;
}
do
{
// Wait for rising edge.
if ((*device_port_IN & device_pin) != 0)
{
// For an Atmel microcontroller this might be faster than "pulse_count++".
pulse_count = 1;
break;
}
} while (--timeout_count > 0);
if (pulse_count == 0)
{
status = SWI_FUNCTION_RETCODE_TIMEOUT;
break;
}
// Trying to measure the time of start bit and calculating the timeout
// for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU.
// So let's just wait the maximum time for the falling edge of a zero bit
// to arrive after we have detected the rising edge of the start bit.
timeout_count = ZERO_PULSE_TIME_OUT;
// Detect possible edge indicating zero bit.
do
{
if ((*device_port_IN & device_pin) == 0)
{
// For an Atmel microcontroller this might be faster than "pulse_count++".
pulse_count = 2;
break;
}
} while (--timeout_count > 0);
// Wait for rising edge of zero pulse before returning. Otherwise we might interpret
// its rising edge as the next start pulse.
if (pulse_count == 2)
{
do
{
if ((*device_port_IN & device_pin) != 0)
break;
} while (timeout_count-- > 0);
}
// Update byte at current buffer index.
else
buffer[i] |= bit_mask; // received "one" bit
}
if (status != SWI_FUNCTION_RETCODE_SUCCESS)
break;
}
interrupts(); //swi_enable_interrupts();
if (status == SWI_FUNCTION_RETCODE_TIMEOUT)
{
if (i > 0)
// Indicate that we timed out after having received at least one byte.
status = SWI_FUNCTION_RETCODE_RX_FAIL;
}
return status;
}
/* Physical functions */
uint8_t atsha204Class::sha204p_wakeup()
{
swi_set_signal_pin(0);
delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH);
swi_set_signal_pin(1);
delay(SHA204_WAKEUP_DELAY);
return SHA204_SUCCESS;
}
uint8_t atsha204Class::sha204p_sleep()
{
return swi_send_byte(SHA204_SWI_FLAG_SLEEP);
}
uint8_t atsha204Class::sha204p_resync(uint8_t size, uint8_t *response)
{
delay(SHA204_SYNC_TIMEOUT);
return sha204p_receive_response(size, response);
}
uint8_t atsha204Class::sha204p_receive_response(uint8_t size, uint8_t *response)
{
uint8_t count_byte;
uint8_t i;
uint8_t ret_code;
for (i = 0; i < size; i++)
response[i] = 0;
(void) swi_send_byte(SHA204_SWI_FLAG_TX);
ret_code = swi_receive_bytes(size, response);
if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL)
{
count_byte = response[SHA204_BUFFER_POS_COUNT];
if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size))
return SHA204_INVALID_SIZE;
return SHA204_SUCCESS;
}
// Translate error so that the Communication layer
// can distinguish between a real error or the
// device being busy executing a command.
if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT)
return SHA204_RX_NO_RESPONSE;
else
return SHA204_RX_FAIL;
}
uint8_t atsha204Class::sha204p_send_command(uint8_t count, uint8_t * command)
{
uint8_t ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD);
if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS)
return SHA204_COMM_FAIL;
return swi_send_bytes(count, command);
}
/* Communication functions */
uint8_t atsha204Class::sha204c_wakeup(uint8_t *response)
{
uint8_t ret_code = sha204p_wakeup();
if (ret_code != SHA204_SUCCESS)
return ret_code;
ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response);
if (ret_code != SHA204_SUCCESS)
return ret_code;
// Verify status response.
if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN)
ret_code = SHA204_INVALID_SIZE;
else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP)
ret_code = SHA204_COMM_FAIL;
else
{
if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33)
|| (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43))
ret_code = SHA204_BAD_CRC;
}
if (ret_code != SHA204_SUCCESS)
delay(SHA204_COMMAND_EXEC_MAX);
return ret_code;
}
uint8_t atsha204Class::sha204c_resync(uint8_t size, uint8_t *response)
{
// Try to re-synchronize without sending a Wake token
// (step 1 of the re-synchronization process).
uint8_t ret_code = sha204p_resync(size, response);
if (ret_code == SHA204_SUCCESS)
return ret_code;
// We lost communication. Send a Wake pulse and try
// to receive a response (steps 2 and 3 of the
// re-synchronization process).
(void) sha204p_sleep();
ret_code = sha204c_wakeup(response);
// Translate a return value of success into one
// that indicates that the device had to be woken up
// and might have lost its TempKey.
return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code);
}
uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout)
{
uint8_t ret_code = SHA204_FUNC_FAIL;
uint8_t ret_code_resync;
uint8_t n_retries_send;
uint8_t n_retries_receive;
uint8_t i;
uint8_t status_byte;
uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT];
uint8_t count_minus_crc = count - SHA204_CRC_SIZE;
uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT;
volatile uint16_t timeout_countdown;
// Append CRC.
sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc);
// Retry loop for sending a command and receiving a response.
n_retries_send = SHA204_RETRY_COUNT + 1;
while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS))
{
// Send command.
ret_code = sha204p_send_command(count, tx_buffer);
if (ret_code != SHA204_SUCCESS)
{
if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE)
return ret_code; // The device seems to be dead in the water.
else
continue;
}
// Wait minimum command execution time and then start polling for a response.
delay(execution_delay);
// Retry loop for receiving a response.
n_retries_receive = SHA204_RETRY_COUNT + 1;
while (n_retries_receive-- > 0)
{
// Reset response buffer.
for (i = 0; i < rx_size; i++)
rx_buffer[i] = 0;
// Poll for response.
timeout_countdown = execution_timeout_us;
do
{
ret_code = sha204p_receive_response(rx_size, rx_buffer);
timeout_countdown -= SHA204_RESPONSE_TIMEOUT;
}
while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE));
if (ret_code == SHA204_RX_NO_RESPONSE)
{
// We did not receive a response. Re-synchronize and send command again.
if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE)
// The device seems to be dead in the water.
return ret_code;
else
break;
}
// Check whether we received a valid response.
if (ret_code == SHA204_INVALID_SIZE)
{
// We see 0xFF for the count when communication got out of sync.
ret_code_resync = sha204c_resync(rx_size, rx_buffer);
if (ret_code_resync == SHA204_SUCCESS)
// We did not have to wake up the device. Try receiving response again.
continue;
if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP)
// We could re-synchronize, but only after waking up the device.
// Re-send command.
break;
else
// We failed to re-synchronize.
return ret_code;
}
// We received a response of valid size.
// Check the consistency of the response.
ret_code = sha204c_check_crc(rx_buffer);
if (ret_code == SHA204_SUCCESS)
{
// Received valid response.
if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN)
// Received non-status response. We are done.
return ret_code;
// Received status response.
status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS];
// Translate the three possible device status error codes
// into library return codes.
if (status_byte == SHA204_STATUS_BYTE_PARSE)
return SHA204_PARSE_ERROR;
if (status_byte == SHA204_STATUS_BYTE_EXEC)
return SHA204_CMD_FAIL;
if (status_byte == SHA204_STATUS_BYTE_COMM)
{
// In case of the device status byte indicating a communication
// error this function exits the retry loop for receiving a response
// and enters the overall retry loop
// (send command / receive response).
ret_code = SHA204_STATUS_CRC;
break;
}
// Received status response from CheckMAC, DeriveKey, GenDig,
// Lock, Nonce, Pause, UpdateExtra, or Write command.
return ret_code;
}
else
{
// Received response with incorrect CRC.
ret_code_resync = sha204c_resync(rx_size, rx_buffer);
if (ret_code_resync == SHA204_SUCCESS)
// We did not have to wake up the device. Try receiving response again.
continue;
if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP)
// We could re-synchronize, but only after waking up the device.
// Re-send command.
break;
else
// We failed to re-synchronize.
return ret_code;
} // block end of check response consistency
} // block end of receive retry loop
} // block end of send and receive retry loop
return ret_code;
}
/* Marshaling functions */
uint8_t atsha204Class::sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode)
{
if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE))
return SHA204_BAD_PARAM;
tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT;
tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM;
tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE;
tx_buffer[RANDOM_PARAM2_IDX] =
tx_buffer[RANDOM_PARAM2_IDX + 1] = 0;
return sha204c_send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, RANDOM_EXEC_MAX - RANDOM_DELAY);
}
uint8_t atsha204Class::sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer)
{
if (!tx_buffer || !rx_buffer)
return SHA204_BAD_PARAM;
tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT;
tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV;
// Parameters are 0.
tx_buffer[DEVREV_PARAM1_IDX] =
tx_buffer[DEVREV_PARAM2_IDX] =
tx_buffer[DEVREV_PARAM2_IDX + 1] = 0;
return sha204c_send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0],
DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY);
}
uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address)
{
uint8_t rx_size;
if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0)
|| ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP)))
return SHA204_BAD_PARAM;
address >>= 2;
if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG)
{
if (address > SHA204_ADDRESS_MASK_CONFIG)
return SHA204_BAD_PARAM;
}
else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP)
{
if (address > SHA204_ADDRESS_MASK_OTP)
return SHA204_BAD_PARAM;
}
else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA)
{
if (address > SHA204_ADDRESS_MASK)
return SHA204_BAD_PARAM;
}
tx_buffer[SHA204_COUNT_IDX] = READ_COUNT;
tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ;
tx_buffer[READ_ZONE_IDX] = zone;
tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK);
tx_buffer[READ_ADDR_IDX + 1] = 0;
rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE;
return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY);
}
uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer)
{
uint8_t poll_delay, poll_timeout, response_size;
uint8_t *p_buffer;
uint8_t len;
uint8_t ret_code = sha204m_check_parameters(op_code, param1, param2,
datalen1, data1, datalen2, data2, datalen3, data3,
tx_size, tx_buffer, rx_size, rx_buffer);
if (ret_code != SHA204_SUCCESS)
return ret_code;
// Supply delays and response size.
switch (op_code)
{
case SHA204_CHECKMAC:
poll_delay = CHECKMAC_DELAY;
poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY;
response_size = CHECKMAC_RSP_SIZE;
break;
case SHA204_DERIVE_KEY:
poll_delay = DERIVE_KEY_DELAY;
poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY;
response_size = DERIVE_KEY_RSP_SIZE;
break;
case SHA204_DEVREV:
poll_delay = DEVREV_DELAY;
poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY;
response_size = DEVREV_RSP_SIZE;
break;
case SHA204_GENDIG:
poll_delay = GENDIG_DELAY;
poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY;
response_size = GENDIG_RSP_SIZE;
break;
case SHA204_HMAC:
poll_delay = HMAC_DELAY;
poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY;
response_size = HMAC_RSP_SIZE;
break;
case SHA204_LOCK:
poll_delay = LOCK_DELAY;
poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY;
response_size = LOCK_RSP_SIZE;
break;
case SHA204_MAC:
poll_delay = MAC_DELAY;
poll_timeout = MAC_EXEC_MAX - MAC_DELAY;
response_size = MAC_RSP_SIZE;
break;
case SHA204_NONCE:
poll_delay = NONCE_DELAY;
poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY;
response_size = param1 == NONCE_MODE_PASSTHROUGH
? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG;
break;
case SHA204_PAUSE:
poll_delay = PAUSE_DELAY;
poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY;
response_size = PAUSE_RSP_SIZE;
break;
case SHA204_RANDOM:
poll_delay = RANDOM_DELAY;
poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY;
response_size = RANDOM_RSP_SIZE;
break;
case SHA204_READ:
poll_delay = READ_DELAY;
poll_timeout = READ_EXEC_MAX - READ_DELAY;
response_size = (param1 & SHA204_ZONE_COUNT_FLAG)
? READ_32_RSP_SIZE : READ_4_RSP_SIZE;
break;
case SHA204_UPDATE_EXTRA:
poll_delay = UPDATE_DELAY;
poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY;
response_size = UPDATE_RSP_SIZE;
break;
case SHA204_WRITE:
poll_delay = WRITE_DELAY;
poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY;
response_size = WRITE_RSP_SIZE;
break;
default:
poll_delay = 0;
poll_timeout = SHA204_COMMAND_EXEC_MAX;
response_size = rx_size;
}
// Assemble command.
len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN;
p_buffer = tx_buffer;
*p_buffer++ = len;
*p_buffer++ = op_code;
*p_buffer++ = param1;
*p_buffer++ = param2 & 0xFF;
*p_buffer++ = param2 >> 8;
if (datalen1 > 0) {
memcpy(p_buffer, data1, datalen1);
p_buffer += datalen1;
}
if (datalen2 > 0) {
memcpy(p_buffer, data2, datalen2);
p_buffer += datalen2;
}
if (datalen3 > 0) {
memcpy(p_buffer, data3, datalen3);
p_buffer += datalen3;
}
sha204c_calculate_crc(len - SHA204_CRC_SIZE, tx_buffer, p_buffer);
// Send command and receive response.
return sha204c_send_and_receive(&tx_buffer[0], response_size,
&rx_buffer[0], poll_delay, poll_timeout);
}
uint8_t atsha204Class::sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2,
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer)
{
#ifdef SHA204_CHECK_PARAMETERS
uint8_t len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN;
if (!tx_buffer || tx_size < len || rx_size < SHA204_RSP_SIZE_MIN || !rx_buffer)
return SHA204_BAD_PARAM;
if ((datalen1 > 0 && !data1) || (datalen2 > 0 && !data2) || (datalen3 > 0 && !data3))
return SHA204_BAD_PARAM;
// Check parameters depending on op-code.
switch (op_code)
{
case SHA204_CHECKMAC:
if (
// no null pointers allowed
!data1 || !data2
// No reserved bits should be set.
|| (param1 | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK
// key_id > 15 not allowed
|| param2 > SHA204_KEY_ID_MAX
)
return SHA204_BAD_PARAM;
break;
case SHA204_DERIVE_KEY:
if (param2 > SHA204_KEY_ID_MAX)
return SHA204_BAD_PARAM;
break;
case SHA204_DEVREV:
break;
case SHA204_GENDIG:
if ((param1 != GENDIG_ZONE_OTP) && (param1 != GENDIG_ZONE_DATA))
return SHA204_BAD_PARAM;
break;
case SHA204_HMAC:
if ((param1 & ~HMAC_MODE_MASK) != 0)
return SHA204_BAD_PARAM;
break;
case SHA204_LOCK:
if (((param1 & ~LOCK_ZONE_MASK) != 0)
|| ((param1 & LOCK_ZONE_NO_CRC) && (param2 != 0)))
return SHA204_BAD_PARAM;
break;
case SHA204_MAC:
if (((param1 & ~MAC_MODE_MASK) != 0)
|| (((param1 & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !data1))
return SHA204_BAD_PARAM;
break;
case SHA204_NONCE:
if ( !data1
|| (param1 > NONCE_MODE_PASSTHROUGH)
|| (param1 == NONCE_MODE_INVALID)
)
return SHA204_BAD_PARAM;
break;
case SHA204_PAUSE:
break;
case SHA204_RANDOM:
if (param1 > RANDOM_NO_SEED_UPDATE)
return SHA204_BAD_PARAM;
break;
case SHA204_READ:
if (((param1 & ~READ_ZONE_MASK) != 0)
|| ((param1 & READ_ZONE_MODE_32_BYTES) && (param1 == SHA204_ZONE_OTP)))
return SHA204_BAD_PARAM;
break;
case SHA204_TEMPSENSE:
break;
case SHA204_UPDATE_EXTRA:
if (param1 > UPDATE_CONFIG_BYTE_86)
return SHA204_BAD_PARAM;
break;
case SHA204_WRITE:
if (!data1 || ((param1 & ~WRITE_ZONE_MASK) != 0))
return SHA204_BAD_PARAM;
break;
default:
// unknown op-code
return SHA204_BAD_PARAM;
}
return SHA204_SUCCESS;
#else
return SHA204_SUCCESS;
#endif
}
/* CRC Calculator and Checker */
void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc)
{
uint16_t crc_register = 0;
crc_register = calculateAndUpdateCrc(length, data, crc_register);
crc[0] = (uint8_t) (crc_register & 0x00FF);
crc[1] = (uint8_t) (crc_register >> 8);
}
uint8_t atsha204Class::sha204c_check_crc(uint8_t *response)
{
uint8_t crc[SHA204_CRC_SIZE];
uint8_t count = response[SHA204_BUFFER_POS_COUNT];
count -= SHA204_CRC_SIZE;
sha204c_calculate_crc(count, response, crc);
return (crc[0] == response[count] && crc[1] == response[count + 1])
? SHA204_SUCCESS : SHA204_BAD_CRC;
}
+321
View File
@@ -0,0 +1,321 @@
#include "Arduino.h"
#ifndef sha204_library_H
#define sha204_library_H
/* bitbang_config.h */
#define PORT_ACCESS_TIME (630) //! time it takes to toggle the pin at CPU clock of 16 MHz (ns)
#define START_PULSE_WIDTH (4340) //! width of start pulse (ns)
#define BIT_DELAY (4) //! delay macro for width of one pulse (start pulse or zero pulse, in ns)
#define RX_TX_DELAY (15) //! turn around time when switching from receive to transmit
#define START_PULSE_TIME_OUT (255) //! This value is decremented while waiting for the falling edge of a start pulse.
#define ZERO_PULSE_TIME_OUT (26) //! This value is decremented while waiting for the falling edge of a zero pulse.
/* swi_phys.h */
#define SWI_FUNCTION_RETCODE_SUCCESS ((uint8_t) 0x00) //!< Communication with device succeeded.
#define SWI_FUNCTION_RETCODE_TIMEOUT ((uint8_t) 0xF1) //!< Communication timed out.
#define SWI_FUNCTION_RETCODE_RX_FAIL ((uint8_t) 0xF9) //!< Communication failed after at least one byte was received.
/* sha204_physical.h */
#define SHA204_RSP_SIZE_MIN ((uint8_t) 4) //!< minimum number of bytes in response
#define SHA204_RSP_SIZE_MAX ((uint8_t) 35) //!< maximum size of response packet
#define SHA204_BUFFER_POS_COUNT (0) //!< buffer index of count byte in command or response
#define SHA204_BUFFER_POS_DATA (1) //!< buffer index of data in response
#define SHA204_WAKEUP_PULSE_WIDTH (uint8_t) (6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! width of Wakeup pulse in 10 us units
#define SHA204_WAKEUP_DELAY (uint8_t) (3.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! delay between Wakeup pulse and communication in ms
/* sha204_swi.c */
#define SHA204_SWI_FLAG_CMD ((uint8_t) 0x77) //!< flag preceding a command
#define SHA204_SWI_FLAG_TX ((uint8_t) 0x88) //!< flag requesting a response
#define SHA204_SWI_FLAG_IDLE ((uint8_t) 0xBB) //!< flag requesting to go into Idle mode
#define SHA204_SWI_FLAG_SLEEP ((uint8_t) 0xCC) //!< flag requesting to go into Sleep mode
/* sha204_comm_marshaling.h */
// command op-code definitions
#define SHA204_CHECKMAC ((uint8_t) 0x28) //!< CheckMac command op-code
#define SHA204_DERIVE_KEY ((uint8_t) 0x1C) //!< DeriveKey command op-code
#define SHA204_DEVREV ((uint8_t) 0x30) //!< DevRev command op-code
#define SHA204_GENDIG ((uint8_t) 0x15) //!< GenDig command op-code
#define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code
#define SHA204_LOCK ((uint8_t) 0x17) //!< Lock command op-code
#define SHA204_MAC ((uint8_t) 0x08) //!< MAC command op-code
#define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code
#define SHA204_PAUSE ((uint8_t) 0x01) //!< Pause command op-code
#define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code
#define SHA204_READ ((uint8_t) 0x02) //!< Read command op-code
#define SHA204_UPDATE_EXTRA ((uint8_t) 0x20) //!< UpdateExtra command op-code
#define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code
// packet size definitions
#define SHA204_RSP_SIZE_VAL ((uint8_t) 7) //!< size of response packet containing four bytes of data
// parameter range definitions
#define SHA204_KEY_ID_MAX ((uint8_t) 15) //!< maximum value for key id
#define SHA204_OTP_BLOCK_MAX ((uint8_t) 1) //!< maximum value for OTP block
// definitions for command packet indexes common to all commands
#define SHA204_COUNT_IDX ( 0) //!< command packet index for count
#define SHA204_OPCODE_IDX ( 1) //!< command packet index for op-code
#define SHA204_PARAM1_IDX ( 2) //!< command packet index for first parameter
#define SHA204_PARAM2_IDX ( 3) //!< command packet index for second parameter
#define SHA204_DATA_IDX ( 5) //!< command packet index for second parameter
// zone definitions
#define SHA204_ZONE_CONFIG ((uint8_t) 0x00) //!< Configuration zone
#define SHA204_ZONE_OTP ((uint8_t) 0x01) //!< OTP (One Time Programming) zone
#define SHA204_ZONE_DATA ((uint8_t) 0x02) //!< Data zone
#define SHA204_ZONE_MASK ((uint8_t) 0x03) //!< Zone mask
#define SHA204_ZONE_COUNT_FLAG ((uint8_t) 0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes.
#define SHA204_ZONE_ACCESS_4 ((uint8_t) 4) //!< Read or write 4 bytes.
#define SHA204_ZONE_ACCESS_32 ((uint8_t) 32) //!< Read or write 32 bytes.
#define SHA204_ADDRESS_MASK_CONFIG ( 0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone.
#define SHA204_ADDRESS_MASK_OTP ( 0x000F) //!< Address bits 4 to 7 are 0 for OTP zone.
#define SHA204_ADDRESS_MASK ( 0x007F) //!< Address bit 7 to 15 are always 0.
// CheckMAC command definitions
#define CHECKMAC_MODE_IDX SHA204_PARAM1_IDX //!< CheckMAC command index for mode
#define CHECKMAC_KEYID_IDX SHA204_PARAM2_IDX //!< CheckMAC command index for key identifier
#define CHECKMAC_CLIENT_CHALLENGE_IDX SHA204_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_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"
// DeriveKey command definitions
#define DERIVE_KEY_RANDOM_IDX SHA204_PARAM1_IDX //!< DeriveKey command index for random bit
#define DERIVE_KEY_TARGETKEY_IDX SHA204_PARAM2_IDX //!< DeriveKey command index for target slot
#define DERIVE_KEY_MAC_IDX SHA204_DATA_IDX //!< DeriveKey command index for optional MAC
#define DERIVE_KEY_COUNT_SMALL SHA204_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
#define DERIVE_KEY_MAC_SIZE (32) //!< DeriveKey MAC size
// DevRev command definitions
#define DEVREV_PARAM1_IDX SHA204_PARAM1_IDX //!< DevRev command index for 1. parameter (ignored)
#define DEVREV_PARAM2_IDX SHA204_PARAM2_IDX //!< DevRev command index for 2. parameter (ignored)
#define DEVREV_COUNT SHA204_CMD_SIZE_MIN //!< DevRev command packet size
// GenDig command definitions
#define GENDIG_ZONE_IDX SHA204_PARAM1_IDX //!< GenDig command index for zone
#define GENDIG_KEYID_IDX SHA204_PARAM2_IDX //!< GenDig command index for key id
#define GENDIG_DATA_IDX SHA204_DATA_IDX //!< GenDig command index for optional data
#define GENDIG_COUNT SHA204_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 (4) //!< GenDig size of "other data"
#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
// HMAC command definitions
#define HMAC_MODE_IDX SHA204_PARAM1_IDX //!< HMAC command index for mode
#define HMAC_KEYID_IDX SHA204_PARAM2_IDX //!< HMAC command index for key id
#define HMAC_COUNT SHA204_CMD_SIZE_MIN //!< HMAC command packet size
#define HMAC_MODE_MASK ((uint8_t) 0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0.
// Lock command definitions
#define LOCK_ZONE_IDX SHA204_PARAM1_IDX //!< Lock command index for zone
#define LOCK_SUMMARY_IDX SHA204_PARAM2_IDX //!< Lock command index for summary
#define LOCK_COUNT SHA204_CMD_SIZE_MIN //!< Lock command packet size
#define LOCK_ZONE_NO_CONFIG ((uint8_t) 0x01) //!< Lock zone is OTP or Data
#define LOCK_ZONE_NO_CRC ((uint8_t) 0x80) //!< Lock command: Ignore summary.
#define LOCK_ZONE_MASK (0x81) //!< Lock parameter 1 bits 2 to 6 are 0.
// Mac command definitions
#define MAC_MODE_IDX SHA204_PARAM1_IDX //!< MAC command index for mode
#define MAC_KEYID_IDX SHA204_PARAM2_IDX //!< MAC command index for key id
#define MAC_CHALLENGE_IDX SHA204_DATA_IDX //!< MAC command index for optional challenge
#define MAC_COUNT_SHORT SHA204_CMD_SIZE_MIN //!< MAC command packet size without challenge
#define MAC_COUNT_LONG (39) //!< MAC command packet size with challenge
#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_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_MODE_MASK ((uint8_t) 0x77) //!< MAC mode bits 3 and 7 are 0.
// Nonce command definitions
#define NONCE_MODE_IDX SHA204_PARAM1_IDX //!< Nonce command index for mode
#define NONCE_PARAM2_IDX SHA204_PARAM2_IDX //!< Nonce command index for 2. parameter
#define NONCE_INPUT_IDX SHA204_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) 3) //!< 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_NUMIN_SIZE (20) //!< Nonce data length
#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce data length in pass-through mode (mode = 3)
// Pause command definitions
#define PAUSE_SELECT_IDX SHA204_PARAM1_IDX //!< Pause command index for Selector
#define PAUSE_PARAM2_IDX SHA204_PARAM2_IDX //!< Pause command index for 2. parameter
#define PAUSE_COUNT SHA204_CMD_SIZE_MIN //!< Pause command packet size
// Random command definitions
#define RANDOM_MODE_IDX SHA204_PARAM1_IDX //!< Random command index for mode
#define RANDOM_PARAM2_IDX SHA204_PARAM2_IDX //!< Random command index for 2. parameter
#define RANDOM_COUNT SHA204_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
// Read command definitions
#define READ_ZONE_IDX SHA204_PARAM1_IDX //!< Read command index for zone
#define READ_ADDR_IDX SHA204_PARAM2_IDX //!< Read command index for address
#define READ_COUNT SHA204_CMD_SIZE_MIN //!< Read command packet size
#define READ_ZONE_MASK ((uint8_t) 0x83) //!< Read zone bits 2 to 6 are 0.
#define READ_ZONE_MODE_32_BYTES ((uint8_t) 0x80) //!< Read mode: 32 bytes
// UpdateExtra command definitions
#define UPDATE_MODE_IDX SHA204_PARAM1_IDX //!< UpdateExtra command index for mode
#define UPDATE_VALUE_IDX SHA204_PARAM2_IDX //!< UpdateExtra command index for new value
#define UPDATE_COUNT SHA204_CMD_SIZE_MIN //!< UpdateExtra command packet size
#define UPDATE_CONFIG_BYTE_86 ((uint8_t) 0x01) //!< UpdateExtra mode: update Config byte 86
// Write command definitions
#define WRITE_ZONE_IDX SHA204_PARAM1_IDX //!< Write command index for zone
#define WRITE_ADDR_IDX SHA204_PARAM2_IDX //!< Write command index for address
#define WRITE_VALUE_IDX SHA204_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
// Response size definitions
#define CHECKMAC_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command
#define DERIVE_KEY_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command
#define DEVREV_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of DevRev command returns 4 bytes
#define GENDIG_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of GenDig command
#define HMAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of HMAC command
#define LOCK_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Lock command
#define MAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of MAC command
#define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3
#define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command
#define PAUSE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Pause command
#define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command
#define READ_4_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of Read command when reading 4 bytes
#define READ_32_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Read command when reading 32 bytes
#define TEMP_SENSE_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of TempSense command returns 4 bytes
#define UPDATE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of UpdateExtra command
#define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command
// command timing definitions for minimum execution times (ms)
#define CHECKMAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define DERIVE_KEY_DELAY ((uint8_t) (14.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define DEVREV_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define GENDIG_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define LOCK_DELAY ((uint8_t) ( 5.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define MAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define PAUSE_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define READ_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define TEMP_SENSE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define UPDATE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
#define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5))
// command timing definitions for maximum execution times (ms)
#define CHECKMAC_EXEC_MAX ((uint8_t) (38.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define DERIVE_KEY_EXEC_MAX ((uint8_t) (62.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define DEVREV_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define GENDIG_EXEC_MAX ((uint8_t) (43.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define LOCK_EXEC_MAX ((uint8_t) (24.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define MAC_EXEC_MAX ((uint8_t) (35.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define PAUSE_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define READ_EXEC_MAX ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define TEMP_SENSE_EXEC_MAX ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define UPDATE_EXEC_MAX ((uint8_t) ( 6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
#define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5))
/* from sha204_config.h */
#define CPU_CLOCK_DEVIATION_POSITIVE (1.01)
#define CPU_CLOCK_DEVIATION_NEGATIVE (0.99)
#define SHA204_RETRY_COUNT (1)
#define SWI_RECEIVE_TIME_OUT ((uint16_t) 163) //! #START_PULSE_TIME_OUT in us instead of loop counts
#define SWI_US_PER_BYTE ((uint16_t) 313) //! It takes 312.5 us to send a byte (9 single-wire bits / 230400 Baud * 8 flag bits).
#define SHA204_SYNC_TIMEOUT ((uint8_t) 85)//! delay before sending a transmit flag in the synchronization routine
#define SHA204_RESPONSE_TIMEOUT ((uint16_t) SWI_RECEIVE_TIME_OUT + SWI_US_PER_BYTE) //! SWI response timeout is the sum of receive timeout and the time it takes to send the TX flag.
/* from sha204_comm.h */
#define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay
#define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte)
#define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac)
#define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes
#define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response
#define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response
#define SHA204_STATUS_BYTE_WAKEUP ((uint8_t) 0x11) //! command parse error
#define SHA204_STATUS_BYTE_PARSE ((uint8_t) 0x03) //! command parse error
#define SHA204_STATUS_BYTE_EXEC ((uint8_t) 0x0F) //! command execution error
#define SHA204_STATUS_BYTE_COMM ((uint8_t) 0xFF) //! communication error
/* EEPROM Addresses */
/* Configuration Zone */
#define ADDRESS_SN03 0 // SN[0:3] are bytes 0->3 of configuration zone
#define ADDRESS_RevNum 4 // bytes 4->7 of config zone are RevNum
#define ADDRESS_SN47 8 // SN[4:7] are bytes 8->11 of config zone
#define ADDRESS_SN8 12 // SN[8] is byte 12 of config zone, should be 0xEE
#define ADDRESS_I2CEN 14 // I2C Enable, bit 0 represents I2C enable status
#define ADDRESS_I2CADD 16 // Defines I2C address of SHA204
#define ADDRESS_OTPMODE 18 // Sets the One-time-programmable mode
#define ADDRESS_SELECTOR 19 // Controls writability of Selector
class atsha204Class
{
private:
uint8_t device_pin;
volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN;
void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc);
uint8_t sha204c_check_crc(uint8_t *response);
void swi_set_signal_pin(uint8_t is_high);
uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer);
uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer);
uint8_t swi_send_byte(uint8_t value);
uint8_t sha204p_receive_response(uint8_t size, uint8_t *response);
uint8_t sha204p_wakeup();
uint8_t sha204p_send_command(uint8_t count, uint8_t * command);
uint8_t sha204p_sleep();
uint8_t sha204p_resync(uint8_t size, uint8_t *response);
public:
atsha204Class(uint8_t pin); // Constructor
uint8_t sha204c_wakeup(uint8_t *response);
uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout);
uint8_t sha204c_resync(uint8_t size, uint8_t *response);
uint8_t sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode);
uint8_t sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer);
uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address);
uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2,
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
uint8_t sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2,
uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3,
uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer);
uint8_t getSerialNumber(uint8_t *response);
uint16_t calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc);
};
#endif