24 #include "NoiseSource.h"
27 #include "utility/ProgMemUtil.h"
29 #if defined (__arm__) && defined (__SAM3X8E__)
32 #define RNG_DUE_TRNG 1
35 #include <avr/eeprom.h>
140 #define RNG_ROUNDS 20
143 #define RNG_REKEY_BLOCKS 16
146 #define RNG_MAX_CREDITS 384
152 static const char tagRNG[16] PROGMEM = {
153 'e',
'x',
'p',
'a',
'n',
'd',
' ',
'3',
154 '2',
'-',
'b',
'y',
't',
'e',
' ',
'k'
163 static const uint8_t initRNG[48] PROGMEM = {
164 0xB0, 0x2A, 0xAE, 0x7D, 0xEE, 0xCB, 0xBB, 0xB1,
165 0xFC, 0x03, 0x6F, 0xDD, 0xDC, 0x7D, 0x76, 0x67,
166 0x0C, 0xE8, 0x1F, 0x0D, 0xA3, 0xA0, 0xAA, 0x1E,
167 0xB0, 0xBD, 0x72, 0x6B, 0x2B, 0x4C, 0x8A, 0x7E,
168 0x34, 0xFC, 0x37, 0x60, 0xF4, 0x1E, 0x22, 0xA0,
169 0x0B, 0xFB, 0x18, 0x84, 0x60, 0xA5, 0x77, 0x72
198 #if defined(RNG_DUE_TRNG)
200 REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
206 #if defined(RNG_DUE_TRNG)
210 #if defined(IFLASH1_ADDR)
211 #define RNG_FLASH_ADDR IFLASH1_ADDR
212 #define RNG_FLASH_SIZE IFLASH1_SIZE
213 #define RNG_FLASH_PAGE_SIZE IFLASH1_PAGE_SIZE
215 #elif defined(IFLASH0_ADDR)
216 #define RNG_FLASH_ADDR IFLASH0_ADDR
217 #define RNG_FLASH_SIZE IFLASH0_SIZE
218 #define RNG_FLASH_PAGE_SIZE IFLASH0_PAGE_SIZE
221 #define RNG_FLASH_ADDR IFLASH_ADDR
222 #define RNG_FLASH_SIZE IFLASH_SIZE
223 #define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
230 #define RNG_SEED_ADDR (RNG_FLASH_ADDR + RNG_FLASH_SIZE - RNG_FLASH_PAGE_SIZE)
231 #define RNG_SEED_PAGE ((RNG_FLASH_SIZE / RNG_FLASH_PAGE_SIZE) - 1)
237 __attribute__((section(
".ramfunc")))
238 static
void stirUniqueIdentifier(
void)
243 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
244 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
248 id[0] = *((
const uint32_t *)RNG_FLASH_ADDR);
249 id[1] = *((
const uint32_t *)(RNG_FLASH_ADDR + 4));
250 id[2] = *((
const uint32_t *)(RNG_FLASH_ADDR + 8));
251 id[3] = *((
const uint32_t *)(RNG_FLASH_ADDR + 12));
254 RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
255 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
259 RNG.
stir((uint8_t *)
id,
sizeof(
id));
264 __attribute__((section(
".ramfunc")))
265 static
void eraseAndWriteSeed()
268 RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
271 while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
299 address = eepromAddress;
302 memcpy_P(block, tagRNG,
sizeof(tagRNG));
303 memcpy_P(block + 4, initRNG,
sizeof(initRNG));
304 #if defined(RNG_EEPROM)
305 if (eeprom_read_byte((
const uint8_t *)address) ==
'S') {
307 for (
int posn = 0; posn < 12; ++posn) {
309 eeprom_read_dword((
const uint32_t *)(address + posn * 4 + 1));
312 #elif defined(RNG_DUE_TRNG)
315 if (((
const uint32_t *)RNG_SEED_ADDR)[0] ==
'S') {
317 for (posn = 0; posn < 12; ++posn)
318 block[posn + 4] ^= ((
const uint32_t *)RNG_SEED_ADDR)[posn + 1];
324 pmc_enable_periph_clk(ID_TRNG);
325 REG_TRNG_CR = TRNG_CR_KEY(0x524E47) | TRNG_CR_ENABLE;
326 REG_TRNG_IDR = TRNG_IDR_DATRDY;
327 for (posn = 0; posn < 12; ++posn) {
332 for (counter = 0; counter < 200; ++counter) {
333 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
338 block[posn + 4] ^= REG_TRNG_ODATA;
353 stir((
const uint8_t *)tag, strlen(tag));
355 #if defined(RNG_DUE_TRNG)
358 stirUniqueIdentifier();
381 #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
382 if (count < MAX_NOISE_SOURCES) {
383 noiseSources[count++] = &source;
408 timeout = ((uint32_t)minutes) * 60000U;
431 if (len > (credits / 8))
440 if (count >= RNG_REKEY_BLOCKS) {
453 memcpy(data, stream, len);
456 memcpy(data, stream, 64);
507 if (len >= (RNG_MAX_CREDITS / 8))
508 return credits >= RNG_MAX_CREDITS;
510 return len <= (credits / 8);
541 if ((credit / 8) >= len)
543 if ((RNG_MAX_CREDITS - credits) > credit)
546 credits = RNG_MAX_CREDITS;
555 size_t templen = len;
558 uint8_t *output = ((uint8_t *)block) + 16;
560 while (templen > 0) {
561 *output++ ^= *data++;
575 if (firstSave && credits >= RNG_MAX_CREDITS) {
613 #if defined(RNG_EEPROM)
614 eeprom_write_block(stream, (
void *)(address + 1), 48);
615 eeprom_update_byte((uint8_t *)address,
'S');
616 #elif defined(RNG_DUE_TRNG)
618 ((uint32_t *)(RNG_SEED_ADDR))[0] =
'S';
619 for (posn = 0; posn < 12; ++posn)
620 ((uint32_t *)(RNG_SEED_ADDR))[posn + 1] = stream[posn];
621 for (posn = 13; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
622 ((uint32_t *)(RNG_SEED_ADDR))[posn + 13] = 0xFFFFFFFF;
638 for (uint8_t posn = 0; posn < count; ++posn)
639 noiseSources[posn]->
stir();
641 #if defined(RNG_DUE_TRNG)
661 if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
662 block[4 + trngPosn] ^= REG_TRNG_ODATA;
663 if (++trngPosn >= 12)
665 if (credits < RNG_MAX_CREDITS) {
675 if ((millis() - timer) >= timeout)
702 #if defined(RNG_EEPROM)
703 for (
int posn = 0; posn <
SEED_SIZE; ++posn)
704 eeprom_write_byte((uint8_t *)(address + posn), 0xFF);
705 #elif defined(RNG_DUE_TRNG)
706 for (
unsigned posn = 0; posn < (RNG_FLASH_PAGE_SIZE / 4); ++posn)
707 ((uint32_t *)(RNG_SEED_ADDR))[posn] = 0xFFFFFFFF;
715 void RNGClass::rekey()
723 memcpy(block + 4, stream, 48);
730 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.