4 #include <cfg/macros.h>
6 #include <sec/random.h>
8 #include <sec/entropy.h>
10 #include <sec/hash/sha1.h>
11 #include <sec/prng/isaac.h>
13 /********************************************************************************/
14 /* Configuration of the random module */
15 /********************************************************************************/
17 #define POOL_CONTEXT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_POOL), _Context)
18 #define POOL_INIT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_POOL), _init)
20 #define EXTRACTOR_STACKINIT PP_CAT(PP_CAT(EXTRACTOR_NAME, CONFIG_RANDOM_EXTRACTOR), _stackinit)
22 #define PRNG_CONTEXT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_PRNG), _Context)
23 #define PRNG_INIT PP_CAT(PP_CAT(PRNG_NAME, CONFIG_RANDOM_PRNG), _init)
26 /********************************************************************************/
28 /********************************************************************************/
30 #if CONFIG_RANDOM_POOL != POOL_NONE
31 static POOL_CONTEXT epool_ctx;
32 static EntropyPool_Context * const epool = (EntropyPool_Context *)&epool_ctx;
35 static PRNG_CONTEXT prng_ctx;
36 static PRNG * const prng = (PRNG*)&prng_ctx;
38 static bool initialized = 0;
41 /********************************************************************************/
43 /********************************************************************************/
46 * Reseed the PRNG if there is enough entropy available at this time.
48 * Some designs (eg: fortuna) suggest to artificially limit the frequency of
49 * this operation to something like 0.1s, to avoid attacks that try to exhaust
52 * We don't believe such attacks are available in an embedded system (as an attacker
53 * does not have a way to ask random numbers from the pool) but we will play safe
54 * here in case eg. the user does something wrong.
56 static void optional_reseeding(void)
58 #if CONFIG_RANDOM_POOL != POOL_NONE
59 static ticks_t last_reseed = 0;
61 // We don't allow more than 10 reseedings per second
62 // (as suggested by Fortuna)
63 ticks_t current = timer_clock();
64 if (ticks_to_ms(current - last_reseed) < 100)
67 if (entropy_seeding_ready(epool))
69 uint8_t seed[prng_seed_len(prng)];
71 entropy_make_seed(epool, seed, sizeof(seed));
72 prng_reseed(prng, seed);
74 last_reseed = current;
82 * Perform the initial seeding of the PRNG.
84 * At startup, we want to immediately seed the PRNG to a point where it can
85 * generate safe-enough random numbers. To do this, we rely on a hw-dependent
86 * function to pull entropy from available hw sources, and then feed it
87 * through an extractor (if any is configured).
89 static void initial_seeding(void)
91 #if CONFIG_RANDOM_POOL != POOL_NONE
93 // We feed entropy into the pool, until it is ready to perform a seeding.
97 random_pull_entropy(buf, sizeof(buf));
98 entropy_add(epool, 0, buf, sizeof(buf), sizeof(buf)*8);
99 } while (!entropy_seeding_ready(epool));
101 optional_reseeding();
103 #elif CONFIG_RANDOM_EXTRACTOR != EXTRACTOR_NONE
105 uint8_t seed[prng_seed_len(prng)];
106 Hash *h = EXTRACTOR_STACKINIT();
108 // "Randomness Extraction and Key Derivation Using the CBC, Cascade and
109 // HMAC Modes" by Yevgeniy Dodis et al. suggests that an padded cascaded hash
110 // function with N bits of output must have at least 2n bits of min-entropy as input
111 // to be a randomness extractor (it generates an output that is computationally
112 // indistiguishable from an uniform distribution).
113 size_t hlen = hash_digest_len(h);
117 while (sidx < sizeof(seed))
119 size_t cnt = MIN(sizeof(seed) - sidx, hlen);
121 random_pull_entropy(buf, sizeof(buf));
124 hash_update(h, buf, sizeof(buf));
125 memcpy(seed+sidx, hash_final(h), cnt);
129 prng_reseed(prng, seed);
135 // If we have been configured without a proper randomness extractor, we do not
136 // have many solutions but feeding the entropy bits directly to the PRNG, and
137 // hoping for the best.
138 uint8_t seed[prng_seed_len(prng)];
139 random_pull_entropy(seed, sizeof(seed));
140 prng_reseed(prng, seed);
146 void random_init(void)
148 #if CONFIG_RANDOM_POOL != POOL_NONE
149 POOL_INIT(&epool_ctx);
151 PRNG_INIT(&prng_ctx);
157 void random_gen(uint8_t *out, size_t len)
161 optional_reseeding();
162 prng_generate(prng, out, len);
165 #if CONFIG_RANDOM_POOL != POOL_NONE
167 void random_add_entropy(enum EntropySource source_idx,
168 const uint8_t *data, size_t len,
171 entropy_add(epool, source_idx, data, len, entropy);