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>
51 #include <sec/entropy/yarrow_pool.h>
53 /********************************************************************************/
54 /* Configuration of the random module */
55 /********************************************************************************/
57 #define POOL_CONTEXT PP_CAT(PP_CAT(POOL_NAMEU, CONFIG_RANDOM_POOL), Context)
58 #define POOL_INIT PP_CAT(PP_CAT(POOL_NAMEL, CONFIG_RANDOM_POOL), _init)
60 #define EXTRACTOR_STACKINIT PP_CAT(PP_CAT(EXTRACTOR_NAME, CONFIG_RANDOM_EXTRACTOR), _stackinit)
62 #define PRNG_CONTEXT PP_CAT(PP_CAT(PRNG_NAMEU, CONFIG_RANDOM_PRNG), Context)
63 #define PRNG_INIT PP_CAT(PP_CAT(PRNG_NAMEL, CONFIG_RANDOM_PRNG), _init)
66 /********************************************************************************/
68 /********************************************************************************/
70 #if CONFIG_RANDOM_POOL != POOL_NONE
71 static POOL_CONTEXT epool_ctx;
72 static EntropyPool * const epool = (EntropyPool *)&epool_ctx;
75 static PRNG_CONTEXT prng_ctx;
76 static PRNG * const prng = (PRNG*)&prng_ctx;
78 static bool initialized = 0;
81 /********************************************************************************/
83 /********************************************************************************/
86 * Reseed the PRNG if there is enough entropy available at this time.
88 * Some designs (eg: fortuna) suggest to artificially limit the frequency of
89 * this operation to something like 0.1s, to avoid attacks that try to exhaust
92 * We don't believe such attacks are available in an embedded system (as an attacker
93 * does not have a way to ask random numbers from the pool) but we will play safe
94 * here in case eg. the user does something wrong.
96 static void optional_reseeding(void)
98 #if CONFIG_RANDOM_POOL != POOL_NONE
99 static ticks_t last_reseed = -1000;
101 // We don't allow more than 10 reseedings per second
102 // (as suggested by Fortuna)
103 ticks_t current = timer_clock();
104 if (ticks_to_ms(current - last_reseed) < 100)
107 if (entropy_seeding_ready(epool))
109 uint8_t seed[prng_seed_len(prng)];
111 entropy_make_seed(epool, seed, sizeof(seed));
112 prng_reseed(prng, seed);
114 last_reseed = current;
122 * Perform the initial seeding of the PRNG.
124 * At startup, we want to immediately seed the PRNG to a point where it can
125 * generate safe-enough random numbers. To do this, we rely on a hw-dependent
126 * function to pull entropy from available hw sources, and then feed it
127 * through an extractor (if any is configured).
129 static void initial_seeding(void)
131 #if CONFIG_RANDOM_POOL != POOL_NONE
133 // We feed entropy into the pool, until it is ready to perform a seeding.
137 random_pull_entropy(buf, sizeof(buf));
138 entropy_add(epool, 0, buf, sizeof(buf), sizeof(buf)*8);
139 } while (!entropy_seeding_ready(epool));
141 optional_reseeding();
143 #elif CONFIG_RANDOM_EXTRACTOR != EXTRACTOR_NONE
145 uint8_t seed[prng_seed_len(prng)];
146 Hash *h = EXTRACTOR_STACKINIT();
148 // "Randomness Extraction and Key Derivation Using the CBC, Cascade and
149 // HMAC Modes" by Yevgeniy Dodis et al. suggests that an padded cascaded hash
150 // function with N bits of output must have at least 2n bits of min-entropy as input
151 // to be a randomness extractor (it generates an output that is computationally
152 // indistiguishable from an uniform distribution).
153 size_t hlen = hash_digest_len(h);
157 while (sidx < sizeof(seed))
159 size_t cnt = MIN(sizeof(seed) - sidx, hlen);
161 random_pull_entropy(buf, sizeof(buf));
164 hash_update(h, buf, sizeof(buf));
165 memcpy(seed+sidx, hash_final(h), cnt);
169 prng_reseed(prng, seed);
175 // If we have been configured without a proper randomness extractor, we do not
176 // have many solutions but feeding the entropy bits directly to the PRNG, and
177 // hoping for the best.
178 uint8_t seed[prng_seed_len(prng)];
179 random_pull_entropy(seed, sizeof(seed));
180 prng_reseed(prng, seed);
186 void random_init(void)
188 #if CONFIG_RANDOM_POOL != POOL_NONE
189 POOL_INIT(&epool_ctx);
191 PRNG_INIT(&prng_ctx);
197 void random_gen(uint8_t *out, size_t len)
201 optional_reseeding();
202 prng_generate(prng, out, len);
205 #if CONFIG_RANDOM_POOL != POOL_NONE
207 void random_add_entropy(enum EntropySource source_idx,
208 const uint8_t *data, size_t len,
211 entropy_add(epool, source_idx, data, len, entropy);