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>
50 /********************************************************************************/
51 /* Configuration of the random module */
52 /********************************************************************************/
54 #define POOL_CONTEXT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_POOL), _Context)
55 #define POOL_INIT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_POOL), _init)
57 #define EXTRACTOR_STACKINIT PP_CAT(PP_CAT(EXTRACTOR_NAME, CONFIG_RANDOM_EXTRACTOR), _stackinit)
59 #define PRNG_CONTEXT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_PRNG), _Context)
60 #define PRNG_INIT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_PRNG), _init)
63 /********************************************************************************/
65 /********************************************************************************/
67 #if CONFIG_RANDOM_POOL != POOL_NONE
68 static POOL_CONTEXT epool_ctx;
69 static EntropyPool_Context * const epool = (EntropyPool_Context *)&epool_ctx;
72 static PRNG_CONTEXT prng_ctx;
73 static PRNG * const prng = (PRNG*)&prng_ctx;
75 static bool initialized = 0;
78 /********************************************************************************/
80 /********************************************************************************/
83 * Reseed the PRNG if there is enough entropy available at this time.
85 * Some designs (eg: fortuna) suggest to artificially limit the frequency of
86 * this operation to something like 0.1s, to avoid attacks that try to exhaust
89 * We don't believe such attacks are available in an embedded system (as an attacker
90 * does not have a way to ask random numbers from the pool) but we will play safe
91 * here in case eg. the user does something wrong.
93 static void optional_reseeding(void)
95 #if CONFIG_RANDOM_POOL != POOL_NONE
96 static ticks_t last_reseed = 0;
98 // We don't allow more than 10 reseedings per second
99 // (as suggested by Fortuna)
100 ticks_t current = timer_clock();
101 if (ticks_to_ms(current - last_reseed) < 100)
104 if (entropy_seeding_ready(epool))
106 uint8_t seed[prng_seed_len(prng)];
108 entropy_make_seed(epool, seed, sizeof(seed));
109 prng_reseed(prng, seed);
111 last_reseed = current;
119 * Perform the initial seeding of the PRNG.
121 * At startup, we want to immediately seed the PRNG to a point where it can
122 * generate safe-enough random numbers. To do this, we rely on a hw-dependent
123 * function to pull entropy from available hw sources, and then feed it
124 * through an extractor (if any is configured).
126 static void initial_seeding(void)
128 #if CONFIG_RANDOM_POOL != POOL_NONE
130 // We feed entropy into the pool, until it is ready to perform a seeding.
134 random_pull_entropy(buf, sizeof(buf));
135 entropy_add(epool, 0, buf, sizeof(buf), sizeof(buf)*8);
136 } while (!entropy_seeding_ready(epool));
138 optional_reseeding();
140 #elif CONFIG_RANDOM_EXTRACTOR != EXTRACTOR_NONE
142 uint8_t seed[prng_seed_len(prng)];
143 Hash *h = EXTRACTOR_STACKINIT();
145 // "Randomness Extraction and Key Derivation Using the CBC, Cascade and
146 // HMAC Modes" by Yevgeniy Dodis et al. suggests that an padded cascaded hash
147 // function with N bits of output must have at least 2n bits of min-entropy as input
148 // to be a randomness extractor (it generates an output that is computationally
149 // indistiguishable from an uniform distribution).
150 size_t hlen = hash_digest_len(h);
154 while (sidx < sizeof(seed))
156 size_t cnt = MIN(sizeof(seed) - sidx, hlen);
158 random_pull_entropy(buf, sizeof(buf));
161 hash_update(h, buf, sizeof(buf));
162 memcpy(seed+sidx, hash_final(h), cnt);
166 prng_reseed(prng, seed);
172 // If we have been configured without a proper randomness extractor, we do not
173 // have many solutions but feeding the entropy bits directly to the PRNG, and
174 // hoping for the best.
175 uint8_t seed[prng_seed_len(prng)];
176 random_pull_entropy(seed, sizeof(seed));
177 prng_reseed(prng, seed);
183 void random_init(void)
185 #if CONFIG_RANDOM_POOL != POOL_NONE
186 POOL_INIT(&epool_ctx);
188 PRNG_INIT(&prng_ctx);
194 void random_gen(uint8_t *out, size_t len)
198 optional_reseeding();
199 prng_generate(prng, out, len);
202 #if CONFIG_RANDOM_POOL != POOL_NONE
204 void random_add_entropy(enum EntropySource source_idx,
205 const uint8_t *data, size_t len,
208 entropy_add(epool, source_idx, data, len, entropy);