ArduinoLibs
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
RNG.cpp
1 /*
2  * Copyright (C) 2015 Southern Storm Software, Pty Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "RNG.h"
24 #include "NoiseSource.h"
25 #include "ChaCha.h"
26 #include "Crypto.h"
27 #include "utility/ProgMemUtil.h"
28 #include <Arduino.h>
29 #if defined (__arm__) && defined (__SAM3X8E__)
30 // The Arduino Due does not have any EEPROM natively on the main chip.
31 // However, it does have a TRNG and flash memory.
32 #define RNG_DUE_TRNG 1
33 #else
34 #define RNG_EEPROM 1
35 #include <avr/eeprom.h>
36 #endif
37 #include <string.h>
38 
132 RNGClass RNG;
133 
139 // Number of ChaCha hash rounds to use for random number generation.
140 #define RNG_ROUNDS 20
141 
142 // Force a rekey after this many blocks of random data.
143 #define RNG_REKEY_BLOCKS 16
144 
145 // Maximum entropy credit that can be contained in the pool.
146 #define RNG_MAX_CREDITS 384
147 
150 // Tag for 256-bit ChaCha20 keys. This will always appear in the
151 // first 16 bytes of the block. The remaining 48 bytes are the seed.
152 static const char tagRNG[16] PROGMEM = {
153  'e', 'x', 'p', 'a', 'n', 'd', ' ', '3',
154  '2', '-', 'b', 'y', 't', 'e', ' ', 'k'
155 };
156 
157 // Initialization seed. This is the ChaCha20 output of hashing
158 // "expand 32-byte k" followed by 48 bytes set to the numbers 1 to 48.
159 // The ChaCha20 output block is then truncated to the first 48 bytes.
160 //
161 // This value is intended to start the RNG in a semi-chaotic state if
162 // we don't have a previously saved seed in EEPROM.
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
170 };
171 
183  : address(0)
184  , credits(0)
185  , firstSave(1)
186  , timer(0)
187  , timeout(3600000UL) // 1 hour in milliseconds
188  , count(0)
189  , trngPosn(0)
190 {
191 }
192 
197 {
198 #if defined(RNG_DUE_TRNG)
199  // Disable the TRNG in the Arduino Due.
200  REG_TRNG_CR = TRNG_CR_KEY(0x524E47);
201 #endif
202  clean(block);
203  clean(stream);
204 }
205 
206 #if defined(RNG_DUE_TRNG)
207 
208 // Find the flash memory of interest. Allow for the possibility
209 // of other SAM-based Arduino variants in the future.
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
214 #define RNG_EFC EFC1
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
219 #define RNG_EFC EFC0
220 #else
221 #define RNG_FLASH_ADDR IFLASH_ADDR
222 #define RNG_FLASH_SIZE IFLASH_SIZE
223 #define RNG_FLASH_PAGE_SIZE IFLASH_PAGE_SIZE
224 #define RNG_EFC EFC
225 #endif
226 
227 // Address of the flash page to use for saving the seed on the Due.
228 // All SAM variants have a page size of 256 bytes or greater so there is
229 // plenty of room for the 48 byte seed in the last page of flash memory.
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)
232 
233 // Stir in the unique identifier for the Arduino Due's CPU.
234 // This function must be in RAM because programs running out of
235 // flash memory are not allowed to access the unique identifier.
236 // Info from: http://forum.arduino.cc/index.php?topic=289190.0
237 __attribute__((section(".ramfunc")))
238 static void stirUniqueIdentifier(void)
239 {
240  uint32_t id[4];
241 
242  // Start Read Unique Identifier.
243  RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_STUI;
244  while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) != 0)
245  ; // do nothing until FRDY falls.
246 
247  // Read the identifier.
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));
252 
253  // Stop Read Unique Identifier.
254  RNG_EFC->EEFC_FCR = (0x5A << 24) | EFC_FCMD_SPUI;
255  while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
256  ; // do nothing until FRDY rises.
257 
258  // Stir the unique identifier into the entropy pool.
259  RNG.stir((uint8_t *)id, sizeof(id));
260 }
261 
262 // Erases the flash page containing the seed and then writes the new seed.
263 // It is assumed the seed has already been loaded into the latch registers.
264 __attribute__((section(".ramfunc")))
265 static void eraseAndWriteSeed()
266 {
267  // Execute the "Erase and Write Page" command.
268  RNG_EFC->EEFC_FCR = (0x5A << 24) | (RNG_SEED_PAGE << 8) | EFC_FCMD_EWP;
269 
270  // Wait for the FRDY bit to be raised.
271  while ((RNG_EFC->EEFC_FSR & EEFC_FSR_FRDY) == 0)
272  ; // do nothing until FRDY rises.
273 }
274 
275 #endif
276 
296 void RNGClass::begin(const char *tag, int eepromAddress)
297 {
298  // Save the EEPROM address for use by save().
299  address = eepromAddress;
300 
301  // Initialize the ChaCha20 input block from the saved seed.
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') {
306  // We have a saved seed: XOR it with the initialization block.
307  for (int posn = 0; posn < 12; ++posn) {
308  block[posn + 4] ^=
309  eeprom_read_dword((const uint32_t *)(address + posn * 4 + 1));
310  }
311  }
312 #elif defined(RNG_DUE_TRNG)
313  // Do we have a seed saved in the last page of flash memory on the Due?
314  int posn, counter;
315  if (((const uint32_t *)RNG_SEED_ADDR)[0] == 'S') {
316  // XOR the saved seed with the initialization block.
317  for (posn = 0; posn < 12; ++posn)
318  block[posn + 4] ^= ((const uint32_t *)RNG_SEED_ADDR)[posn + 1];
319  }
320 
321  // If the device has just been reprogrammed, there will be no saved seed.
322  // XOR the initialization block with some output from the CPU's TRNG
323  // to permute the state in a first boot situation after reprogramming.
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; // Disable interrupts - we will poll.
327  for (posn = 0; posn < 12; ++posn) {
328  // According to the documentation the TRNG should produce a new
329  // 32-bit random value every 84 clock cycles. If it still hasn't
330  // produced a value after 200 iterations, then assume that the
331  // TRNG is not producing output and stop.
332  for (counter = 0; counter < 200; ++counter) {
333  if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0)
334  break;
335  }
336  if (counter >= 200)
337  break;
338  block[posn + 4] ^= REG_TRNG_ODATA;
339  }
340 #endif
341 
342  // No entropy credits for the saved seed.
343  credits = 0;
344 
345  // Trigger an automatic save once the entropy credits max out.
346  firstSave = 1;
347 
348  // Rekey the random number generator immediately.
349  rekey();
350 
351  // Stir in the supplied tag data but don't credit any entropy to it.
352  if (tag)
353  stir((const uint8_t *)tag, strlen(tag));
354 
355 #if defined(RNG_DUE_TRNG)
356  // Stir in the unique identifier for the CPU so that different
357  // devices will give different outputs even without seeding.
358  stirUniqueIdentifier();
359 #endif
360 
361  // Re-save the seed to obliterate the previous value and to ensure
362  // that if the system is reset without a call to save() that we won't
363  // accidentally generate the same sequence of random data again.
364  save();
365 }
366 
380 {
381  #define MAX_NOISE_SOURCES (sizeof(noiseSources) / sizeof(noiseSources[0]))
382  if (count < MAX_NOISE_SOURCES) {
383  noiseSources[count++] = &source;
384  source.added();
385  }
386 }
387 
404 void RNGClass::setAutoSaveTime(uint16_t minutes)
405 {
406  if (!minutes)
407  minutes = 1; // Just in case.
408  timeout = ((uint32_t)minutes) * 60000U;
409 }
410 
428 void RNGClass::rand(uint8_t *data, size_t len)
429 {
430  // Decrease the amount of entropy in the pool.
431  if (len > (credits / 8))
432  credits = 0;
433  else
434  credits -= len * 8;
435 
436  // Generate the random data.
437  uint8_t count = 0;
438  while (len > 0) {
439  // Force a rekey if we have generated too many blocks in this request.
440  if (count >= RNG_REKEY_BLOCKS) {
441  rekey();
442  count = 1;
443  } else {
444  ++count;
445  }
446 
447  // Increment the low counter word and generate a new keystream block.
448  ++(block[12]);
449  ChaCha::hashCore(stream, block, RNG_ROUNDS);
450 
451  // Copy the data to the return buffer.
452  if (len < 64) {
453  memcpy(data, stream, len);
454  break;
455  } else {
456  memcpy(data, stream, 64);
457  data += 64;
458  len -= 64;
459  }
460  }
461 
462  // Force a rekey after every request.
463  rekey();
464 }
465 
505 bool RNGClass::available(size_t len) const
506 {
507  if (len >= (RNG_MAX_CREDITS / 8))
508  return credits >= RNG_MAX_CREDITS;
509  else
510  return len <= (credits / 8);
511 }
512 
538 void RNGClass::stir(const uint8_t *data, size_t len, unsigned int credit)
539 {
540  // Increase the entropy credit.
541  if ((credit / 8) >= len)
542  credit = len * 8;
543  if ((RNG_MAX_CREDITS - credits) > credit)
544  credits += credit;
545  else
546  credits = RNG_MAX_CREDITS;
547 
548  // Process the supplied input data.
549  if (len > 0) {
550  // XOR the data with the ChaCha input block in 48 byte
551  // chunks and rekey the ChaCha cipher for each chunk to mix
552  // the data in. This should scatter any "true entropy" in
553  // the input across the entire block.
554  while (len > 0) {
555  size_t templen = len;
556  if (templen > 48)
557  templen = 48;
558  uint8_t *output = ((uint8_t *)block) + 16;
559  len -= templen;
560  while (templen > 0) {
561  *output++ ^= *data++;
562  --templen;
563  }
564  rekey();
565  }
566  } else {
567  // There was no input data, so just force a rekey so we
568  // get some mixing of the state even without new data.
569  rekey();
570  }
571 
572  // Save if this is the first time we have reached max entropy.
573  // This provides some protection if the system is powered off before
574  // the first auto-save timeout occurs.
575  if (firstSave && credits >= RNG_MAX_CREDITS) {
576  firstSave = 0;
577  save();
578  }
579 }
580 
608 {
609  // Generate random data from the current state and save
610  // that as the seed. Then force a rekey.
611  ++(block[12]);
612  ChaCha::hashCore(stream, block, RNG_ROUNDS);
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)
617  unsigned posn;
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;
623  eraseAndWriteSeed();
624 #endif
625  rekey();
626  timer = millis();
627 }
628 
636 {
637  // Stir in the entropy from all registered noise sources.
638  for (uint8_t posn = 0; posn < count; ++posn)
639  noiseSources[posn]->stir();
640 
641 #if defined(RNG_DUE_TRNG)
642  // If there is data available from the Arudino Due's TRNG, then XOR
643  // it with the state block and increase the entropy credit. We don't
644  // call stir() yet because that will seriously slow down the system
645  // given how fast the TRNG is. Instead we save up the XOR'ed TRNG
646  // data until the next rand() call and then hash it to generate the
647  // desired output.
648  //
649  // The CPU documentation claims that the TRNG output is very good so
650  // this should only make the pool more and more random as time goes on.
651  // However there is a risk that the CPU manufacturer was pressured by
652  // government or intelligence agencies to insert a back door that
653  // generates predictable output. Or the manufacturer was overly
654  // optimistic about their TRNG design and it is actually flawed in a
655  // way they don't realise.
656  //
657  // If you are concerned about such threats, then make sure to mix in
658  // data from other noise sources. By hashing together the TRNG with
659  // the other noise data, rand() should produce unpredictable data even
660  // if one of the sources is actually predictable.
661  if ((REG_TRNG_ISR & TRNG_ISR_DATRDY) != 0) {
662  block[4 + trngPosn] ^= REG_TRNG_ODATA;
663  if (++trngPosn >= 12)
664  trngPosn = 0;
665  if (credits < RNG_MAX_CREDITS) {
666  // Credit 1 bit of entropy for the word. The TRNG should be
667  // better than this but it is so fast that we want to collect
668  // up more data before passing it to the application.
669  ++credits;
670  }
671  }
672 #endif
673 
674  // Save the seed if the auto-save timer has expired.
675  if ((millis() - timer) >= timeout)
676  save();
677 }
678 
699 {
700  clean(block);
701  clean(stream);
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;
708  eraseAndWriteSeed();
709 #endif
710 }
711 
715 void RNGClass::rekey()
716 {
717  // Rekey the cipher for the next request by generating a new block.
718  // This is intended to make it difficult to wind the random number
719  // backwards if the state is captured later. The first 16 bytes of
720  // "block" remain set to "tagRNG".
721  ++(block[12]);
722  ChaCha::hashCore(stream, block, RNG_ROUNDS);
723  memcpy(block + 4, stream, 48);
724 
725  // Permute the high word of the counter using the system microsecond
726  // counter to introduce a little bit of non-stir randomness for each
727  // request. Note: If random data is requested on a predictable schedule
728  // then this may not help very much. It is still necessary to stir in
729  // high quality entropy data on a regular basis using stir().
730  block[13] ^= micros();
731 }
void save()
Saves the random seed to EEPROM.
Definition: RNG.cpp:607
void rand(uint8_t *data, size_t len)
Generates random bytes into a caller-supplied buffer.
Definition: RNG.cpp:428
void begin(const char *tag, int eepromAddress)
Initializes the random number generator.
Definition: RNG.cpp:296
Abstract base class for random noise sources.
Definition: NoiseSource.h:29
~RNGClass()
Destroys this random number generator instance.
Definition: RNG.cpp:196
virtual void added()
Called when the noise source is added to RNG with RNG.addNoiseSource().
Definition: NoiseSource.cpp:95
void addNoiseSource(NoiseSource &source)
Adds a noise source to the random number generator.
Definition: RNG.cpp:379
RNGClass()
Constructs a new random number generator instance.
Definition: RNG.cpp:182
void destroy()
Destroys the data in the random number pool and the saved seed in EEPROM.
Definition: RNG.cpp:698
bool available(size_t len) const
Determine if there is sufficient entropy available for a specific request size.
Definition: RNG.cpp:505
void loop()
Run periodic housekeeping tasks on the random number generator.
Definition: RNG.cpp:635
Pseudo random number generator suitable for cryptography.
Definition: RNG.h:31
static const int SEED_SIZE
Size of a saved random number seed in EEPROM space.
Definition: RNG.h:53
static void hashCore(uint32_t *output, const uint32_t *input, uint8_t rounds)
Executes the ChaCha hash core on an input memory block.
Definition: ChaCha.cpp:253
void stir(const uint8_t *data, size_t len, unsigned int credit=0)
Stirs additional entropy data into the random pool.
Definition: RNG.cpp:538
void setAutoSaveTime(uint16_t minutes)
Sets the amount of time between automatic seed saves.
Definition: RNG.cpp:404