BeRTOS
random.c
Go to the documentation of this file.
00001 
00038 #include "random.h"
00039 #include "random_p.h"
00040 
00041 #include <cfg/macros.h>
00042 #include <drv/timer.h>
00043 #include <sec/random.h>
00044 #include <sec/prng.h>
00045 #include <sec/entropy.h>
00046 #include <sec/util.h>
00047 #include <sec/hash/sha1.h>
00048 #include <sec/prng/isaac.h>
00049 #include <sec/prng/x917.h>
00050 #include <sec/prng/yarrow.h>
00051 #include <sec/entropy/yarrow_pool.h>
00052 
00053 /********************************************************************************/
00054 /* Configuration of the random module                                           */
00055 /********************************************************************************/
00056 
00057 #define POOL_CONTEXT          PP_CAT(PP_CAT(POOL_NAMEU, CONFIG_RANDOM_POOL), Context)
00058 #define POOL_INIT             PP_CAT(PP_CAT(POOL_NAMEL, CONFIG_RANDOM_POOL), _init)
00059 
00060 #define EXTRACTOR_STACKINIT   PP_CAT(PP_CAT(EXTRACTOR_NAME, CONFIG_RANDOM_EXTRACTOR), _stackinit)
00061 
00062 #define PRNG_CONTEXT          PP_CAT(PP_CAT(PRNG_NAMEU, CONFIG_RANDOM_PRNG), Context)
00063 #define PRNG_INIT             PP_CAT(PP_CAT(PRNG_NAMEL, CONFIG_RANDOM_PRNG), _init)
00064 
00065 
00066 /********************************************************************************/
00067 /* Global state                                                                 */
00068 /********************************************************************************/
00069 
00070 #if CONFIG_RANDOM_POOL != POOL_NONE
00071 static POOL_CONTEXT epool_ctx;
00072 static EntropyPool * const epool = (EntropyPool *)&epool_ctx;
00073 #endif
00074 
00075 static PRNG_CONTEXT prng_ctx;
00076 static PRNG * const prng = (PRNG*)&prng_ctx;
00077 
00078 static bool initialized = 0;
00079 
00080 
00081 /********************************************************************************/
00082 /* Code                                                                         */
00083 /********************************************************************************/
00084 
00085 /*
00086  * Reseed the PRNG if there is enough entropy available at this time.
00087  *
00088  * Some designs (eg: fortuna) suggest to artificially limit the frequency of
00089  * this operation to something like 0.1s, to avoid attacks that try to exhaust
00090  * the entropy pool.
00091  *
00092  * We don't believe such attacks are available in an embedded system (as an attacker
00093  * does not have a way to ask random numbers from the pool) but we will play safe
00094  * here in case eg. the user does something wrong.
00095  */
00096 static void optional_reseeding(void)
00097 {
00098 #if CONFIG_RANDOM_POOL != POOL_NONE
00099     static ticks_t last_reseed = -1000;
00100 
00101     // We don't allow more than 10 reseedings per second
00102     // (as suggested by Fortuna)
00103     ticks_t current = timer_clock();
00104     if (ticks_to_ms(current - last_reseed) < 100)
00105         return;
00106 
00107     if (entropy_seeding_ready(epool))
00108     {
00109         uint8_t seed[prng_seed_len(prng)];
00110 
00111         entropy_make_seed(epool, seed, sizeof(seed));
00112         prng_reseed(prng, seed);
00113 
00114         last_reseed = current;
00115         PURGE(seed);
00116     }
00117 #endif
00118 }
00119 
00120 
00121 /*
00122  * Perform the initial seeding of the PRNG.
00123  *
00124  * At startup, we want to immediately seed the PRNG to a point where it can
00125  * generate safe-enough random numbers. To do this, we rely on a hw-dependent
00126  * function to pull entropy from available hw sources, and then feed it
00127  * through an extractor (if any is configured).
00128  */
00129 static void initial_seeding(void)
00130 {
00131 #if CONFIG_RANDOM_POOL != POOL_NONE
00132 
00133     // We feed entropy into the pool, until it is ready to perform a seeding.
00134     do
00135     {
00136         uint8_t buf[16];
00137         random_pull_entropy(buf, sizeof(buf));
00138         entropy_add(epool, 0, buf, sizeof(buf), sizeof(buf)*8);
00139     } while (!entropy_seeding_ready(epool));
00140 
00141     optional_reseeding();
00142 
00143 #elif CONFIG_RANDOM_EXTRACTOR != EXTRACTOR_NONE
00144 
00145     uint8_t seed[prng_seed_len(prng)];
00146     Hash *h = EXTRACTOR_STACKINIT();
00147 
00148     // "Randomness Extraction and Key Derivation Using the CBC, Cascade and
00149     // HMAC Modes" by Yevgeniy Dodis et al. suggests that an padded cascaded hash
00150     // function with N bits of output must have at least 2n bits of min-entropy as input
00151     // to be a randomness extractor (it generates an output that is computationally
00152     // indistiguishable from an uniform distribution).
00153     size_t hlen = hash_digest_len(h);
00154     uint8_t buf[hlen*2];
00155     size_t sidx = 0;
00156 
00157     while (sidx < sizeof(seed))
00158     {
00159         size_t cnt = MIN(sizeof(seed) - sidx, hlen);
00160 
00161         random_pull_entropy(buf, sizeof(buf));
00162 
00163         hash_begin(h);
00164         hash_update(h, buf, sizeof(buf));
00165         memcpy(seed+sidx, hash_final(h), cnt);
00166         sidx += cnt;
00167     }
00168 
00169     prng_reseed(prng, seed);
00170     PURGE(buf);
00171     PURGE(seed);
00172 
00173 #else
00174 
00175     // If we have been configured without a proper randomness extractor, we do not
00176     // have many solutions but feeding the entropy bits directly to the PRNG, and
00177     // hoping for the best.
00178     uint8_t seed[prng_seed_len(prng)];
00179     random_pull_entropy(seed, sizeof(seed));
00180     prng_reseed(prng, seed);
00181     PURGE(seed);
00182 
00183 #endif
00184 }
00185 
00186 void random_init(void)
00187 {
00188 #if CONFIG_RANDOM_POOL != POOL_NONE
00189     POOL_INIT(&epool_ctx);
00190 #endif
00191     PRNG_INIT(&prng_ctx);
00192 
00193     initialized = 1;
00194     initial_seeding();
00195 }
00196 
00197 void random_gen(uint8_t *out, size_t len)
00198 {
00199     ASSERT(initialized);
00200 
00201     optional_reseeding();
00202     prng_generate(prng, out, len);
00203 }
00204 
00205 #if CONFIG_RANDOM_POOL != POOL_NONE
00206 
00207 void random_add_entropy(enum EntropySource source_idx,
00208                         const uint8_t *data, size_t len,
00209                         int entropy)
00210 {
00211     entropy_add(epool, source_idx, data, len, entropy);
00212 }
00213 
00214 #endif