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>
142 #define RNG_ROUNDS 20
145 #define RNG_REKEY_BLOCKS 16
148 #define RNG_MAX_CREDITS 384
154 static const char tagRNG[16] PROGMEM = {
155 'e',
'x',
'p',
'a',
'n',
'd',
' ',
'3',
156 '2',
'-',
'b',
'y',
't',
'e',
' ',
'k'
165 static const uint8_t initRNG[48] PROGMEM = {
166 0xB0, 0x2A, 0xAE, 0x7D, 0xEE, 0xCB, 0xBB, 0xB1,
167 0xFC, 0x03, 0x6F, 0xDD, 0xDC, 0x7D, 0x76, 0x67,
168 0x0C, 0xE8, 0x1F, 0x0D, 0xA3, 0xA0, 0xAA, 0x1E,
169 0xB0, 0xBD, 0x72, 0x6B, 0x2B, 0x4C, 0x8A, 0x7E,
170 0x34, 0xFC, 0x37, 0x60, 0xF4, 0x1E, 0x22, 0xA0,
171 0x0B, 0xFB, 0x18, 0x84, 0x60, 0xA5, 0x77, 0x72
174 #if defined(RNG_WATCHDOG)
186 #define leftShift3(value) ((value) << 3)
187 #define leftShift10(value) ((value) << 10)
188 #define leftShift15(value) ((value) << 15)
189 #define rightShift6(value) ((value) >> 6)
190 #define rightShift11(value) ((value) >> 11)
192 static uint32_t
volatile hash = 0;
193 static uint8_t
volatile outBits = 0;
204 unsigned char value = TCNT1L;
205 #elif defined(TCNT0L)
206 unsigned char value = TCNT0L;
208 unsigned char value = TCNT0;
213 hash += leftShift10(hash);
214 hash ^= rightShift6(hash);
218 #endif // RNG_WATCHDOG
246 #if defined(RNG_DUE_TRNG)
248 REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
250 #if defined(RNG_WATCHDOG)
256 MCUSR &= ~(1 << WDRF);
259 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
269 #if defined(RNG_DUE_TRNG)
273 #if defined(IFLASH1_ADDR)
274 #define RNG_FLASH_ADDR IFLASH1_ADDR
275 #define RNG_FLASH_SIZE IFLASH1_SIZE
276 #define RNG_FLASH_PAGE_SIZE IFLASH1_PAGE_SIZE
278 #elif defined(IFLASH0_ADDR)
279 #define RNG_FLASH_ADDR IFLASH0_ADDR
280 #define RNG_FLASH_SIZE IFLASH0_SIZE
281 #define RNG_FLASH_PAGE_SIZE IFLASH0_PAGE_SIZE
284 #define RNG_FLASH_ADDR IFLASH_ADDR
285 #define RNG_FLASH_SIZE IFLASH_SIZE
286 #define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
293 #define RNG_SEED_ADDR (RNG_FLASH_ADDR + RNG_FLASH_SIZE - RNG_FLASH_PAGE_SIZE)
294 #define RNG_SEED_PAGE ((RNG_FLASH_SIZE / RNG_FLASH_PAGE_SIZE) - 1)
300 __attribute__((section(
".ramfunc")))
301 static
void stirUniqueIdentifier(
void)
306 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
307 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
311 id[0] = *((
const uint32_t *)RNG_FLASH_ADDR);
312 id[1] = *((
const uint32_t *)(RNG_FLASH_ADDR + 4));
313 id[2] = *((
const uint32_t *)(RNG_FLASH_ADDR + 8));
314 id[3] = *((
const uint32_t *)(RNG_FLASH_ADDR + 12));
317 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
318 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
322 RNG.
stir((uint8_t *)
id,
sizeof(
id));
327 __attribute__((section(
".ramfunc")))
328 static
void eraseAndWriteSeed()
331 RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
334 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
362 address = eepromAddress;
365 memcpy_P(block, tagRNG,
sizeof(tagRNG));
366 memcpy_P(block + 4, initRNG,
sizeof(initRNG));
367 #if defined(RNG_EEPROM)
368 if (eeprom_read_byte((
const uint8_t *)address) ==
'S') {
370 for (
int posn = 0; posn < 12; ++posn) {
372 eeprom_read_dword((
const uint32_t *)(address + posn * 4 + 1));
375 #elif defined(RNG_DUE_TRNG)
378 if (((
const uint32_t *)RNG_SEED_ADDR)[0] ==
'S') {
380 for (posn = 0; posn < 12; ++posn)
381 block[posn + 4] ^= ((
const uint32_t *)RNG_SEED_ADDR)[posn + 1];
387 pmc_enable_periph_clk(ID_TRNG);
388 REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
389 REG_TRNG_IDR = TRNG_IDR_DATRDY;
390 for (posn = 0; posn < 12; ++posn) {
395 for (counter = 0; counter < 200; ++counter) {
396 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
401 block[posn + 4] ^= REG_TRNG_ODATA;
416 stir((
const uint8_t *)tag, strlen(tag));
418 #if defined(RNG_DUE_TRNG)
421 stirUniqueIdentifier();
424 #if defined(RNG_WATCHDOG)
430 MCUSR &= ~(1 << WDRF);
434 _WD_CONTROL_REG |= (1 << _WD_CHANGE_BIT) | (1 << WDE);
435 _WD_CONTROL_REG = (1 << WDIE);
461 #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
462 if (count < MAX_NOISE_SOURCES) {
463 noiseSources[count++] = &source;
488 timeout = ((uint32_t)minutes) * 60000U;
511 if (len > (credits / 8))
520 if (count >= RNG_REKEY_BLOCKS) {
533 memcpy(data, stream, len);
536 memcpy(data, stream, 64);
587 if (len >= (RNG_MAX_CREDITS / 8))
588 return credits >= RNG_MAX_CREDITS;
590 return len <= (credits / 8);
621 if ((credit / 8) >= len && len)
623 if ((RNG_MAX_CREDITS - credits) > credit)
626 credits = RNG_MAX_CREDITS;
635 size_t templen = len;
638 uint8_t *output = ((uint8_t *)block) + 16;
640 while (templen > 0) {
641 *output++ ^= *data++;
655 if (firstSave && credits >= RNG_MAX_CREDITS) {
693 #if defined(RNG_EEPROM)
694 eeprom_write_block(stream, (
void *)(address + 1), 48);
695 eeprom_update_byte((uint8_t *)address,
'S');
696 #elif defined(RNG_DUE_TRNG)
698 ((uint32_t *)(RNG_SEED_ADDR))[0] =
'S';
699 for (posn = 0; posn < 12; ++posn)
700 ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
701 for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
702 ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
718 for (uint8_t posn = 0; posn < count; ++posn)
719 noiseSources[posn]->
stir();
721 #if defined(RNG_DUE_TRNG)
741 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
742 block[4 + trngPosn] ^= REG_TRNG_ODATA;
743 if (++trngPosn >= 12)
745 if (credits < RNG_MAX_CREDITS) {
752 #elif defined(RNG_WATCHDOG)
756 uint32_t value = hash;
763 value += leftShift3(value);
764 value ^= rightShift11(value);
765 value += leftShift15(value);
769 block[4 + trngPosn] ^= value;
770 if (++trngPosn >= 12) {
783 if ((millis() - timer) >= timeout)
810 #if defined(RNG_EEPROM)
811 for (
int posn = 0; posn <
SEED_SIZE; ++posn)
812 eeprom_write_byte((uint8_t *)(address + posn), 0xFF);
813 #elif defined(RNG_DUE_TRNG)
814 for (
unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
815 ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF;
823 void RNGClass::rekey()
831 memcpy(block + 4, stream, 48);
838 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, int eepromAddress)
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.