24 #include "NoiseSource.h"
28 #include "utility/ProgMemUtil.h"
29 #if defined (__arm__) && defined (__SAM3X8E__)
32 #define RNG_DUE_TRNG 1
33 #elif defined(__AVR__)
34 #include <avr/eeprom.h>
38 #if defined(MEGATINYCORE) || defined(LOGIC_H)
51 #elif defined(TCNT1L) || defined(TCNT0L) || defined(TCNT0)
52 #define RNG_WATCHDOG 1
55 #define RNG_EEPROM_ADDRESS (E2END + 1 - RNGClass::SEED_SIZE)
56 #elif defined(ESP8266)
60 #define RNG_WORD_TRNG 1
61 #define RNG_WORD_TRNG_GET() (ESP8266_DREG(0x20E44))
64 #define RNG_WORD_TRNG 1
65 #define RNG_WORD_TRNG_GET() (esp_random())
76 #if !defined(RNG_DUE_TRNG) && \
77 !defined(RNG_WATCHDOG) && \
78 !defined(RNG_WORD_TRNG) && \
80 #warning "no hardware random number source detected for this platform"
187 #define RNG_ROUNDS 20
190 #define RNG_REKEY_BLOCKS 16
193 #define RNG_MAX_CREDITS 384u
198 extern uint8_t crypto_crc8(uint8_t tag,
const void *data,
unsigned size);
202 static const char tagRNG[16] PROGMEM = {
203 'e',
'x',
'p',
'a',
'n',
'd',
' ',
'3',
204 '2',
'-',
'b',
'y',
't',
'e',
' ',
'k'
213 static const uint8_t initRNG[48] PROGMEM = {
214 0xB0, 0x2A, 0xAE, 0x7D, 0xEE, 0xCB, 0xBB, 0xB1,
215 0xFC, 0x03, 0x6F, 0xDD, 0xDC, 0x7D, 0x76, 0x67,
216 0x0C, 0xE8, 0x1F, 0x0D, 0xA3, 0xA0, 0xAA, 0x1E,
217 0xB0, 0xBD, 0x72, 0x6B, 0x2B, 0x4C, 0x8A, 0x7E,
218 0x34, 0xFC, 0x37, 0x60, 0xF4, 0x1E, 0x22, 0xA0,
219 0x0B, 0xFB, 0x18, 0x84, 0x60, 0xA5, 0x77, 0x72
222 #if defined(RNG_WATCHDOG)
234 #define leftShift3(value) ((value) << 3)
235 #define leftShift10(value) ((value) << 10)
236 #define leftShift15(value) ((value) << 15)
237 #define rightShift6(value) ((value) >> 6)
238 #define rightShift11(value) ((value) >> 11)
240 static uint32_t
volatile hash = 0;
241 static uint8_t
volatile outBits = 0;
252 unsigned char value = TCNT1L;
253 #elif defined(TCNT0L)
254 unsigned char value = TCNT0L;
256 unsigned char value = TCNT0;
261 hash += leftShift10(hash);
262 hash ^= rightShift6(hash);
266 #elif defined(RNG_CCL)
269 #define leftShift3(value) ((value) << 3)
270 #define leftShift10(value) ((value) << 10)
271 #define leftShift15(value) ((value) << 15)
272 #define rightShift6(value) ((value) >> 6)
273 #define rightShift11(value) ((value) >> 11)
275 static uint32_t
volatile hash = 0;
276 static uint8_t
volatile outBits = 0;
281 uint8_t temp = TCB0.INTFLAGS;
291 RTC_INTFLAGS = RTC_OVF_bm;
292 unsigned char value = (TCB0.CNT);
294 hash += leftShift10(hash);
295 hash ^= rightShift6(hash);
328 #if defined(RNG_DUE_TRNG)
330 REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
332 #if defined(RNG_WATCHDOG)
338 MCUSR &= ~(1 << WDRF);
341 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
346 #elif defined(RNG_CCL)
354 #if defined(RNG_DUE_TRNG)
358 #if defined(IFLASH1_ADDR)
359 #define RNG_FLASH_ADDR IFLASH1_ADDR
360 #define RNG_FLASH_SIZE IFLASH1_SIZE
361 #define RNG_FLASH_PAGE_SIZE IFLASH1_PAGE_SIZE
363 #elif defined(IFLASH0_ADDR)
364 #define RNG_FLASH_ADDR IFLASH0_ADDR
365 #define RNG_FLASH_SIZE IFLASH0_SIZE
366 #define RNG_FLASH_PAGE_SIZE IFLASH0_PAGE_SIZE
369 #define RNG_FLASH_ADDR IFLASH_ADDR
370 #define RNG_FLASH_SIZE IFLASH_SIZE
371 #define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
378 #define RNG_SEED_ADDR (RNG_FLASH_ADDR + RNG_FLASH_SIZE - RNG_FLASH_PAGE_SIZE)
379 #define RNG_SEED_PAGE ((RNG_FLASH_SIZE / RNG_FLASH_PAGE_SIZE) - 1)
385 __attribute__((section(
".ramfunc")))
386 static
void stirUniqueIdentifier(
void)
391 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
392 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
396 id[0] = *((
const uint32_t *)RNG_FLASH_ADDR);
397 id[1] = *((
const uint32_t *)(RNG_FLASH_ADDR + 4));
398 id[2] = *((
const uint32_t *)(RNG_FLASH_ADDR + 8));
399 id[3] = *((
const uint32_t *)(RNG_FLASH_ADDR + 12));
402 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
403 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
407 RNG.
stir((uint8_t *)id,
sizeof(id));
412 __attribute__((section(
".ramfunc")))
413 static
void eraseAndWriteSeed()
416 RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
419 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
445 memcpy_P(block, tagRNG,
sizeof(tagRNG));
446 memcpy_P(block + 4, initRNG,
sizeof(initRNG));
447 #if defined(RNG_EEPROM)
448 int address = RNG_EEPROM_ADDRESS;
449 eeprom_read_block(stream, (
const void *)address,
SEED_SIZE);
450 if (crypto_crc8(
'S', stream,
SEED_SIZE - 1) ==
451 ((
const uint8_t *)stream)[
SEED_SIZE - 1]) {
454 for (
int posn = 0; posn < 12; ++posn)
455 block[posn + 4] ^= stream[posn];
457 #elif defined(RNG_DUE_TRNG)
459 if (crypto_crc8(
'S', ((
const uint32_t *)RNG_SEED_ADDR) + 1,
SEED_SIZE)
460 == ((
const uint32_t *)RNG_SEED_ADDR)[0]) {
462 for (
int posn = 0; posn < 12; ++posn)
463 block[posn + 4] ^= ((
const uint32_t *)RNG_SEED_ADDR)[posn + 1];
469 pmc_enable_periph_clk(ID_TRNG);
470 REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
471 REG_TRNG_IDR = TRNG_IDR_DATRDY;
474 #if defined(RNG_ESP_NVS)
476 nvs_handle handle = 0;
477 if (nvs_open(
"rng", NVS_READONLY, &handle) == 0) {
479 if (nvs_get_blob(handle,
"seed", NULL, &len) == 0 && len ==
SEED_SIZE) {
481 if (nvs_get_blob(handle,
"seed", seed, &len) == 0) {
482 for (
int posn = 0; posn < 12; ++posn)
483 block[posn + 4] ^= seed[posn];
490 #if defined(RNG_WORD_TRNG)
506 stir((
const uint8_t *)tag, strlen(tag));
508 #if defined(RNG_DUE_TRNG)
511 stirUniqueIdentifier();
512 #elif defined(ESP8266)
516 ids[0] = ESP.getChipId();
517 ids[1] = ESP.getFlashChipId();
518 stir((
const uint8_t *)ids,
sizeof(ids));
521 uint64_t mac = ESP.getEfuseMac();
522 stir((
const uint8_t *)&mac,
sizeof(mac));
528 tag = __TIME__ __DATE__;
529 stir((
const uint8_t *)tag, strlen(tag));
532 #if defined(RNG_WATCHDOG)
538 MCUSR &= ~(1 << WDRF);
542 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
543 _WD_CONTROL_REG = (1 << WDIE);
547 #elif defined(RNG_CCL)
553 CCL.LUT1CTRLA = 0x01;
554 EVSYS.CHANNEL0 = EVSYS_CHANNEL0_CCL_LUT1_gc;
555 EVSYS.USERCCLLUT1A = EVSYS_USER_CHANNEL0_gc;
556 EVSYS.USERTCB0COUNT = EVSYS_USER_CHANNEL0_gc;
567 RTC.CLKSEL = RTC_CLKSEL_INT32K_gc;
568 while (RTC.STATUS > 0);
569 uint8_t CCL_SAMPLE_PERIOD;
571 CCL_SAMPLE_PERIOD = 2;
572 #elif(F_CPU == 4000000)
573 CCL_SAMPLE_PERIOD = 5;
574 #elif(F_CPU == 2000000)
575 CCL_SAMPLE_PERIOD = 9;
576 #elif(F_CPU == 1000000)
577 CCL_SAMPLE_PERIOD = 16;
579 #error "Chip frequency not supported"
581 RTC.PER = CCL_SAMPLE_PERIOD;
582 RTC.INTCTRL |= RTC_OVF_bm;
585 RTC.CTRLA = RTC_PRESCALER_DIV1_gc
613 #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
614 if (count < MAX_NOISE_SOURCES) {
615 noiseSources[count++] = &source;
640 timeout = ((uint32_t)minutes) * 60000U;
668 if ( (uint16_t)len > (credits / 8))
689 if (count >= RNG_REKEY_BLOCKS) {
702 memcpy(data, stream, len);
705 memcpy(data, stream, 64);
756 if (len >= (RNG_MAX_CREDITS / 8))
757 return credits >= RNG_MAX_CREDITS;
759 return (uint16_t)len <= (credits / 8);
790 if ((credit / 8) >= len && len)
792 if ((uint16_t)(RNG_MAX_CREDITS - credits) > credit)
795 credits = RNG_MAX_CREDITS;
804 size_t templen = len;
807 uint8_t *output = ((uint8_t *)block) + 16;
809 while (templen > 0) {
810 *output++ ^= *data++;
824 if (firstSave && credits >= RNG_MAX_CREDITS) {
862 #if defined(RNG_EEPROM)
866 int address = RNG_EEPROM_ADDRESS;
867 eeprom_write_block(stream, (
void *)address,
SEED_SIZE - 1);
868 eeprom_write_byte((uint8_t *)(address +
SEED_SIZE - 1),
869 crypto_crc8(
'S', stream,
SEED_SIZE - 1));
870 #elif defined(RNG_DUE_TRNG)
872 ((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8(
'S', stream,
SEED_SIZE);
873 for (posn = 0; posn < 12; ++posn)
874 ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
875 for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
876 ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
878 #elif defined(RNG_ESP_NVS)
880 nvs_handle handle = 0;
881 if (nvs_open(
"rng", NVS_READWRITE, &handle) == 0) {
882 nvs_erase_all(handle);
883 nvs_set_blob(handle,
"seed", stream,
SEED_SIZE);
901 for (uint8_t posn = 0; posn < count; ++posn)
902 noiseSources[posn]->
stir();
904 #if defined(RNG_DUE_TRNG)
924 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
925 block[4 + trngPosn] ^= REG_TRNG_ODATA;
926 if (++trngPosn >= 12)
928 if (credits < RNG_MAX_CREDITS) {
936 #elif defined(RNG_WORD_TRNG)
938 block[4 + trngPosn] ^= RNG_WORD_TRNG_GET();
939 if (++trngPosn >= 12)
941 if (credits < RNG_MAX_CREDITS) {
948 #elif defined(RNG_WATCHDOG)
952 uint32_t value = hash;
959 value += leftShift3(value);
960 value ^= rightShift11(value);
961 value += leftShift15(value);
966 if (credits > RNG_MAX_CREDITS)
967 credits = RNG_MAX_CREDITS;
971 block[4 + trngPosn] ^= value;
972 if (++trngPosn >= 12) {
982 #elif defined(RNG_CCL)
984 uint32_t value = hash;
990 value += leftShift3(value);
991 value ^= rightShift11(value);
992 value += leftShift15(value);
996 if (credits > RNG_MAX_CREDITS)
997 credits = RNG_MAX_CREDITS;
1000 block[4 + trngPosn] ^= value;
1001 if (++trngPosn >= 12) {
1012 if ((millis() - timer) >= timeout)
1039 #if defined(RNG_EEPROM)
1040 int address = RNG_EEPROM_ADDRESS;
1041 for (
int posn = 0; posn <
SEED_SIZE; ++posn)
1042 eeprom_write_byte((uint8_t *)(address + posn), 0xFF);
1043 #elif defined(RNG_DUE_TRNG)
1044 for (
unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
1045 ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF;
1046 eraseAndWriteSeed();
1047 #elif defined(RNG_ESP_NVS)
1048 nvs_handle handle = 0;
1049 if (nvs_open(
"rng", NVS_READWRITE, &handle) == 0) {
1050 nvs_erase_all(handle);
1061 void RNGClass::rekey()
1069 memcpy(block + 4, stream, 48);
1076 block[13] ^= micros();
1082 void RNGClass::mixTRNG()
1084 #if defined(RNG_DUE_TRNG)
1086 for (
int posn = 0; posn < 12; ++posn) {
1092 for (counter = 0; counter < 200; ++counter) {
1093 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
1098 block[posn + 4] ^= REG_TRNG_ODATA;
1100 #elif defined(RNG_WORD_TRNG)
1102 for (uint8_t index = 4; index < 16; ++index)
1103 block[index] ^= RNG_WORD_TRNG_GET();
1104 #elif defined(RNG_WATCHDOG)
1107 if (outBits >= 32) {
1108 uint32_t value = hash;
1115 value += leftShift3(value);
1116 value ^= rightShift11(value);
1117 value += leftShift15(value);
1124 #elif defined(RNG_CCL)
1125 if (outBits >= 32) {
1126 uint32_t value = hash;
1132 value += leftShift3(value);
1133 value ^= rightShift11(value);
1134 value += leftShift15(value);
static void hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds)
Executes the ChaCha hash core on an input memory block.
Abstract base class for random noise sources.
virtual void added()
Called when the noise source is added to RNG with RNG.addNoiseSource().
Pseudo random number generator suitable for cryptography.
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 setAutoSaveTime(uint16_t minutes)
Sets the amount of time between automatic seed saves.
void begin(const char *tag)
Initializes the random number generator.
void loop()
Run periodic housekeeping tasks on the random number generator.
void destroy()
Destroys the data in the random number pool and the saved seed in EEPROM.
void addNoiseSource(NoiseSource &source)
Adds a noise source to the random number generator.
bool available(size_t len) const
Determine if there is sufficient entropy available for a specific request size.
RNGClass()
Constructs a new random number generator instance.
void stir(const uint8_t *data, size_t len, unsigned int credit=0)
Stirs additional entropy data into the random pool.
static const int SEED_SIZE
Size of a saved random number seed in EEPROM space.
~RNGClass()
Destroys this random number generator instance.