BeRTOS
|
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