4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
33 * \brief High-level random number generation functions.
34 * \author Giovanni Bajo <rasky@develer.com>
41 #include <cfg/macros.h>
42 #include <drv/timer.h>
43 #include <sec/random.h>
45 #include <sec/entropy.h>
47 #include <sec/hash/sha1.h>
48 #include <sec/prng/isaac.h>
49 #include <sec/prng/x917.h>
50 #include <sec/prng/yarrow.h>
52 /********************************************************************************/
53 /* Configuration of the random module */
54 /********************************************************************************/
56 #define POOL_CONTEXT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_POOL), Context)
57 #define POOL_INIT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_POOL), _init)
59 #define EXTRACTOR_STACKINIT PP_CAT(PP_CAT(EXTRACTOR_NAME, CONFIG_RANDOM_EXTRACTOR), _stackinit)
61 #define PRNG_CONTEXT PP_CAT(PP_CAT(PRNG_NAMEU, CONFIG_RANDOM_PRNG), Context)
62 #define PRNG_INIT PP_CAT(PP_CAT(PRNG_NAMEL, CONFIG_RANDOM_PRNG), _init)
65 /********************************************************************************/
67 /********************************************************************************/
69 #if CONFIG_RANDOM_POOL != POOL_NONE
70 static POOL_CONTEXT epool_ctx;
71 static EntropyPool_Context * const epool = (EntropyPool_Context *)&epool_ctx;
74 static PRNG_CONTEXT prng_ctx;
75 static PRNG * const prng = (PRNG*)&prng_ctx;
77 static bool initialized = 0;
80 /********************************************************************************/
82 /********************************************************************************/
85 * Reseed the PRNG if there is enough entropy available at this time.
87 * Some designs (eg: fortuna) suggest to artificially limit the frequency of
88 * this operation to something like 0.1s, to avoid attacks that try to exhaust
91 * We don't believe such attacks are available in an embedded system (as an attacker
92 * does not have a way to ask random numbers from the pool) but we will play safe
93 * here in case eg. the user does something wrong.
95 static void optional_reseeding(void)
97 #if CONFIG_RANDOM_POOL != POOL_NONE
98 static ticks_t last_reseed = 0;
100 // We don't allow more than 10 reseedings per second
101 // (as suggested by Fortuna)
102 ticks_t current = timer_clock();
103 if (ticks_to_ms(current - last_reseed) < 100)
106 if (entropy_seeding_ready(epool))
108 uint8_t seed[prng_seed_len(prng)];
110 entropy_make_seed(epool, seed, sizeof(seed));
111 prng_reseed(prng, seed);
113 last_reseed = current;
121 * Perform the initial seeding of the PRNG.
123 * At startup, we want to immediately seed the PRNG to a point where it can
124 * generate safe-enough random numbers. To do this, we rely on a hw-dependent
125 * function to pull entropy from available hw sources, and then feed it
126 * through an extractor (if any is configured).
128 static void initial_seeding(void)
130 #if CONFIG_RANDOM_POOL != POOL_NONE
132 // We feed entropy into the pool, until it is ready to perform a seeding.
136 random_pull_entropy(buf, sizeof(buf));
137 entropy_add(epool, 0, buf, sizeof(buf), sizeof(buf)*8);
138 } while (!entropy_seeding_ready(epool));
140 optional_reseeding();
142 #elif CONFIG_RANDOM_EXTRACTOR != EXTRACTOR_NONE
144 uint8_t seed[prng_seed_len(prng)];
145 Hash *h = EXTRACTOR_STACKINIT();
147 // "Randomness Extraction and Key Derivation Using the CBC, Cascade and
148 // HMAC Modes" by Yevgeniy Dodis et al. suggests that an padded cascaded hash
149 // function with N bits of output must have at least 2n bits of min-entropy as input
150 // to be a randomness extractor (it generates an output that is computationally
151 // indistiguishable from an uniform distribution).
152 size_t hlen = hash_digest_len(h);
156 while (sidx < sizeof(seed))
158 size_t cnt = MIN(sizeof(seed) - sidx, hlen);
160 random_pull_entropy(buf, sizeof(buf));
163 hash_update(h, buf, sizeof(buf));
164 memcpy(seed+sidx, hash_final(h), cnt);
168 prng_reseed(prng, seed);
174 // If we have been configured without a proper randomness extractor, we do not
175 // have many solutions but feeding the entropy bits directly to the PRNG, and
176 // hoping for the best.
177 uint8_t seed[prng_seed_len(prng)];
178 random_pull_entropy(seed, sizeof(seed));
179 prng_reseed(prng, seed);
185 void random_init(void)
187 #if CONFIG_RANDOM_POOL != POOL_NONE
188 POOL_INIT(&epool_ctx);
190 PRNG_INIT(&prng_ctx);
196 void random_gen(uint8_t *out, size_t len)
200 optional_reseeding();
201 prng_generate(prng, out, len);
204 #if CONFIG_RANDOM_POOL != POOL_NONE
206 void random_add_entropy(enum EntropySource source_idx,
207 const uint8_t *data, size_t len,
210 entropy_add(epool, source_idx, data, len, entropy);