BeRTOS
yarrow_pool.c
Go to the documentation of this file.
00001 
00038 #include "yarrow_pool.h"
00039 #include <cfg/macros.h>
00040 #include <sec/hash/sha1.h>
00041 #include <sec/util.h>
00042 #include <string.h>
00043 
00044 #define CONFIG_YARROW_POOL_FAST_RESEEDING_THRESHOLD   100
00045 #define CONFIG_YARROW_POOL_SLOW_RESEEDING_THRESHOLD   160
00046 #define CONFIG_YARROW_POOL_MAX_ENTROPY_DENSITY        50   // percent
00047 #define CONFIG_YARROW_POOL_RESEED_ITERATIONS          80
00048 
00049 static void yarrow_fast_reseed(YarrowPoolContext *ctx, uint8_t *out, size_t len)
00050 {
00051     Hash *h = &ctx->pools[0].hash.h;
00052     size_t hlen = hash_digest_len(h);
00053 
00054     uint8_t v0[hlen];
00055     memcpy(v0, hash_final(h), hlen);
00056 
00057     uint8_t vcur[hlen];
00058     memcpy(vcur, v0, hlen);
00059 
00060     for (uint32_t i=1;i<=CONFIG_YARROW_POOL_RESEED_ITERATIONS; ++i) {
00061         hash_begin(h);
00062         hash_update(h, vcur, hlen);
00063         hash_update(h, v0, hlen);
00064         hash_update(h, &i, 4);
00065         memcpy(vcur, hash_final(h), hlen);
00066     }
00067 
00068 
00069     // FIXME: yarrow explains how to expand the hash digest if it's
00070     // smaller than the output size. This is not the case for now,
00071     // so we it's not implemented here.
00072     ASSERT(len < hlen);
00073     memcpy(out, vcur, len);
00074 
00075     // Reinitialize the fast pool
00076     hash_begin(h);
00077     for (int i=0; i<CONFIG_ENTROPY_NUM_SOURCES; ++i)
00078         ctx->pools[0].entropy[i] = 0;
00079 
00080     PURGE(v0);
00081     PURGE(vcur);
00082 }
00083 
00084 static void yarrow_slow_reseed(YarrowPoolContext *ctx, uint8_t *out, size_t len)
00085 {
00086     uint8_t *data = hash_final(&ctx->pools[1].hash.h);
00087 
00088     hash_update(&ctx->pools[0].hash.h, data, hash_digest_len(&ctx->pools[1].hash.h));
00089     yarrow_fast_reseed(ctx, out, len);
00090 
00091     // Reinitialize the slow pool
00092     hash_begin(&ctx->pools[1].hash.h);
00093     for (int i=0; i<CONFIG_ENTROPY_NUM_SOURCES; ++i)
00094         ctx->pools[1].entropy[i] = 0;
00095 }
00096 
00097 static void yarrow_add_entropy(EntropyPool *ctx_, int source_idx, const uint8_t *data, size_t len, int entropy)
00098 {
00099     YarrowPoolContext *ctx = (YarrowPoolContext *)ctx_;
00100 
00101     ASSERT(source_idx < CONFIG_ENTROPY_NUM_SOURCES);
00102 
00103     int curpool = ctx->sources[source_idx].curpool;
00104     ctx->sources[source_idx].curpool = 1 - ctx->sources[source_idx].curpool;
00105 
00106     // TODO: Yarrow also describes a statistical entropy estimator
00107     // Currently, we just use the provided entropy and the maximum
00108     // density.
00109     entropy = MIN((size_t)entropy, len*8*100/CONFIG_YARROW_POOL_MAX_ENTROPY_DENSITY);
00110 
00111     hash_update(&ctx->pools[curpool].hash.h, data, len);
00112     ctx->pools[curpool].entropy[source_idx] += entropy;
00113 }
00114 
00115 static bool yarrow_fast_reseeding_ready(YarrowPoolContext *ctx)
00116 {
00117     for (int i=0; i<CONFIG_ENTROPY_NUM_SOURCES; ++i)
00118         if (ctx->pools[0].entropy[i] >=
00119                 CONFIG_YARROW_POOL_FAST_RESEEDING_THRESHOLD)
00120             return 1;
00121     return 0;
00122 }
00123 
00124 static bool yarrow_slow_reseeding_ready(YarrowPoolContext *ctx)
00125 {
00126     int count = 0;
00127 
00128     for (int i=0; i<CONFIG_ENTROPY_NUM_SOURCES; ++i)
00129         if (ctx->pools[1].entropy[i] >=
00130                 CONFIG_YARROW_POOL_SLOW_RESEEDING_THRESHOLD) {
00131             ++count;
00132             if (count == 2)
00133                 return 1;
00134         }
00135 
00136     return 0;
00137 }
00138 
00139 static bool yarrow_reseeding_ready(EntropyPool *ctx_)
00140 {
00141     YarrowPoolContext *ctx = (YarrowPoolContext *)ctx_;
00142     return yarrow_fast_reseeding_ready(ctx) || yarrow_slow_reseeding_ready(ctx);
00143 }
00144 
00145 static void yarrow_reseed(EntropyPool *ctx_, uint8_t *out, size_t len)
00146 {
00147     YarrowPoolContext *ctx = (YarrowPoolContext *)ctx_;
00148 
00149     if (yarrow_slow_reseeding_ready(ctx))
00150         yarrow_slow_reseed(ctx, out, len);
00151     else {
00152         ASSERT(yarrow_fast_reseeding_ready(ctx));
00153         yarrow_fast_reseed(ctx, out, len);
00154     }
00155 }
00156 
00157 /**********************************************************************/
00158 
00159 void yarrowpool_init(YarrowPoolContext *ctx)
00160 {
00161     ctx->e.add_entropy = yarrow_add_entropy;
00162     ctx->e.seeding_ready = yarrow_reseeding_ready;
00163     ctx->e.make_seed = yarrow_reseed;
00164 
00165     for (int i=0; i<2; ++i) {
00166         memset(ctx->pools[i].entropy, 0, sizeof(ctx->pools[i].entropy));
00167         SHA1_init(&ctx->pools[i].hash);
00168         hash_begin(&ctx->pools[i].hash.h);
00169     }
00170 
00171     memset(ctx->sources, 0, sizeof(ctx->sources));
00172 }