24 #include "NoiseSource.h"
27 #include "utility/ProgMemUtil.h"
29 #if defined (__arm__) && defined (__SAM3X8E__)
32 #define RNG_DUE_TRNG 1
33 #elif defined(__AVR__)
34 #define RNG_EEPROM 1 // Use EEPROM to save the seed.
35 #define RNG_WATCHDOG 1 // Harvest entropy from watchdog jitter.
36 #include <avr/eeprom.h>
39 #define RNG_EEPROM_ADDRESS (E2END + 1 - RNGClass::SEED_SIZE)
147 #define RNG_ROUNDS 20
150 #define RNG_REKEY_BLOCKS 16
153 #define RNG_MAX_CREDITS 384
158 extern uint8_t crypto_crc8(uint8_t tag,
const void *data,
unsigned size);
162 static const char tagRNG[16] PROGMEM = {
163 'e',
'x',
'p',
'a',
'n',
'd',
' ',
'3',
164 '2',
'-',
'b',
'y',
't',
'e',
' ',
'k'
173 static const uint8_t initRNG[48] PROGMEM = {
174 0xB0, 0x2A, 0xAE, 0x7D, 0xEE, 0xCB, 0xBB, 0xB1,
175 0xFC, 0x03, 0x6F, 0xDD, 0xDC, 0x7D, 0x76, 0x67,
176 0x0C, 0xE8, 0x1F, 0x0D, 0xA3, 0xA0, 0xAA, 0x1E,
177 0xB0, 0xBD, 0x72, 0x6B, 0x2B, 0x4C, 0x8A, 0x7E,
178 0x34, 0xFC, 0x37, 0x60, 0xF4, 0x1E, 0x22, 0xA0,
179 0x0B, 0xFB, 0x18, 0x84, 0x60, 0xA5, 0x77, 0x72
182 #if defined(RNG_WATCHDOG)
194 #define leftShift3(value) ((value) << 3)
195 #define leftShift10(value) ((value) << 10)
196 #define leftShift15(value) ((value) << 15)
197 #define rightShift6(value) ((value) >> 6)
198 #define rightShift11(value) ((value) >> 11)
200 static uint32_t
volatile hash = 0;
201 static uint8_t
volatile outBits = 0;
212 unsigned char value = TCNT1L;
213 #elif defined(TCNT0L)
214 unsigned char value = TCNT0L;
216 unsigned char value = TCNT0;
221 hash += leftShift10(hash);
222 hash ^= rightShift6(hash);
226 #endif // RNG_WATCHDOG
253 #if defined(RNG_DUE_TRNG)
255 REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
257 #if defined(RNG_WATCHDOG)
263 MCUSR &= ~(1 << WDRF);
266 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
276 #if defined(RNG_DUE_TRNG)
280 #if defined(IFLASH1_ADDR)
281 #define RNG_FLASH_ADDR IFLASH1_ADDR
282 #define RNG_FLASH_SIZE IFLASH1_SIZE
283 #define RNG_FLASH_PAGE_SIZE IFLASH1_PAGE_SIZE
285 #elif defined(IFLASH0_ADDR)
286 #define RNG_FLASH_ADDR IFLASH0_ADDR
287 #define RNG_FLASH_SIZE IFLASH0_SIZE
288 #define RNG_FLASH_PAGE_SIZE IFLASH0_PAGE_SIZE
291 #define RNG_FLASH_ADDR IFLASH_ADDR
292 #define RNG_FLASH_SIZE IFLASH_SIZE
293 #define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
300 #define RNG_SEED_ADDR (RNG_FLASH_ADDR + RNG_FLASH_SIZE - RNG_FLASH_PAGE_SIZE)
301 #define RNG_SEED_PAGE ((RNG_FLASH_SIZE / RNG_FLASH_PAGE_SIZE) - 1)
307 __attribute__((section(
".ramfunc")))
308 static
void stirUniqueIdentifier(
void)
313 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
314 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
318 id[0] = *((
const uint32_t *)RNG_FLASH_ADDR);
319 id[1] = *((
const uint32_t *)(RNG_FLASH_ADDR + 4));
320 id[2] = *((
const uint32_t *)(RNG_FLASH_ADDR + 8));
321 id[3] = *((
const uint32_t *)(RNG_FLASH_ADDR + 12));
324 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
325 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
329 RNG.
stir((uint8_t *)
id,
sizeof(
id));
334 __attribute__((section(
".ramfunc")))
335 static
void eraseAndWriteSeed()
338 RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
341 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
363 memcpy_P(block, tagRNG,
sizeof(tagRNG));
364 memcpy_P(block + 4, initRNG,
sizeof(initRNG));
365 #if defined(RNG_EEPROM)
366 int address = RNG_EEPROM_ADDRESS;
367 eeprom_read_block(stream, (
const void *)address,
SEED_SIZE);
368 if (crypto_crc8(
'S', stream,
SEED_SIZE - 1) ==
369 ((
const uint8_t *)stream)[
SEED_SIZE - 1]) {
372 for (
int posn = 0; posn < 12; ++posn)
373 block[posn + 4] ^= stream[posn];
375 #elif defined(RNG_DUE_TRNG)
378 if (crypto_crc8(
'S', ((
const uint32_t *)RNG_SEED_ADDR) + 1,
SEED_SIZE)
379 == ((
const uint32_t *)RNG_SEED_ADDR)[0]) {
381 for (posn = 0; posn < 12; ++posn)
382 block[posn + 4] ^= ((
const uint32_t *)RNG_SEED_ADDR)[posn + 1];
388 pmc_enable_periph_clk(ID_TRNG);
389 REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
390 REG_TRNG_IDR = TRNG_IDR_DATRDY;
391 for (posn = 0; posn < 12; ++posn) {
396 for (counter = 0; counter < 200; ++counter) {
397 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
402 block[posn + 4] ^= REG_TRNG_ODATA;
417 stir((
const uint8_t *)tag, strlen(tag));
419 #if defined(RNG_DUE_TRNG)
422 stirUniqueIdentifier();
428 tag = __TIME__ __DATE__;
429 stir((
const uint8_t *)tag, strlen(tag));
432 #if defined(RNG_WATCHDOG)
438 MCUSR &= ~(1 << WDRF);
442 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
443 _WD_CONTROL_REG = (1 << WDIE);
469 #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
470 if (count < MAX_NOISE_SOURCES) {
471 noiseSources[count++] = &source;
496 timeout = ((uint32_t)minutes) * 60000U;
519 if (len > (credits / 8))
528 if (count >= RNG_REKEY_BLOCKS) {
541 memcpy(data, stream, len);
544 memcpy(data, stream, 64);
595 if (len >= (RNG_MAX_CREDITS / 8))
596 return credits >= RNG_MAX_CREDITS;
598 return len <= (credits / 8);
629 if ((credit / 8) >= len && len)
631 if ((RNG_MAX_CREDITS - credits) > credit)
634 credits = RNG_MAX_CREDITS;
643 size_t templen = len;
646 uint8_t *output = ((uint8_t *)block) + 16;
648 while (templen > 0) {
649 *output++ ^= *data++;
663 if (firstSave && credits >= RNG_MAX_CREDITS) {
701 #if defined(RNG_EEPROM)
705 int address = RNG_EEPROM_ADDRESS;
706 eeprom_write_block(stream, (
void *)address,
SEED_SIZE - 1);
707 eeprom_write_byte((uint8_t *)(address +
SEED_SIZE - 1),
708 crypto_crc8(
'S', stream,
SEED_SIZE - 1));
709 #elif defined(RNG_DUE_TRNG)
711 ((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8(
'S', stream,
SEED_SIZE);
712 for (posn = 0; posn < 12; ++posn)
713 ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
714 for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
715 ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
731 for (uint8_t posn = 0; posn < count; ++posn)
732 noiseSources[posn]->
stir();
734 #if defined(RNG_DUE_TRNG)
754 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
755 block[4 + trngPosn] ^= REG_TRNG_ODATA;
756 if (++trngPosn >= 12)
758 if (credits < RNG_MAX_CREDITS) {
765 #elif defined(RNG_WATCHDOG)
769 uint32_t value = hash;
776 value += leftShift3(value);
777 value ^= rightShift11(value);
778 value += leftShift15(value);
782 block[4 + trngPosn] ^= value;
783 if (++trngPosn >= 12) {
796 if ((millis() - timer) >= timeout)
823 #if defined(RNG_EEPROM)
824 int address = RNG_EEPROM_ADDRESS;
825 for (
int posn = 0; posn <
SEED_SIZE; ++posn)
826 eeprom_write_byte((uint8_t *)(address + posn), 0xFF);
827 #elif defined(RNG_DUE_TRNG)
828 for (
unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
829 ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF;
837 void RNGClass::rekey()
845 memcpy(block + 4, stream, 48);
852 block[13] ^= micros();
void save()
Saves the random seed to EEPROM.
void rand(uint8_t *data, size_t len)
Generates random bytes into a caller-supplied buffer.
void begin(const char *tag)
Initializes the random number generator.
Abstract base class for random noise sources.
~RNGClass()
Destroys this random number generator instance.
virtual void added()
Called when the noise source is added to RNG with RNG.addNoiseSource().
void addNoiseSource(NoiseSource &source)
Adds a noise source to the random number generator.
RNGClass()
Constructs a new random number generator instance.
void destroy()
Destroys the data in the random number pool and the saved seed in EEPROM.
bool available(size_t len) const
Determine if there is sufficient entropy available for a specific request size.
void loop()
Run periodic housekeeping tasks on the random number generator.
Pseudo random number generator suitable for cryptography.
static const int SEED_SIZE
Size of a saved random number seed in EEPROM space.
static void hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds)
Executes the ChaCha hash core on an input memory block.
void stir(const uint8_t *data, size_t len, unsigned int credit=0)
Stirs additional entropy data into the random pool.
void setAutoSaveTime(uint16_t minutes)
Sets the amount of time between automatic seed saves.