1
0
mirror of https://github.com/taigrr/arduinolibs synced 2025-01-18 04:33:12 -08:00

Use CRC-8 to validate the random seed in EEPROM/Flash

This commit is contained in:
Rhys Weatherley
2017-11-26 10:06:29 +10:00
parent 8400d51420
commit 06987988be
4 changed files with 55 additions and 11 deletions

View File

@@ -77,3 +77,38 @@ bool secure_compare(const void *data1, const void *data2, size_t len)
}
return (bool)((((uint16_t)0x0100) - result) >> 8);
}
/**
* \brief Calculates the CRC-8 value over an array in memory.
*
* \param tag Starting tag to distinguish this calculation.
* \param data The data to checksum.
* \param size The number of bytes to checksum.
* \return The CRC-8 value over the data.
*
* This function does not provide any real security. It is a simple
* check that seed values have been initialized within EEPROM or Flash.
* If the CRC-8 check fails, then it is assumed that the EEPROM/Flash
* contents are invalid and should be re-initialized.
*
* Reference: http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch4
*/
uint8_t crypto_crc8(uint8_t tag, const void *data, unsigned size)
{
const uint8_t *d = (const uint8_t *)data;
uint8_t crc = 0xFF ^ tag;
uint8_t bit;
while (size > 0) {
crc ^= *d++;
for (bit = 0; bit < 8; ++bit) {
// if (crc & 0x80)
// crc = (crc << 1) ^ 0x1D;
// else
// crc = (crc << 1);
uint8_t generator = (uint8_t)((((int8_t)crc) >> 7) & 0x1D);
crc = (crc << 1) ^ generator;
}
--size;
}
return crc;
}

View File

@@ -154,6 +154,9 @@ RNGClass RNG;
/** @cond */
// Imported from Crypto.cpp.
extern uint8_t crypto_crc8(uint8_t tag, const void *data, unsigned size);
// Tag for 256-bit ChaCha20 keys. This will always appear in the
// first 16 bytes of the block. The remaining 48 bytes are the seed.
static const char tagRNG[16] PROGMEM = {
@@ -361,17 +364,19 @@ void RNGClass::begin(const char *tag)
memcpy_P(block + 4, initRNG, sizeof(initRNG));
#if defined(RNG_EEPROM)
int address = RNG_EEPROM_ADDRESS;
if (eeprom_read_byte((const uint8_t *)address) == 'S') {
eeprom_read_block(stream, (const void *)address, SEED_SIZE);
if (crypto_crc8('S', stream, SEED_SIZE - 1) ==
((const uint8_t *)stream)[SEED_SIZE - 1]) {
// We have a saved seed: XOR it with the initialization block.
for (int posn = 0; posn < 12; ++posn) {
block[posn + 4] ^=
eeprom_read_dword((const uint32_t *)(address + posn * 4 + 1));
}
// Note: the CRC-8 value is included. No point throwing it away.
for (int posn = 0; posn < 12; ++posn)
block[posn + 4] ^= stream[posn];
}
#elif defined(RNG_DUE_TRNG)
// Do we have a seed saved in the last page of flash memory on the Due?
int posn, counter;
if (((const uint32_t *)RNG_SEED_ADDR)[0] == 'S') {
if (crypto_crc8('S', ((const uint32_t *)RNG_SEED_ADDR) + 1, SEED_SIZE)
== ((const uint32_t *)RNG_SEED_ADDR)[0]) {
// XOR the saved seed with the initialization block.
for (posn = 0; posn < 12; ++posn)
block[posn + 4] ^= ((const uint32_t *)RNG_SEED_ADDR)[posn + 1];
@@ -694,12 +699,16 @@ void RNGClass::save()
++(block[12]);
ChaCha::hashCore(stream, block, RNG_ROUNDS);
#if defined(RNG_EEPROM)
// We shorten the seed from 48 bytes to 47 to leave room for
// the CRC-8 value. We do this to align the data on an 8-byte
// boundary in EERPOM.
int address = RNG_EEPROM_ADDRESS;
eeprom_write_block(stream, (void *)(address + 1), 48);
eeprom_update_byte((uint8_t *)address, 'S');
eeprom_write_block(stream, (void *)address, SEED_SIZE - 1);
eeprom_write_byte((uint8_t *)(address + SEED_SIZE - 1),
crypto_crc8('S', stream, SEED_SIZE - 1));
#elif defined(RNG_DUE_TRNG)
unsigned posn;
((uint32_t *)(RNG_SEED_ADDR))[0] = 'S';
((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8('S', stream, SEED_SIZE);
for (posn = 0; posn < 12; ++posn)
((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)

View File

@@ -50,7 +50,7 @@ public:
void destroy();
static const int SEED_SIZE = 49;
static const int SEED_SIZE = 48;
private:
uint32_t block[16];