New default pin is A3. New option to skip UART confirmation: SKIP_UART_CONFIRMATION This option prohibits the possibility to auto-generate key as there will probably not be a way to show the generated key to the user. More copy+paste friendly serial output of the generated key for insertion into personalization sketch.
973 lines
28 KiB
Arduino
973 lines
28 KiB
Arduino
/* 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. On boards that does not provide UART
|
|
input it is possible to configure the sketch to skip this confirmation.
|
|
Default settings use ATSHA204 on pin 17 (A3).
|
|
*/
|
|
#include <sha204_library.h>
|
|
#include <sha204_lib_return_codes.h>
|
|
|
|
// The pin the ATSHA204 is connected on
|
|
#define ATSHA204_PIN 17 // A3
|
|
|
|
// 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
|
|
|
|
// Uncomment this for boards that lack UART
|
|
// IMPORTANT: No confirmation will be required for locking any zones with this
|
|
// configuration!
|
|
// Also, key generation is not permitted in this mode as there is no way of
|
|
// presenting the generated key.
|
|
//#define SKIP_UART_CONFIRMATION
|
|
|
|
#if defined(SKIP_UART_CONFIRMATION) && !defined(USER_KEY_DATA)
|
|
#error You have to define USER_KEY_DATA for boards that does not have UART
|
|
#endif
|
|
|
|
#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
|
|
#ifndef SKIP_UART_CONFIRMATION
|
|
while (Serial.available())
|
|
{
|
|
Serial.read();
|
|
}
|
|
Serial.println(F("Send SPACE character now to lock the configuration..."));
|
|
|
|
while (Serial.available() == 0);
|
|
if (Serial.read() == ' ')
|
|
#endif //not SKIP_UART_CONFIRMATION
|
|
{
|
|
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];
|
|
}
|
|
}
|
|
}
|
|
#ifndef SKIP_UART_CONFIRMATION
|
|
else
|
|
{
|
|
Serial.println(F("Unexpected answer. Skipping lock."));
|
|
}
|
|
#endif //not SKIP_UART_CONFIRMATION
|
|
#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.println(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++)
|
|
{
|
|
Serial.print("0x");
|
|
if (key[i] < 0x10)
|
|
{
|
|
Serial.print('0'); // Because Serial.print does not 0-pad HEX
|
|
}
|
|
Serial.print(key[i], HEX);
|
|
if (i < 31) Serial.print(',');
|
|
if (!((i+1) % 8)) Serial.println();
|
|
}
|
|
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
|
|
#ifndef SKIP_UART_CONFIRMATION
|
|
while (Serial.available())
|
|
{
|
|
Serial.read();
|
|
}
|
|
Serial.println(F("Send SPACE character to lock data..."));
|
|
while (Serial.available() == 0);
|
|
if (Serial.read() == ' ')
|
|
#endif //not SKIP_UART_CONFIRMATION
|
|
{
|
|
// 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];
|
|
}
|
|
}
|
|
}
|
|
#ifndef SKIP_UART_CONFIRMATION
|
|
else
|
|
{
|
|
Serial.println(F("Unexpected answer. Skipping lock."));
|
|
}
|
|
#endif //not SKIP_UART_CONFIRMATION
|
|
#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()
|
|
{
|
|
}
|