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)
40 #elif defined(ESP8266)
44 #define RNG_WORD_TRNG 1
45 #define RNG_WORD_TRNG_GET() (ESP8266_DREG(0x20E44))
48 #define RNG_WORD_TRNG 1
49 #define RNG_WORD_TRNG_GET() (esp_random())
60 #if !defined(RNG_DUE_TRNG) && \
61 !defined(RNG_WATCHDOG) && \
62 !defined(RNG_WORD_TRNG)
63 #error "no hardware random number source detected for this platform"
170 #define RNG_ROUNDS 20
173 #define RNG_REKEY_BLOCKS 16
176 #define RNG_MAX_CREDITS 384u
181 extern uint8_t crypto_crc8(uint8_t tag,
const void *data,
unsigned size);
185 static const char tagRNG[16] PROGMEM = {
186 'e',
'x',
'p',
'a',
'n',
'd',
' ',
'3',
187 '2',
'-',
'b',
'y',
't',
'e',
' ',
'k'
196 static const uint8_t initRNG[48] PROGMEM = {
197 0xB0, 0x2A, 0xAE, 0x7D, 0xEE, 0xCB, 0xBB, 0xB1,
198 0xFC, 0x03, 0x6F, 0xDD, 0xDC, 0x7D, 0x76, 0x67,
199 0x0C, 0xE8, 0x1F, 0x0D, 0xA3, 0xA0, 0xAA, 0x1E,
200 0xB0, 0xBD, 0x72, 0x6B, 0x2B, 0x4C, 0x8A, 0x7E,
201 0x34, 0xFC, 0x37, 0x60, 0xF4, 0x1E, 0x22, 0xA0,
202 0x0B, 0xFB, 0x18, 0x84, 0x60, 0xA5, 0x77, 0x72
205 #if defined(RNG_WATCHDOG)
217 #define leftShift3(value) ((value) << 3)
218 #define leftShift10(value) ((value) << 10)
219 #define leftShift15(value) ((value) << 15)
220 #define rightShift6(value) ((value) >> 6)
221 #define rightShift11(value) ((value) >> 11)
223 static uint32_t
volatile hash = 0;
224 static uint8_t
volatile outBits = 0;
235 unsigned char value = TCNT1L;
236 #elif defined(TCNT0L)
237 unsigned char value = TCNT0L;
239 unsigned char value = TCNT0;
244 hash += leftShift10(hash);
245 hash ^= rightShift6(hash);
249 #endif // RNG_WATCHDOG
278 #if defined(RNG_DUE_TRNG)
280 REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
282 #if defined(RNG_WATCHDOG)
288 MCUSR &= ~(1 << WDRF);
291 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
301 #if defined(RNG_DUE_TRNG)
305 #if defined(IFLASH1_ADDR)
306 #define RNG_FLASH_ADDR IFLASH1_ADDR
307 #define RNG_FLASH_SIZE IFLASH1_SIZE
308 #define RNG_FLASH_PAGE_SIZE IFLASH1_PAGE_SIZE
310 #elif defined(IFLASH0_ADDR)
311 #define RNG_FLASH_ADDR IFLASH0_ADDR
312 #define RNG_FLASH_SIZE IFLASH0_SIZE
313 #define RNG_FLASH_PAGE_SIZE IFLASH0_PAGE_SIZE
316 #define RNG_FLASH_ADDR IFLASH_ADDR
317 #define RNG_FLASH_SIZE IFLASH_SIZE
318 #define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
325 #define RNG_SEED_ADDR (RNG_FLASH_ADDR + RNG_FLASH_SIZE - RNG_FLASH_PAGE_SIZE)
326 #define RNG_SEED_PAGE ((RNG_FLASH_SIZE / RNG_FLASH_PAGE_SIZE) - 1)
332 __attribute__((section(
".ramfunc")))
333 static
void stirUniqueIdentifier(
void)
338 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
339 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
343 id[0] = *((
const uint32_t *)RNG_FLASH_ADDR);
344 id[1] = *((
const uint32_t *)(RNG_FLASH_ADDR + 4));
345 id[2] = *((
const uint32_t *)(RNG_FLASH_ADDR + 8));
346 id[3] = *((
const uint32_t *)(RNG_FLASH_ADDR + 12));
349 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
350 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
354 RNG.
stir((uint8_t *)
id,
sizeof(
id));
359 __attribute__((section(
".ramfunc")))
360 static
void eraseAndWriteSeed()
363 RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
366 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
392 memcpy_P(block, tagRNG,
sizeof(tagRNG));
393 memcpy_P(block + 4, initRNG,
sizeof(initRNG));
394 #if defined(RNG_EEPROM)
395 int address = RNG_EEPROM_ADDRESS;
396 eeprom_read_block(stream, (
const void *)address,
SEED_SIZE);
397 if (crypto_crc8(
'S', stream,
SEED_SIZE - 1) ==
398 ((
const uint8_t *)stream)[
SEED_SIZE - 1]) {
401 for (
int posn = 0; posn < 12; ++posn)
402 block[posn + 4] ^= stream[posn];
404 #elif defined(RNG_DUE_TRNG)
406 if (crypto_crc8(
'S', ((
const uint32_t *)RNG_SEED_ADDR) + 1,
SEED_SIZE)
407 == ((
const uint32_t *)RNG_SEED_ADDR)[0]) {
409 for (
int posn = 0; posn < 12; ++posn)
410 block[posn + 4] ^= ((
const uint32_t *)RNG_SEED_ADDR)[posn + 1];
416 pmc_enable_periph_clk(ID_TRNG);
417 REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
418 REG_TRNG_IDR = TRNG_IDR_DATRDY;
421 #if defined(RNG_ESP_NVS)
423 nvs_handle handle = 0;
424 if (nvs_open(
"rng", NVS_READONLY, &handle) == 0) {
426 if (nvs_get_blob(handle,
"seed", NULL, &len) == 0 && len ==
SEED_SIZE) {
428 if (nvs_get_blob(handle,
"seed", seed, &len) == 0) {
429 for (
int posn = 0; posn < 12; ++posn)
430 block[posn + 4] ^= seed[posn];
437 #if defined(RNG_WORD_TRNG)
453 stir((
const uint8_t *)tag, strlen(tag));
455 #if defined(RNG_DUE_TRNG)
458 stirUniqueIdentifier();
459 #elif defined(ESP8266)
463 ids[0] = ESP.getChipId();
464 ids[1] = ESP.getFlashChipId();
465 stir((
const uint8_t *)ids,
sizeof(ids));
468 uint64_t mac = ESP.getEfuseMac();
469 stir((
const uint8_t *)&mac,
sizeof(mac));
475 tag = __TIME__ __DATE__;
476 stir((
const uint8_t *)tag, strlen(tag));
479 #if defined(RNG_WATCHDOG)
485 MCUSR &= ~(1 << WDRF);
489 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
490 _WD_CONTROL_REG = (1 << WDIE);
519 #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
520 if (count < MAX_NOISE_SOURCES) {
521 noiseSources[count++] = &source;
546 timeout = ((uint32_t)minutes) * 60000U;
574 if (len > (credits / 8u))
595 if (count >= RNG_REKEY_BLOCKS) {
608 memcpy(data, stream, len);
611 memcpy(data, stream, 64);
662 if (len >= (RNG_MAX_CREDITS / 8))
663 return credits >= RNG_MAX_CREDITS;
665 return len <= (credits / 8u);
696 if ((credit / 8) >= len && len)
698 if ((RNG_MAX_CREDITS - credits) > credit)
701 credits = RNG_MAX_CREDITS;
710 size_t templen = len;
713 uint8_t *output = ((uint8_t *)block) + 16;
715 while (templen > 0) {
716 *output++ ^= *data++;
730 if (firstSave && credits >= RNG_MAX_CREDITS) {
768 #if defined(RNG_EEPROM)
772 int address = RNG_EEPROM_ADDRESS;
773 eeprom_write_block(stream, (
void *)address,
SEED_SIZE - 1);
774 eeprom_write_byte((uint8_t *)(address +
SEED_SIZE - 1),
775 crypto_crc8(
'S', stream,
SEED_SIZE - 1));
776 #elif defined(RNG_DUE_TRNG)
778 ((uint32_t *)(RNG_SEED_ADDR))[0] = crypto_crc8(
'S', stream,
SEED_SIZE);
779 for (posn = 0; posn < 12; ++posn)
780 ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
781 for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
782 ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
784 #elif defined(RNG_ESP_NVS)
786 nvs_handle handle = 0;
787 if (nvs_open(
"rng", NVS_READWRITE, &handle) == 0) {
788 nvs_erase_all(handle);
789 nvs_set_blob(handle,
"seed", stream,
SEED_SIZE);
807 for (uint8_t posn = 0; posn < count; ++posn)
808 noiseSources[posn]->
stir();
810 #if defined(RNG_DUE_TRNG)
830 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
831 block[4 + trngPosn] ^= REG_TRNG_ODATA;
832 if (++trngPosn >= 12)
834 if (credits < RNG_MAX_CREDITS) {
842 #elif defined(RNG_WORD_TRNG)
844 block[4 + trngPosn] ^= RNG_WORD_TRNG_GET();
845 if (++trngPosn >= 12)
847 if (credits < RNG_MAX_CREDITS) {
854 #elif defined(RNG_WATCHDOG)
858 uint32_t value = hash;
865 value += leftShift3(value);
866 value ^= rightShift11(value);
867 value += leftShift15(value);
872 if (credits > RNG_MAX_CREDITS)
873 credits = RNG_MAX_CREDITS;
877 block[4 + trngPosn] ^= value;
878 if (++trngPosn >= 12) {
891 if ((millis() - timer) >= timeout)
918 #if defined(RNG_EEPROM)
919 int address = RNG_EEPROM_ADDRESS;
920 for (
int posn = 0; posn <
SEED_SIZE; ++posn)
921 eeprom_write_byte((uint8_t *)(address + posn), 0xFF);
922 #elif defined(RNG_DUE_TRNG)
923 for (
unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
924 ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF;
926 #elif defined(RNG_ESP_NVS)
927 nvs_handle handle = 0;
928 if (nvs_open(
"rng", NVS_READWRITE, &handle) == 0) {
929 nvs_erase_all(handle);
940 void RNGClass::rekey()
948 memcpy(block + 4, stream, 48);
955 block[13] ^= micros();
961 void RNGClass::mixTRNG()
963 #if defined(RNG_DUE_TRNG)
965 for (
int posn = 0; posn < 12; ++posn) {
971 for (counter = 0; counter < 200; ++counter) {
972 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
977 block[posn + 4] ^= REG_TRNG_ODATA;
979 #elif defined(RNG_WORD_TRNG)
981 for (uint8_t index = 4; index < 16; ++index)
982 block[index] ^= RNG_WORD_TRNG_GET();
983 #elif defined(RNG_WATCHDOG)
987 uint32_t value = hash;
994 value += leftShift3(value);
995 value ^= rightShift11(value);
996 value += leftShift15(value);
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.