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