rand-fortuna.c revision 1.1.1.1
1258945Sroberto/* $NetBSD: rand-fortuna.c,v 1.1.1.1 2011/04/13 18:14:50 elric Exp $ */ 2258945Sroberto 3258945Sroberto/* 4258945Sroberto * fortuna.c 5258945Sroberto * Fortuna-like PRNG. 6258945Sroberto * 7258945Sroberto * Copyright (c) 2005 Marko Kreen 8258945Sroberto * All rights reserved. 9258945Sroberto * 10258945Sroberto * Redistribution and use in source and binary forms, with or without 11258945Sroberto * modification, are permitted provided that the following conditions 12258945Sroberto * are met: 13258945Sroberto * 1. Redistributions of source code must retain the above copyright 14258945Sroberto * notice, this list of conditions and the following disclaimer. 15258945Sroberto * 2. Redistributions in binary form must reproduce the above copyright 16258945Sroberto * notice, this list of conditions and the following disclaimer in the 17258945Sroberto * documentation and/or other materials provided with the distribution. 18258945Sroberto * 19258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20258945Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21258945Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22258945Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23258945Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24258945Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25258945Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26258945Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27258945Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28258945Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29258945Sroberto * SUCH DAMAGE. 30258945Sroberto * 31258945Sroberto * $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.8 2006/10/04 00:29:46 momjian Exp $ 32258945Sroberto */ 33258945Sroberto 34258945Sroberto#include <config.h> 35258945Sroberto 36258945Sroberto#include <stdio.h> 37258945Sroberto#include <stdlib.h> 38258945Sroberto#include <rand.h> 39258945Sroberto#include <heim_threads.h> 40258945Sroberto 41258945Sroberto#ifdef KRB5 42258945Sroberto#include <krb5/krb5-types.h> 43258945Sroberto#endif 44258945Sroberto#include <krb5/roken.h> 45258945Sroberto 46258945Sroberto#include "randi.h" 47258945Sroberto#include "aes.h" 48258945Sroberto#include "sha.h" 49258945Sroberto 50258945Sroberto/* 51258945Sroberto * Why Fortuna-like: There does not seem to be any definitive reference 52258945Sroberto * on Fortuna in the net. Instead this implementation is based on 53258945Sroberto * following references: 54258945Sroberto * 55258945Sroberto * http://en.wikipedia.org/wiki/Fortuna_(PRNG) 56258945Sroberto * - Wikipedia article 57258945Sroberto * http://jlcooke.ca/random/ 58258945Sroberto * - Jean-Luc Cooke Fortuna-based /dev/random driver for Linux. 59258945Sroberto */ 60258945Sroberto 61258945Sroberto/* 62258945Sroberto * There is some confusion about whether and how to carry forward 63258945Sroberto * the state of the pools. Seems like original Fortuna does not 64258945Sroberto * do it, resetting hash after each request. I guess expecting 65258945Sroberto * feeding to happen more often that requesting. This is absolutely 66258945Sroberto * unsuitable for pgcrypto, as nothing asynchronous happens here. 67258945Sroberto * 68258945Sroberto * J.L. Cooke fixed this by feeding previous hash to new re-initialized 69258945Sroberto * hash context. 70258945Sroberto * 71258945Sroberto * Fortuna predecessor Yarrow requires ability to query intermediate 72258945Sroberto * 'final result' from hash, without affecting it. 73258945Sroberto * 74258945Sroberto * This implementation uses the Yarrow method - asking intermediate 75258945Sroberto * results, but continuing with old state. 76258945Sroberto */ 77258945Sroberto 78258945Sroberto 79258945Sroberto/* 80258945Sroberto * Algorithm parameters 81258945Sroberto */ 82258945Sroberto 83258945Sroberto#define NUM_POOLS 32 84258945Sroberto 85258945Sroberto/* in microseconds */ 86258945Sroberto#define RESEED_INTERVAL 100000 /* 0.1 sec */ 87258945Sroberto 88258945Sroberto/* for one big request, reseed after this many bytes */ 89258945Sroberto#define RESEED_BYTES (1024*1024) 90258945Sroberto 91258945Sroberto/* 92258945Sroberto * Skip reseed if pool 0 has less than this many 93258945Sroberto * bytes added since last reseed. 94258945Sroberto */ 95258945Sroberto#define POOL0_FILL (256/8) 96258945Sroberto 97258945Sroberto/* 98258945Sroberto * Algorithm constants 99258945Sroberto */ 100258945Sroberto 101258945Sroberto/* Both cipher key size and hash result size */ 102258945Sroberto#define BLOCK 32 103258945Sroberto 104258945Sroberto/* cipher block size */ 105258945Sroberto#define CIPH_BLOCK 16 106258945Sroberto 107258945Sroberto/* for internal wrappers */ 108258945Sroberto#define MD_CTX SHA256_CTX 109258945Sroberto#define CIPH_CTX AES_KEY 110258945Sroberto 111258945Srobertostruct fortuna_state 112258945Sroberto{ 113258945Sroberto unsigned char counter[CIPH_BLOCK]; 114258945Sroberto unsigned char result[CIPH_BLOCK]; 115258945Sroberto unsigned char key[BLOCK]; 116258945Sroberto MD_CTX pool[NUM_POOLS]; 117258945Sroberto CIPH_CTX ciph; 118258945Sroberto unsigned reseed_count; 119258945Sroberto struct timeval last_reseed_time; 120258945Sroberto unsigned pool0_bytes; 121258945Sroberto unsigned rnd_pos; 122258945Sroberto int tricks_done; 123258945Sroberto pid_t pid; 124258945Sroberto}; 125258945Srobertotypedef struct fortuna_state FState; 126258945Sroberto 127258945Sroberto 128258945Sroberto/* 129258945Sroberto * Use our own wrappers here. 130258945Sroberto * - Need to get intermediate result from digest, without affecting it. 131258945Sroberto * - Need re-set key on a cipher context. 132258945Sroberto * - Algorithms are guaranteed to exist. 133258945Sroberto * - No memory allocations. 134258945Sroberto */ 135258945Sroberto 136258945Srobertostatic void 137258945Srobertociph_init(CIPH_CTX * ctx, const unsigned char *key, int klen) 138258945Sroberto{ 139258945Sroberto AES_set_encrypt_key(key, klen * 8, ctx); 140258945Sroberto} 141258945Sroberto 142258945Srobertostatic void 143258945Srobertociph_encrypt(CIPH_CTX * ctx, const unsigned char *in, unsigned char *out) 144258945Sroberto{ 145258945Sroberto AES_encrypt(in, out, ctx); 146258945Sroberto} 147258945Sroberto 148258945Srobertostatic void 149258945Srobertomd_init(MD_CTX * ctx) 150258945Sroberto{ 151258945Sroberto SHA256_Init(ctx); 152258945Sroberto} 153258945Sroberto 154258945Srobertostatic void 155258945Srobertomd_update(MD_CTX * ctx, const unsigned char *data, int len) 156258945Sroberto{ 157258945Sroberto SHA256_Update(ctx, data, len); 158258945Sroberto} 159258945Sroberto 160258945Srobertostatic void 161258945Srobertomd_result(MD_CTX * ctx, unsigned char *dst) 162258945Sroberto{ 163258945Sroberto SHA256_CTX tmp; 164258945Sroberto 165258945Sroberto memcpy(&tmp, ctx, sizeof(*ctx)); 166258945Sroberto SHA256_Final(dst, &tmp); 167258945Sroberto memset(&tmp, 0, sizeof(tmp)); 168258945Sroberto} 169258945Sroberto 170258945Sroberto/* 171258945Sroberto * initialize state 172258945Sroberto */ 173258945Srobertostatic void 174258945Srobertoinit_state(FState * st) 175258945Sroberto{ 176258945Sroberto int i; 177258945Sroberto 178258945Sroberto memset(st, 0, sizeof(*st)); 179258945Sroberto for (i = 0; i < NUM_POOLS; i++) 180258945Sroberto md_init(&st->pool[i]); 181258945Sroberto st->pid = getpid(); 182258945Sroberto} 183258945Sroberto 184258945Sroberto/* 185258945Sroberto * Endianess does not matter. 186258945Sroberto * It just needs to change without repeating. 187258945Sroberto */ 188258945Srobertostatic void 189258945Srobertoinc_counter(FState * st) 190258945Sroberto{ 191258945Sroberto uint32_t *val = (uint32_t *) st->counter; 192258945Sroberto 193258945Sroberto if (++val[0]) 194258945Sroberto return; 195258945Sroberto if (++val[1]) 196258945Sroberto return; 197258945Sroberto if (++val[2]) 198258945Sroberto return; 199258945Sroberto ++val[3]; 200258945Sroberto} 201258945Sroberto 202258945Sroberto/* 203258945Sroberto * This is called 'cipher in counter mode'. 204258945Sroberto */ 205258945Srobertostatic void 206258945Srobertoencrypt_counter(FState * st, unsigned char *dst) 207258945Sroberto{ 208258945Sroberto ciph_encrypt(&st->ciph, st->counter, dst); 209258945Sroberto inc_counter(st); 210258945Sroberto} 211258945Sroberto 212258945Sroberto 213258945Sroberto/* 214258945Sroberto * The time between reseed must be at least RESEED_INTERVAL 215258945Sroberto * microseconds. 216258945Sroberto */ 217258945Srobertostatic int 218258945Srobertoenough_time_passed(FState * st) 219258945Sroberto{ 220258945Sroberto int ok; 221258945Sroberto struct timeval tv; 222258945Sroberto struct timeval *last = &st->last_reseed_time; 223258945Sroberto 224258945Sroberto gettimeofday(&tv, NULL); 225258945Sroberto 226258945Sroberto /* check how much time has passed */ 227258945Sroberto ok = 0; 228258945Sroberto if (tv.tv_sec > last->tv_sec + 1) 229258945Sroberto ok = 1; 230258945Sroberto else if (tv.tv_sec == last->tv_sec + 1) 231258945Sroberto { 232258945Sroberto if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) 233258945Sroberto ok = 1; 234258945Sroberto } 235258945Sroberto else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) 236258945Sroberto ok = 1; 237258945Sroberto 238258945Sroberto /* reseed will happen, update last_reseed_time */ 239258945Sroberto if (ok) 240258945Sroberto memcpy(last, &tv, sizeof(tv)); 241258945Sroberto 242258945Sroberto memset(&tv, 0, sizeof(tv)); 243258945Sroberto 244258945Sroberto return ok; 245258945Sroberto} 246258945Sroberto 247258945Sroberto/* 248258945Sroberto * generate new key from all the pools 249258945Sroberto */ 250258945Srobertostatic void 251258945Srobertoreseed(FState * st) 252258945Sroberto{ 253258945Sroberto unsigned k; 254258945Sroberto unsigned n; 255258945Sroberto MD_CTX key_md; 256258945Sroberto unsigned char buf[BLOCK]; 257258945Sroberto 258258945Sroberto /* set pool as empty */ 259258945Sroberto st->pool0_bytes = 0; 260258945Sroberto 261258945Sroberto /* 262258945Sroberto * Both #0 and #1 reseed would use only pool 0. Just skip #0 then. 263258945Sroberto */ 264258945Sroberto n = ++st->reseed_count; 265258945Sroberto 266258945Sroberto /* 267258945Sroberto * The goal: use k-th pool only 1/(2^k) of the time. 268258945Sroberto */ 269258945Sroberto md_init(&key_md); 270258945Sroberto for (k = 0; k < NUM_POOLS; k++) 271258945Sroberto { 272258945Sroberto md_result(&st->pool[k], buf); 273258945Sroberto md_update(&key_md, buf, BLOCK); 274258945Sroberto 275258945Sroberto if (n & 1 || !n) 276258945Sroberto break; 277258945Sroberto n >>= 1; 278258945Sroberto } 279258945Sroberto 280258945Sroberto /* add old key into mix too */ 281258945Sroberto md_update(&key_md, st->key, BLOCK); 282258945Sroberto 283258945Sroberto /* add pid to make output diverse after fork() */ 284258945Sroberto md_update(&key_md, (const unsigned char *)&st->pid, sizeof(st->pid)); 285258945Sroberto 286258945Sroberto /* now we have new key */ 287258945Sroberto md_result(&key_md, st->key); 288258945Sroberto 289258945Sroberto /* use new key */ 290258945Sroberto ciph_init(&st->ciph, st->key, BLOCK); 291258945Sroberto 292258945Sroberto memset(&key_md, 0, sizeof(key_md)); 293258945Sroberto memset(buf, 0, BLOCK); 294258945Sroberto} 295258945Sroberto 296258945Sroberto/* 297258945Sroberto * Pick a random pool. This uses key bytes as random source. 298258945Sroberto */ 299258945Srobertostatic unsigned 300258945Srobertoget_rand_pool(FState * st) 301258945Sroberto{ 302258945Sroberto unsigned rnd; 303258945Sroberto 304258945Sroberto /* 305258945Sroberto * This slightly prefers lower pools - thats OK. 306258945Sroberto */ 307258945Sroberto rnd = st->key[st->rnd_pos] % NUM_POOLS; 308258945Sroberto 309258945Sroberto st->rnd_pos++; 310258945Sroberto if (st->rnd_pos >= BLOCK) 311258945Sroberto st->rnd_pos = 0; 312258945Sroberto 313258945Sroberto return rnd; 314258945Sroberto} 315258945Sroberto 316258945Sroberto/* 317258945Sroberto * update pools 318258945Sroberto */ 319258945Srobertostatic void 320258945Srobertoadd_entropy(FState * st, const unsigned char *data, unsigned len) 321258945Sroberto{ 322258945Sroberto unsigned pos; 323258945Sroberto unsigned char hash[BLOCK]; 324258945Sroberto MD_CTX md; 325258945Sroberto 326258945Sroberto /* hash given data */ 327258945Sroberto md_init(&md); 328258945Sroberto md_update(&md, data, len); 329258945Sroberto md_result(&md, hash); 330258945Sroberto 331258945Sroberto /* 332258945Sroberto * Make sure the pool 0 is initialized, then update randomly. 333258945Sroberto */ 334258945Sroberto if (st->reseed_count == 0) 335258945Sroberto pos = 0; 336258945Sroberto else 337258945Sroberto pos = get_rand_pool(st); 338258945Sroberto md_update(&st->pool[pos], hash, BLOCK); 339258945Sroberto 340258945Sroberto if (pos == 0) 341258945Sroberto st->pool0_bytes += len; 342258945Sroberto 343258945Sroberto memset(hash, 0, BLOCK); 344258945Sroberto memset(&md, 0, sizeof(md)); 345258945Sroberto} 346258945Sroberto 347258945Sroberto/* 348258945Sroberto * Just take 2 next blocks as new key 349258945Sroberto */ 350258945Srobertostatic void 351258945Srobertorekey(FState * st) 352258945Sroberto{ 353258945Sroberto encrypt_counter(st, st->key); 354258945Sroberto encrypt_counter(st, st->key + CIPH_BLOCK); 355258945Sroberto ciph_init(&st->ciph, st->key, BLOCK); 356258945Sroberto} 357258945Sroberto 358258945Sroberto/* 359258945Sroberto * Hide public constants. (counter, pools > 0) 360258945Sroberto * 361258945Sroberto * This can also be viewed as spreading the startup 362258945Sroberto * entropy over all of the components. 363258945Sroberto */ 364258945Srobertostatic void 365258945Srobertostartup_tricks(FState * st) 366258945Sroberto{ 367258945Sroberto int i; 368258945Sroberto unsigned char buf[BLOCK]; 369258945Sroberto 370258945Sroberto /* Use next block as counter. */ 371258945Sroberto encrypt_counter(st, st->counter); 372258945Sroberto 373258945Sroberto /* Now shuffle pools, excluding #0 */ 374258945Sroberto for (i = 1; i < NUM_POOLS; i++) 375258945Sroberto { 376258945Sroberto encrypt_counter(st, buf); 377258945Sroberto encrypt_counter(st, buf + CIPH_BLOCK); 378258945Sroberto md_update(&st->pool[i], buf, BLOCK); 379258945Sroberto } 380258945Sroberto memset(buf, 0, BLOCK); 381258945Sroberto 382258945Sroberto /* Hide the key. */ 383258945Sroberto rekey(st); 384258945Sroberto 385258945Sroberto /* This can be done only once. */ 386258945Sroberto st->tricks_done = 1; 387258945Sroberto} 388258945Sroberto 389258945Srobertostatic void 390258945Srobertoextract_data(FState * st, unsigned count, unsigned char *dst) 391258945Sroberto{ 392258945Sroberto unsigned n; 393258945Sroberto unsigned block_nr = 0; 394258945Sroberto pid_t pid = getpid(); 395258945Sroberto 396258945Sroberto /* Should we reseed? */ 397258945Sroberto if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0) 398258945Sroberto if (enough_time_passed(st)) 399258945Sroberto reseed(st); 400258945Sroberto 401258945Sroberto /* Do some randomization on first call */ 402258945Sroberto if (!st->tricks_done) 403258945Sroberto startup_tricks(st); 404258945Sroberto 405258945Sroberto /* If we forked, force a reseed again */ 406258945Sroberto if (pid != st->pid) { 407258945Sroberto st->pid = pid; 408258945Sroberto reseed(st); 409293650Sglebius } 410258945Sroberto 411258945Sroberto while (count > 0) 412258945Sroberto { 413258945Sroberto /* produce bytes */ 414258945Sroberto encrypt_counter(st, st->result); 415258945Sroberto 416258945Sroberto /* copy result */ 417258945Sroberto if (count > CIPH_BLOCK) 418258945Sroberto n = CIPH_BLOCK; 419258945Sroberto else 420258945Sroberto n = count; 421258945Sroberto memcpy(dst, st->result, n); 422258945Sroberto dst += n; 423258945Sroberto count -= n; 424293650Sglebius 425258945Sroberto /* must not give out too many bytes with one key */ 426258945Sroberto block_nr++; 427258945Sroberto if (block_nr > (RESEED_BYTES / CIPH_BLOCK)) 428258945Sroberto { 429258945Sroberto rekey(st); 430258945Sroberto block_nr = 0; 431258945Sroberto } 432258945Sroberto } 433258945Sroberto /* Set new key for next request. */ 434258945Sroberto rekey(st); 435258945Sroberto} 436258945Sroberto 437258945Sroberto/* 438258945Sroberto * public interface 439258945Sroberto */ 440258945Sroberto 441258945Srobertostatic FState main_state; 442258945Srobertostatic int init_done; 443258945Srobertostatic int have_entropy; 444258945Sroberto#define FORTUNA_RESEED_BYTE 10000 445258945Srobertostatic unsigned resend_bytes; 446258945Sroberto 447258945Sroberto/* 448258945Sroberto * This mutex protects all of the above static elements from concurrent 449258945Sroberto * access by multiple threads 450258945Sroberto */ 451258945Srobertostatic HEIMDAL_MUTEX fortuna_mutex = HEIMDAL_MUTEX_INITIALIZER; 452258945Sroberto 453258945Sroberto/* 454258945Sroberto * Try our best to do an inital seed 455258945Sroberto */ 456258945Sroberto#define INIT_BYTES 128 457258945Sroberto 458258945Sroberto/* 459258945Sroberto * fortuna_mutex must be held across calls to this function 460258945Sroberto */ 461258945Sroberto 462258945Srobertostatic int 463258945Srobertofortuna_reseed(void) 464258945Sroberto{ 465258945Sroberto int entropy_p = 0; 466258945Sroberto 467258945Sroberto if (!init_done) 468258945Sroberto abort(); 469258945Sroberto 470258945Sroberto#ifndef NO_RAND_UNIX_METHOD 471258945Sroberto { 472258945Sroberto unsigned char buf[INIT_BYTES]; 473258945Sroberto if ((*hc_rand_unix_method.bytes)(buf, sizeof(buf)) == 1) { 474258945Sroberto add_entropy(&main_state, buf, sizeof(buf)); 475258945Sroberto entropy_p = 1; 476258945Sroberto memset(buf, 0, sizeof(buf)); 477258945Sroberto } 478258945Sroberto } 479258945Sroberto#endif 480258945Sroberto#ifdef HAVE_ARC4RANDOM 481258945Sroberto { 482258945Sroberto uint32_t buf[INIT_BYTES / sizeof(uint32_t)]; 483258945Sroberto int i; 484258945Sroberto 485258945Sroberto for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++) 486258945Sroberto buf[i] = arc4random(); 487258945Sroberto add_entropy(&main_state, (void *)buf, sizeof(buf)); 488258945Sroberto entropy_p = 1; 489258945Sroberto } 490#endif 491#ifndef NO_RAND_EGD_METHOD 492 /* 493 * Only to get egd entropy if /dev/random or arc4rand failed since 494 * it can be horribly slow to generate new bits. 495 */ 496 if (!entropy_p) { 497 unsigned char buf[INIT_BYTES]; 498 if ((*hc_rand_egd_method.bytes)(buf, sizeof(buf)) == 1) { 499 add_entropy(&main_state, buf, sizeof(buf)); 500 entropy_p = 1; 501 memset(buf, 0, sizeof(buf)); 502 } 503 } 504#endif 505 /* 506 * Fall back to gattering data from timer and secret files, this 507 * is really the last resort. 508 */ 509 if (!entropy_p) { 510 /* to save stackspace */ 511 union { 512 unsigned char buf[INIT_BYTES]; 513 unsigned char shad[1001]; 514 } u; 515 int fd; 516 517 /* add timer info */ 518 if ((*hc_rand_timer_method.bytes)(u.buf, sizeof(u.buf)) == 1) 519 add_entropy(&main_state, u.buf, sizeof(u.buf)); 520 /* add /etc/shadow */ 521 fd = open("/etc/shadow", O_RDONLY, 0); 522 if (fd >= 0) { 523 ssize_t n; 524 rk_cloexec(fd); 525 /* add_entropy will hash the buf */ 526 while ((n = read(fd, (char *)u.shad, sizeof(u.shad))) > 0) 527 add_entropy(&main_state, u.shad, sizeof(u.shad)); 528 close(fd); 529 } 530 531 memset(&u, 0, sizeof(u)); 532 533 entropy_p = 1; /* sure about this ? */ 534 } 535 { 536 pid_t pid = getpid(); 537 add_entropy(&main_state, (void *)&pid, sizeof(pid)); 538 } 539 { 540 struct timeval tv; 541 gettimeofday(&tv, NULL); 542 add_entropy(&main_state, (void *)&tv, sizeof(tv)); 543 } 544#ifdef HAVE_GETUID 545 { 546 uid_t u = getuid(); 547 add_entropy(&main_state, (void *)&u, sizeof(u)); 548 } 549#endif 550 return entropy_p; 551} 552 553/* 554 * fortuna_mutex must be held by callers of this function 555 */ 556static int 557fortuna_init(void) 558{ 559 if (!init_done) 560 { 561 init_state(&main_state); 562 init_done = 1; 563 } 564 if (!have_entropy) 565 have_entropy = fortuna_reseed(); 566 return (init_done && have_entropy); 567} 568 569 570 571static void 572fortuna_seed(const void *indata, int size) 573{ 574 HEIMDAL_MUTEX_lock(&fortuna_mutex); 575 576 fortuna_init(); 577 add_entropy(&main_state, indata, size); 578 if (size >= INIT_BYTES) 579 have_entropy = 1; 580 581 HEIMDAL_MUTEX_unlock(&fortuna_mutex); 582} 583 584static int 585fortuna_bytes(unsigned char *outdata, int size) 586{ 587 int ret = 0; 588 589 HEIMDAL_MUTEX_lock(&fortuna_mutex); 590 591 if (!fortuna_init()) 592 goto out; 593 594 resend_bytes += size; 595 if (resend_bytes > FORTUNA_RESEED_BYTE || resend_bytes < size) { 596 resend_bytes = 0; 597 fortuna_reseed(); 598 } 599 extract_data(&main_state, size, outdata); 600 ret = 1; 601 602out: 603 HEIMDAL_MUTEX_unlock(&fortuna_mutex); 604 605 return ret; 606} 607 608static void 609fortuna_cleanup(void) 610{ 611 HEIMDAL_MUTEX_lock(&fortuna_mutex); 612 613 init_done = 0; 614 have_entropy = 0; 615 memset(&main_state, 0, sizeof(main_state)); 616 617 HEIMDAL_MUTEX_unlock(&fortuna_mutex); 618} 619 620static void 621fortuna_add(const void *indata, int size, double entropi) 622{ 623 fortuna_seed(indata, size); 624} 625 626static int 627fortuna_pseudorand(unsigned char *outdata, int size) 628{ 629 return fortuna_bytes(outdata, size); 630} 631 632static int 633fortuna_status(void) 634{ 635 int result; 636 637 HEIMDAL_MUTEX_lock(&fortuna_mutex); 638 result = fortuna_init(); 639 HEIMDAL_MUTEX_unlock(&fortuna_mutex); 640 641 return result ? 1 : 0; 642} 643 644const RAND_METHOD hc_rand_fortuna_method = { 645 fortuna_seed, 646 fortuna_bytes, 647 fortuna_cleanup, 648 fortuna_add, 649 fortuna_pseudorand, 650 fortuna_status 651}; 652 653const RAND_METHOD * 654RAND_fortuna_method(void) 655{ 656 return &hc_rand_fortuna_method; 657} 658