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

@ -160,7 +160,7 @@ void setup() {
}
\endcode
The random number generator uses 49 bytes of space at the end of
The random number generator uses 48 bytes of space at the end of
EEPROM memory to store the previous seed. When the system is started
next time, the previous saved seed is loaded and then deliberately
overwritten with a new seed. This ensures that the device will not

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];