random_pool.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /****************************************************************************
  2. * crypto/random_pool.c
  3. *
  4. * Copyright (C) 2015-2017 Haltian Ltd. All rights reserved.
  5. * Authors: Juha Niskanen <juha.niskanen@haltian.com>
  6. * Jussi Kivilinna <jussi.kivilinna@haltian.com>
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. * 3. Neither the name NuttX nor the names of its contributors may be
  19. * used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  25. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  26. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  27. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  28. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  29. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  30. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  32. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  33. * POSSIBILITY OF SUCH DAMAGE.
  34. *
  35. ****************************************************************************/
  36. /****************************************************************************
  37. * Included Files
  38. ****************************************************************************/
  39. #include <nuttx/config.h>
  40. #include <stdint.h>
  41. #include <stdbool.h>
  42. #include <string.h>
  43. #include <unistd.h>
  44. #include <debug.h>
  45. #include <assert.h>
  46. #include <errno.h>
  47. #include <nuttx/arch.h>
  48. #include <nuttx/random.h>
  49. #include <nuttx/board.h>
  50. #include <nuttx/crypto/blake2s.h>
  51. /****************************************************************************
  52. * Definitions
  53. ****************************************************************************/
  54. #ifndef MIN
  55. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  56. #endif
  57. #define ROTL_32(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
  58. #define ROTR_32(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) )
  59. /****************************************************************************
  60. * Private Function Prototypes
  61. ****************************************************************************/
  62. /****************************************************************************
  63. * Private Types
  64. ****************************************************************************/
  65. struct blake2xs_rng_s
  66. {
  67. uint32_t out_node_offset;
  68. blake2s_param param;
  69. blake2s_state ctx;
  70. char out_root[BLAKE2S_OUTBYTES];
  71. };
  72. struct rng_s
  73. {
  74. sem_t rd_sem; /* Threads can only exclusively access the RNG */
  75. volatile uint32_t rd_addptr;
  76. volatile uint32_t rd_newentr;
  77. volatile uint8_t rd_rotate;
  78. volatile uint8_t rd_prev_time;
  79. volatile uint16_t rd_prev_irq;
  80. bool output_initialized;
  81. struct blake2xs_rng_s blake2xs;
  82. };
  83. enum
  84. {
  85. POOL_SIZE = ENTROPY_POOL_SIZE,
  86. POOL_MASK = (POOL_SIZE - 1),
  87. MIN_SEED_NEW_ENTROPY_WORDS = 128,
  88. MAX_SEED_NEW_ENTROPY_WORDS = 1024
  89. };
  90. /****************************************************************************
  91. * Private Data
  92. ****************************************************************************/
  93. static struct rng_s g_rng;
  94. #ifdef CONFIG_BOARD_ENTROPY_POOL
  95. /* Entropy pool structure can be provided by board source. Use for this is,
  96. * for example, allocate entropy pool from special area of RAM which content
  97. * is kept over system reset.
  98. */
  99. # define entropy_pool board_entropy_pool
  100. #else
  101. static struct entropy_pool_s entropy_pool;
  102. #endif
  103. /* Polynomial from paper "The Linux Pseudorandom Number Generator Revisited"
  104. * x^POOL_SIZE + x^104 + x^76 + x^51 + x^25 + x + 1 */
  105. static const uint32_t pool_stir[] = { POOL_SIZE, 104, 76, 51, 25, 1 };
  106. /* Derived from IEEE 802.3 CRC-32 */
  107. static const uint32_t pool_twist[8] =
  108. {
  109. 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
  110. 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
  111. };
  112. /****************************************************************************
  113. * Private Functions
  114. ****************************************************************************/
  115. /****************************************************************************
  116. * Name: addentropy
  117. *
  118. * Description:
  119. *
  120. * This function adds a number of integers into the entropy pool.
  121. * The pool is stirred with a polynomial of degree POOL_SIZE over GF(2).
  122. *
  123. * Code is inspired by add_entropy_words() function of OpenBSD kernel.
  124. *
  125. * Input Parameters:
  126. * buf - Buffer of integers to be added
  127. * n - Number of elements in buf
  128. * inc_new - Count element as new entry
  129. *
  130. * Returned Value:
  131. * None
  132. *
  133. ****************************************************************************/
  134. static void addentropy(FAR const uint32_t *buf, size_t n, bool inc_new)
  135. {
  136. /* Compile time check for that POOL_SIZE is power of two. */
  137. static char pool_size_p2_check[1 - ((POOL_SIZE & (POOL_SIZE - 1)) * 2)];
  138. UNUSED(pool_size_p2_check);
  139. while (n-- > 0)
  140. {
  141. uint32_t rotate;
  142. uint32_t w;
  143. uint32_t i;
  144. rotate = g_rng.rd_rotate;
  145. w = ROTL_32(*buf, rotate);
  146. i = g_rng.rd_addptr = (g_rng.rd_addptr - 1) & POOL_MASK;
  147. /* Normal round, we add 7 bits of rotation to the pool.
  148. * At the beginning of the pool, we add extra 7 bits
  149. * rotation, in order for successive passes spread the
  150. * input bits across the pool evenly.
  151. */
  152. g_rng.rd_rotate = (rotate + (i ? 7 : 14)) & 31;
  153. /* XOR pool contents corresponding to polynomial terms */
  154. w ^= entropy_pool.pool[(i + pool_stir[1]) & POOL_MASK];
  155. w ^= entropy_pool.pool[(i + pool_stir[2]) & POOL_MASK];
  156. w ^= entropy_pool.pool[(i + pool_stir[3]) & POOL_MASK];
  157. w ^= entropy_pool.pool[(i + pool_stir[4]) & POOL_MASK];
  158. w ^= entropy_pool.pool[(i + pool_stir[5]) & POOL_MASK];
  159. w ^= entropy_pool.pool[i]; /* 2^POOL_SIZE */
  160. entropy_pool.pool[i] = (w >> 3) ^ pool_twist[w & 7];
  161. buf++;
  162. if (inc_new)
  163. {
  164. g_rng.rd_newentr += 1;
  165. }
  166. }
  167. }
  168. /****************************************************************************
  169. * Name: getentropy
  170. *
  171. * Description:
  172. * Hash entropy pool to BLAKE2s context. This is an internal interface for
  173. * seeding out-facing BLAKE2Xs random bit generator from entropy pool.
  174. *
  175. * Code is inspired by extract_entropy() function of OpenBSD kernel.
  176. *
  177. * Note that this function cannot fail, other than by asserting.
  178. *
  179. * Warning: In protected kernel builds, this interface MUST NOT be
  180. * exported to userspace. This interface MUST NOT be used as a
  181. * general-purpose random bit generator!
  182. *
  183. * Input Parameters:
  184. * S - BLAKE2s instance that will absorb entropy pool
  185. *
  186. * Returned Value:
  187. * None
  188. *
  189. ****************************************************************************/
  190. static void getentropy(FAR blake2s_state *S)
  191. {
  192. #ifdef CONFIG_SCHED_CPULOAD
  193. struct cpuload_s load;
  194. #endif
  195. uint32_t tmp;
  196. add_sw_randomness(g_rng.rd_newentr);
  197. /* Absorb the entropy pool */
  198. blake2s_update(S, (FAR const uint32_t *)entropy_pool.pool,
  199. sizeof(entropy_pool.pool));
  200. /* Add something back so repeated calls to this function
  201. * return different values.
  202. */
  203. tmp = sizeof(entropy_pool.pool);
  204. tmp <<= 27;
  205. #ifdef CONFIG_SCHED_CPULOAD
  206. clock_cpuload(0, &load);
  207. tmp += load.total ^ ROTL_32(load.active, 23);
  208. #endif
  209. add_sw_randomness(tmp);
  210. g_rng.rd_newentr = 0;
  211. }
  212. /* The BLAKE2Xs based random number generator algorithm.
  213. *
  214. * BLAKE2X is a extensible-output function (XOF) variant of BLAKE2 hash
  215. * function. One application of XOFs is use as deterministic random bit
  216. * number generator (DRBG) as used here. BLAKE2 specification is available
  217. * at https://blake2.net/
  218. *
  219. * BLAKE2Xs here implementation is based on public-domain/CC0 BLAKE2 reference
  220. * implementation by Samual Neves, at
  221. * https://github.com/BLAKE2/BLAKE2/tree/master/ref
  222. * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
  223. */
  224. static void rng_reseed(void)
  225. {
  226. blake2s_param P = {};
  227. /* Reset output node counter. */
  228. g_rng.blake2xs.out_node_offset = 0;
  229. /* Initialize parameter block */
  230. P.digest_length = BLAKE2S_OUTBYTES;
  231. P.key_length = 0;
  232. P.fanout = 1;
  233. P.depth = 1;
  234. blake2_store32(P.leaf_length, 0);
  235. blake2_store32(P.node_offset, 0);
  236. blake2_store16(P.xof_length, 0xffff);
  237. P.node_depth = 0;
  238. P.inner_length = 0;
  239. g_rng.blake2xs.param = P;
  240. blake2s_init_param(&g_rng.blake2xs.ctx, &g_rng.blake2xs.param);
  241. /* Initialize with randomness from entropy pool */
  242. getentropy(&g_rng.blake2xs.ctx);
  243. /* Absorb also the previous root */
  244. blake2s_update(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root,
  245. sizeof(g_rng.blake2xs.out_root));
  246. /* Finalize the new root hash */
  247. blake2s_final(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root,
  248. BLAKE2S_OUTBYTES);
  249. explicit_bzero(&g_rng.blake2xs.ctx, sizeof(g_rng.blake2xs.ctx));
  250. /* Setup parameters for output phase. */
  251. g_rng.blake2xs.param.key_length = 0;
  252. g_rng.blake2xs.param.fanout = 0;
  253. blake2_store32(g_rng.blake2xs.param.leaf_length, BLAKE2S_OUTBYTES);
  254. g_rng.blake2xs.param.inner_length = BLAKE2S_OUTBYTES;
  255. g_rng.blake2xs.param.node_depth = 0;
  256. g_rng.output_initialized = true;
  257. }
  258. static void rng_buf_internal(FAR void *bytes, size_t nbytes)
  259. {
  260. if (!g_rng.output_initialized)
  261. {
  262. if (g_rng.rd_newentr < MIN_SEED_NEW_ENTROPY_WORDS)
  263. {
  264. cryptwarn("Entropy pool RNG initialized with very low entropy. "
  265. " Consider implementing CONFIG_BOARD_INITRNGSEED!\n");
  266. }
  267. rng_reseed();
  268. }
  269. else if (g_rng.rd_newentr >= MAX_SEED_NEW_ENTROPY_WORDS)
  270. {
  271. /* Initial entropy is low. Reseed when we have accumulated more. */
  272. rng_reseed();
  273. }
  274. else if (g_rng.blake2xs.out_node_offset == UINT32_MAX)
  275. {
  276. /* Maximum BLAKE2Xs output reached (2^32-1 output blocks, maximum 128 GiB
  277. * bytes), reseed. */
  278. rng_reseed();
  279. }
  280. /* Output phase for BLAKE2Xs. */
  281. for (; nbytes > 0; ++g_rng.blake2xs.out_node_offset)
  282. {
  283. size_t block_size = MIN(nbytes, BLAKE2S_OUTBYTES);
  284. /* Initialize state */
  285. g_rng.blake2xs.param.digest_length = block_size;
  286. blake2_store32(g_rng.blake2xs.param.node_offset,
  287. g_rng.blake2xs.out_node_offset);
  288. blake2s_init_param(&g_rng.blake2xs.ctx, &g_rng.blake2xs.param);
  289. /* Process state and output random bytes */
  290. blake2s_update(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root,
  291. sizeof(g_rng.blake2xs.out_root));
  292. blake2s_final(&g_rng.blake2xs.ctx, bytes, block_size);
  293. bytes += block_size;
  294. nbytes -= block_size;
  295. }
  296. }
  297. static void rng_init(void)
  298. {
  299. cryptinfo("Initializing RNG\n");
  300. memset(&g_rng, 0, sizeof(struct rng_s));
  301. nxsem_init(&g_rng.rd_sem, 0, 1);
  302. /* We do not initialize output here because this is called
  303. * quite early in boot and there may not be enough entropy.
  304. *
  305. * Board level may define CONFIG_BOARD_INITRNGSEED if it implements
  306. * early random seeding.
  307. */
  308. }
  309. /****************************************************************************
  310. * Public Functions
  311. ****************************************************************************/
  312. /****************************************************************************
  313. * Name: up_rngaddint
  314. *
  315. * Description:
  316. * Add one integer to entropy pool, contributing a specific kind
  317. * of entropy to pool.
  318. *
  319. * Input Parameters:
  320. * kindof - Enumeration constant telling where val came from
  321. * val - Integer to be added
  322. *
  323. * Returned Value:
  324. * None
  325. *
  326. ****************************************************************************/
  327. void up_rngaddint(enum rnd_source_t kindof, int val)
  328. {
  329. uint32_t buf[1];
  330. buf[0] = val;
  331. up_rngaddentropy(kindof, buf, 1);
  332. }
  333. /****************************************************************************
  334. * Name: up_rngaddentropy
  335. *
  336. * Description:
  337. * Add buffer of integers to entropy pool.
  338. *
  339. * Input Parameters:
  340. * kindof - Enumeration constant telling where val came from
  341. * buf - Buffer of integers to be added
  342. * n - Number of elements in buf
  343. *
  344. * Returned Value:
  345. * None
  346. *
  347. ****************************************************************************/
  348. void up_rngaddentropy(enum rnd_source_t kindof, FAR const uint32_t *buf,
  349. size_t n)
  350. {
  351. uint32_t tbuf[1];
  352. struct timespec ts;
  353. bool new_inc = true;
  354. if (kindof == RND_SRC_IRQ && n > 0)
  355. {
  356. /* Ignore interrupt randomness if previous interrupt was from same
  357. * source. */
  358. if (buf[0] == g_rng.rd_prev_irq)
  359. {
  360. return;
  361. }
  362. g_rng.rd_prev_irq = buf[0];
  363. }
  364. /* We don't actually track what kind of entropy we receive,
  365. * just add it all to pool. One exception is interrupt
  366. * and timer randomness, where we limit rate of new pool entry
  367. * counting to prevent high interrupt rate triggering RNG
  368. * reseeding too fast.
  369. */
  370. (void)clock_gettime(CLOCK_REALTIME, &ts);
  371. tbuf[0] = ROTL_32(ts.tv_nsec, 17) ^ ROTL_32(ts.tv_sec, 3);
  372. tbuf[0] += ROTL_32(kindof, 27);
  373. tbuf[0] += ROTL_32((uintptr_t)&tbuf[0], 11);
  374. if (kindof == RND_SRC_TIME || kindof == RND_SRC_IRQ)
  375. {
  376. uint8_t curr_time = ts.tv_sec * 8 + ts.tv_nsec / (NSEC_PER_SEC / 8);
  377. /* Allow interrupts/timers increase entropy counter at max rate
  378. * of 8 Hz. */
  379. if (g_rng.rd_prev_time == curr_time)
  380. {
  381. new_inc = false;
  382. }
  383. else
  384. {
  385. g_rng.rd_prev_time = curr_time;
  386. }
  387. }
  388. if (n > 0)
  389. {
  390. tbuf[0] ^= buf[0];
  391. buf++;
  392. n--;
  393. }
  394. addentropy(tbuf, 1, new_inc);
  395. if (n > 0)
  396. {
  397. addentropy(buf, n, new_inc);
  398. }
  399. }
  400. /****************************************************************************
  401. * Name: up_rngreseed
  402. *
  403. * Description:
  404. * Force reseeding random number generator from entropy pool
  405. *
  406. ****************************************************************************/
  407. void up_rngreseed(void)
  408. {
  409. int ret;
  410. do
  411. {
  412. /* Take the semaphore (perhaps waiting) */
  413. ret = nxsem_wait(&g_rng.rd_sem);
  414. /* The only case that an error should occur here is if the wait was
  415. * awakened by a signal.
  416. */
  417. DEBUGASSERT(ret == OK || ret == -EINTR);
  418. }
  419. while (ret == -EINTR);
  420. if (g_rng.rd_newentr >= MIN_SEED_NEW_ENTROPY_WORDS)
  421. {
  422. rng_reseed();
  423. }
  424. nxsem_post(&g_rng.rd_sem);
  425. }
  426. /****************************************************************************
  427. * Name: up_randompool_initialize
  428. *
  429. * Description:
  430. * Initialize entropy pool and random number generator
  431. *
  432. ****************************************************************************/
  433. void up_randompool_initialize(void)
  434. {
  435. rng_init();
  436. #ifdef CONFIG_BOARD_INITRNGSEED
  437. board_init_rngseed();
  438. #endif
  439. }
  440. /****************************************************************************
  441. * Name: getrandom
  442. *
  443. * Description:
  444. * Fill a buffer of arbitrary length with randomness. This is the
  445. * preferred interface for getting random numbers. The traditional
  446. * /dev/random approach is susceptible for things like the attacker
  447. * exhausting file descriptors on purpose.
  448. *
  449. * Note that this function cannot fail, other than by asserting.
  450. *
  451. * Input Parameters:
  452. * bytes - Buffer for returned random bytes
  453. * nbytes - Number of bytes requested.
  454. *
  455. * Returned Value:
  456. * None
  457. *
  458. ****************************************************************************/
  459. void getrandom(FAR void *bytes, size_t nbytes)
  460. {
  461. int ret;
  462. do
  463. {
  464. /* Take the semaphore (perhaps waiting) */
  465. ret = nxsem_wait(&g_rng.rd_sem);
  466. /* The only case that an error should occur here is if the wait was
  467. * awakened by a signal.
  468. */
  469. DEBUGASSERT(ret == OK || ret == -EINTR);
  470. }
  471. while (ret == -EINTR);
  472. rng_buf_internal(bytes, nbytes);
  473. nxsem_post(&g_rng.rd_sem);
  474. }