00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "postgres.h"
00033
00034 #include <sys/time.h>
00035 #include <time.h>
00036
00037 #include "rijndael.h"
00038 #include "sha2.h"
00039 #include "fortuna.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 #define NUM_POOLS 23
00090
00091
00092 #define RESEED_INTERVAL 100000
00093
00094
00095 #define RESEED_BYTES (1024*1024)
00096
00097
00098
00099
00100
00101 #define POOL0_FILL (256/8)
00102
00103
00104
00105
00106
00107
00108 #define BLOCK 32
00109
00110
00111 #define CIPH_BLOCK 16
00112
00113
00114 #define MD_CTX SHA256_CTX
00115 #define CIPH_CTX rijndael_ctx
00116
00117 struct fortuna_state
00118 {
00119 uint8 counter[CIPH_BLOCK];
00120 uint8 result[CIPH_BLOCK];
00121 uint8 key[BLOCK];
00122 MD_CTX pool[NUM_POOLS];
00123 CIPH_CTX ciph;
00124 unsigned reseed_count;
00125 struct timeval last_reseed_time;
00126 unsigned pool0_bytes;
00127 unsigned rnd_pos;
00128 int tricks_done;
00129 };
00130 typedef struct fortuna_state FState;
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 static void
00142 ciph_init(CIPH_CTX * ctx, const uint8 *key, int klen)
00143 {
00144 rijndael_set_key(ctx, (const uint32 *) key, klen, 1);
00145 }
00146
00147 static void
00148 ciph_encrypt(CIPH_CTX * ctx, const uint8 *in, uint8 *out)
00149 {
00150 rijndael_encrypt(ctx, (const uint32 *) in, (uint32 *) out);
00151 }
00152
00153 static void
00154 md_init(MD_CTX * ctx)
00155 {
00156 SHA256_Init(ctx);
00157 }
00158
00159 static void
00160 md_update(MD_CTX * ctx, const uint8 *data, int len)
00161 {
00162 SHA256_Update(ctx, data, len);
00163 }
00164
00165 static void
00166 md_result(MD_CTX * ctx, uint8 *dst)
00167 {
00168 SHA256_CTX tmp;
00169
00170 memcpy(&tmp, ctx, sizeof(*ctx));
00171 SHA256_Final(dst, &tmp);
00172 memset(&tmp, 0, sizeof(tmp));
00173 }
00174
00175
00176
00177
00178 static void
00179 init_state(FState *st)
00180 {
00181 int i;
00182
00183 memset(st, 0, sizeof(*st));
00184 for (i = 0; i < NUM_POOLS; i++)
00185 md_init(&st->pool[i]);
00186 }
00187
00188
00189
00190
00191
00192 static void
00193 inc_counter(FState *st)
00194 {
00195 uint32 *val = (uint32 *) st->counter;
00196
00197 if (++val[0])
00198 return;
00199 if (++val[1])
00200 return;
00201 if (++val[2])
00202 return;
00203 ++val[3];
00204 }
00205
00206
00207
00208
00209 static void
00210 encrypt_counter(FState *st, uint8 *dst)
00211 {
00212 ciph_encrypt(&st->ciph, st->counter, dst);
00213 inc_counter(st);
00214 }
00215
00216
00217
00218
00219
00220
00221 static int
00222 enough_time_passed(FState *st)
00223 {
00224 int ok;
00225 struct timeval tv;
00226 struct timeval *last = &st->last_reseed_time;
00227
00228 gettimeofday(&tv, NULL);
00229
00230
00231 ok = 0;
00232 if (tv.tv_sec > last->tv_sec + 1)
00233 ok = 1;
00234 else if (tv.tv_sec == last->tv_sec + 1)
00235 {
00236 if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
00237 ok = 1;
00238 }
00239 else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
00240 ok = 1;
00241
00242
00243 if (ok)
00244 memcpy(last, &tv, sizeof(tv));
00245
00246 memset(&tv, 0, sizeof(tv));
00247
00248 return ok;
00249 }
00250
00251
00252
00253
00254 static void
00255 reseed(FState *st)
00256 {
00257 unsigned k;
00258 unsigned n;
00259 MD_CTX key_md;
00260 uint8 buf[BLOCK];
00261
00262
00263 st->pool0_bytes = 0;
00264
00265
00266
00267
00268 n = ++st->reseed_count;
00269
00270
00271
00272
00273 md_init(&key_md);
00274 for (k = 0; k < NUM_POOLS; k++)
00275 {
00276 md_result(&st->pool[k], buf);
00277 md_update(&key_md, buf, BLOCK);
00278
00279 if (n & 1 || !n)
00280 break;
00281 n >>= 1;
00282 }
00283
00284
00285 md_update(&key_md, st->key, BLOCK);
00286
00287
00288 md_result(&key_md, st->key);
00289
00290
00291 ciph_init(&st->ciph, st->key, BLOCK);
00292
00293 memset(&key_md, 0, sizeof(key_md));
00294 memset(buf, 0, BLOCK);
00295 }
00296
00297
00298
00299
00300 static unsigned
00301 get_rand_pool(FState *st)
00302 {
00303 unsigned rnd;
00304
00305
00306
00307
00308 rnd = st->key[st->rnd_pos] % NUM_POOLS;
00309
00310 st->rnd_pos++;
00311 if (st->rnd_pos >= BLOCK)
00312 st->rnd_pos = 0;
00313
00314 return rnd;
00315 }
00316
00317
00318
00319
00320 static void
00321 add_entropy(FState *st, const uint8 *data, unsigned len)
00322 {
00323 unsigned pos;
00324 uint8 hash[BLOCK];
00325 MD_CTX md;
00326
00327
00328 md_init(&md);
00329 md_update(&md, data, len);
00330 md_result(&md, hash);
00331
00332
00333
00334
00335 if (st->reseed_count == 0)
00336 pos = 0;
00337 else
00338 pos = get_rand_pool(st);
00339 md_update(&st->pool[pos], hash, BLOCK);
00340
00341 if (pos == 0)
00342 st->pool0_bytes += len;
00343
00344 memset(hash, 0, BLOCK);
00345 memset(&md, 0, sizeof(md));
00346 }
00347
00348
00349
00350
00351 static void
00352 rekey(FState *st)
00353 {
00354 encrypt_counter(st, st->key);
00355 encrypt_counter(st, st->key + CIPH_BLOCK);
00356 ciph_init(&st->ciph, st->key, BLOCK);
00357 }
00358
00359
00360
00361
00362
00363
00364
00365 static void
00366 startup_tricks(FState *st)
00367 {
00368 int i;
00369 uint8 buf[BLOCK];
00370
00371
00372 encrypt_counter(st, st->counter);
00373
00374
00375 for (i = 1; i < NUM_POOLS; i++)
00376 {
00377 encrypt_counter(st, buf);
00378 encrypt_counter(st, buf + CIPH_BLOCK);
00379 md_update(&st->pool[i], buf, BLOCK);
00380 }
00381 memset(buf, 0, BLOCK);
00382
00383
00384 rekey(st);
00385
00386
00387 st->tricks_done = 1;
00388 }
00389
00390 static void
00391 extract_data(FState *st, unsigned count, uint8 *dst)
00392 {
00393 unsigned n;
00394 unsigned block_nr = 0;
00395
00396
00397 if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0)
00398 if (enough_time_passed(st))
00399 reseed(st);
00400
00401
00402 if (!st->tricks_done)
00403 startup_tricks(st);
00404
00405 while (count > 0)
00406 {
00407
00408 encrypt_counter(st, st->result);
00409
00410
00411 if (count > CIPH_BLOCK)
00412 n = CIPH_BLOCK;
00413 else
00414 n = count;
00415 memcpy(dst, st->result, n);
00416 dst += n;
00417 count -= n;
00418
00419
00420 block_nr++;
00421 if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
00422 {
00423 rekey(st);
00424 block_nr = 0;
00425 }
00426 }
00427
00428 rekey(st);
00429 }
00430
00431
00432
00433
00434
00435 static FState main_state;
00436 static int init_done = 0;
00437
00438 void
00439 fortuna_add_entropy(const uint8 *data, unsigned len)
00440 {
00441 if (!init_done)
00442 {
00443 init_state(&main_state);
00444 init_done = 1;
00445 }
00446 if (!data || !len)
00447 return;
00448 add_entropy(&main_state, data, len);
00449 }
00450
00451 void
00452 fortuna_get_bytes(unsigned len, uint8 *dst)
00453 {
00454 if (!init_done)
00455 {
00456 init_state(&main_state);
00457 init_done = 1;
00458 }
00459 if (!dst || !len)
00460 return;
00461 extract_data(&main_state, len, dst);
00462 }