LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/hcrypto - rand-fortuna.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 170 218 78.0 %
Date: 2024-04-21 15:09:00 Functions: 19 24 79.2 %

          Line data    Source code
       1             : /*
       2             :  * fortuna.c
       3             :  *              Fortuna-like PRNG.
       4             :  *
       5             :  * Copyright (c) 2005 Marko Kreen
       6             :  * All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  * 1. Redistributions of source code must retain the above copyright
      12             :  *        notice, this list of conditions and the following disclaimer.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *        notice, this list of conditions and the following disclaimer in the
      15             :  *        documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      18             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      19             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      20             :  * ARE DISCLAIMED.      IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
      21             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      22             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      23             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      24             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      25             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      26             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      27             :  * SUCH DAMAGE.
      28             :  *
      29             :  * $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.8 2006/10/04 00:29:46 momjian Exp $
      30             :  */
      31             : 
      32             : #include <config.h>
      33             : #include <roken.h>
      34             : #include <rand.h>
      35             : #include <heim_threads.h>
      36             : 
      37             : #ifdef KRB5
      38             : #include <krb5-types.h>
      39             : #endif
      40             : 
      41             : #include "randi.h"
      42             : #include "aes.h"
      43             : #include "sha.h"
      44             : 
      45             : /*
      46             :  * Why Fortuna-like: There does not seem to be any definitive reference
      47             :  * on Fortuna in the net.  Instead this implementation is based on
      48             :  * following references:
      49             :  *
      50             :  * http://en.wikipedia.org/wiki/Fortuna_(PRNG)
      51             :  *       - Wikipedia article
      52             :  * http://jlcooke.ca/random/
      53             :  *       - Jean-Luc Cooke Fortuna-based /dev/random driver for Linux.
      54             :  */
      55             : 
      56             : /*
      57             :  * There is some confusion about whether and how to carry forward
      58             :  * the state of the pools.      Seems like original Fortuna does not
      59             :  * do it, resetting hash after each request.  I guess expecting
      60             :  * feeding to happen more often that requesting.   This is absolutely
      61             :  * unsuitable for pgcrypto, as nothing asynchronous happens here.
      62             :  *
      63             :  * J.L. Cooke fixed this by feeding previous hash to new re-initialized
      64             :  * hash context.
      65             :  *
      66             :  * Fortuna predecessor Yarrow requires ability to query intermediate
      67             :  * 'final result' from hash, without affecting it.
      68             :  *
      69             :  * This implementation uses the Yarrow method - asking intermediate
      70             :  * results, but continuing with old state.
      71             :  */
      72             : 
      73             : 
      74             : /*
      75             :  * Algorithm parameters
      76             :  */
      77             : 
      78             : #define NUM_POOLS               32
      79             : 
      80             : /* in microseconds */
      81             : #define RESEED_INTERVAL 100000  /* 0.1 sec */
      82             : 
      83             : /* for one big request, reseed after this many bytes */
      84             : #define RESEED_BYTES    (1024*1024)
      85             : 
      86             : /*
      87             :  * Skip reseed if pool 0 has less than this many
      88             :  * bytes added since last reseed.
      89             :  */
      90             : #define POOL0_FILL              (256/8)
      91             : 
      92             : /*
      93             :  * Algorithm constants
      94             :  */
      95             : 
      96             : /* Both cipher key size and hash result size */
      97             : #define BLOCK                   32
      98             : 
      99             : /* cipher block size */
     100             : #define CIPH_BLOCK              16
     101             : 
     102             : /* for internal wrappers */
     103             : #define MD_CTX                  SHA256_CTX
     104             : #define CIPH_CTX                AES_KEY
     105             : 
     106             : struct fortuna_state
     107             : {
     108             :     unsigned char       counter[CIPH_BLOCK];
     109             :     unsigned char       result[CIPH_BLOCK];
     110             :     unsigned char       key[BLOCK];
     111             :     MD_CTX              pool[NUM_POOLS];
     112             :     CIPH_CTX            ciph;
     113             :     unsigned            reseed_count;
     114             :     struct timeval      last_reseed_time;
     115             :     unsigned            pool0_bytes;
     116             :     unsigned            rnd_pos;
     117             :     int                 tricks_done;
     118             :     pid_t               pid;
     119             : };
     120             : typedef struct fortuna_state FState;
     121             : 
     122             : 
     123             : /*
     124             :  * Use our own wrappers here.
     125             :  * - Need to get intermediate result from digest, without affecting it.
     126             :  * - Need re-set key on a cipher context.
     127             :  * - Algorithms are guaranteed to exist.
     128             :  * - No memory allocations.
     129             :  */
     130             : 
     131             : static void
     132     3566655 : ciph_init(CIPH_CTX * ctx, const unsigned char *key, int klen)
     133             : {
     134     3566655 :     AES_set_encrypt_key(key, klen * 8, ctx);
     135     3516909 : }
     136             : 
     137             : static void
     138    12937228 : ciph_encrypt(CIPH_CTX * ctx, const unsigned char *in, unsigned char *out)
     139             : {
     140    12937228 :     AES_encrypt(in, out, ctx);
     141    12704814 : }
     142             : 
     143             : static void
     144     1230390 : md_init(MD_CTX * ctx)
     145             : {
     146     1230390 :     SHA256_Init(ctx);
     147     1184597 : }
     148             : 
     149             : static void
     150     1378100 : md_update(MD_CTX * ctx, const unsigned char *data, int len)
     151             : {
     152     1378100 :     SHA256_Update(ctx, data, len);
     153     1327120 : }
     154             : 
     155             : static void
     156      181561 : md_result(MD_CTX * ctx, unsigned char *dst)
     157             : {
     158        6456 :     SHA256_CTX  tmp;
     159             : 
     160      181561 :     memcpy(&tmp, ctx, sizeof(*ctx));
     161      181561 :     SHA256_Final(dst, &tmp);
     162      181561 :     memset_s(&tmp, sizeof(tmp), 0, sizeof(tmp));
     163      181561 : }
     164             : 
     165             : /*
     166             :  * initialize state
     167             :  */
     168             : static void
     169       33851 : init_state(FState * st)
     170             : {
     171        1269 :     int                 i;
     172             : 
     173       33851 :     memset(st, 0, sizeof(*st));
     174     1117083 :     for (i = 0; i < NUM_POOLS; i++)
     175     1083232 :         md_init(&st->pool[i]);
     176       33851 :     st->pid = getpid();
     177       33851 : }
     178             : 
     179             : /*
     180             :  * Endianess does not matter.
     181             :  * It just needs to change without repeating.
     182             :  */
     183             : static void
     184    12937228 : inc_counter(FState * st)
     185             : {
     186    12937228 :     uint32_t   *val = (uint32_t *) st->counter;
     187             : 
     188    12937228 :     if (++val[0])
     189    12704814 :         return;
     190           0 :     if (++val[1])
     191           0 :         return;
     192           0 :     if (++val[2])
     193           0 :         return;
     194           0 :     ++val[3];
     195             : }
     196             : 
     197             : /*
     198             :  * This is called 'cipher in counter mode'.
     199             :  */
     200             : static void
     201    12937228 : encrypt_counter(FState * st, unsigned char *dst)
     202             : {
     203    12937228 :     ciph_encrypt(&st->ciph, st->counter, dst);
     204    12937228 :     inc_counter(st);
     205    12937228 : }
     206             : 
     207             : 
     208             : /*
     209             :  * The time between reseed must be at least RESEED_INTERVAL
     210             :  * microseconds.
     211             :  */
     212             : static int
     213       33985 : enough_time_passed(FState * st)
     214             : {
     215        1270 :     int                 ok;
     216        1270 :     struct timeval tv;
     217       33985 :     struct timeval *last = &st->last_reseed_time;
     218             : 
     219       33985 :     gettimeofday(&tv, NULL);
     220             : 
     221             :     /* check how much time has passed */
     222       33985 :     ok = 0;
     223       33985 :     if (tv.tv_sec > last->tv_sec + 1)
     224       32715 :         ok = 1;
     225           0 :     else if (tv.tv_sec == last->tv_sec + 1)
     226             :     {
     227           0 :         if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
     228           0 :             ok = 1;
     229             :     }
     230           0 :     else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
     231           0 :         ok = 1;
     232             : 
     233             :     /* reseed will happen, update last_reseed_time */
     234       32715 :     if (ok)
     235       33985 :         memcpy(last, &tv, sizeof(tv));
     236             : 
     237       33985 :     memset_s(&tv, sizeof(tv), 0, sizeof(tv));
     238             : 
     239       33985 :     return ok;
     240             : }
     241             : 
     242             : /*
     243             :  * generate new key from all the pools
     244             :  */
     245             : static void
     246       34145 : reseed(FState * st)
     247             : {
     248        1270 :     unsigned    k;
     249        1270 :     unsigned    n;
     250        1270 :     MD_CTX              key_md;
     251        1270 :     unsigned char       buf[BLOCK];
     252             : 
     253             :     /* set pool as empty */
     254       34145 :     st->pool0_bytes = 0;
     255             : 
     256             :     /*
     257             :      * Both #0 and #1 reseed would use only pool 0. Just skip #0 then.
     258             :      */
     259       34145 :     n = ++st->reseed_count;
     260             : 
     261             :     /*
     262             :      * The goal: use k-th pool only 1/(2^k) of the time.
     263             :      */
     264       34145 :     md_init(&key_md);
     265       35673 :     for (k = 0; k < NUM_POOLS; k++)
     266             :     {
     267       34403 :         md_result(&st->pool[k], buf);
     268       34403 :         md_update(&key_md, buf, BLOCK);
     269             : 
     270       34403 :         if (n & 1 || !n)
     271             :             break;
     272         258 :         n >>= 1;
     273             :     }
     274             : 
     275             :     /* add old key into mix too */
     276       34145 :     md_update(&key_md, st->key, BLOCK);
     277             : 
     278             :     /* add pid to make output diverse after fork() */
     279       34145 :     md_update(&key_md, (const unsigned char *)&st->pid, sizeof(st->pid));
     280             : 
     281             :     /* now we have new key */
     282       34145 :     md_result(&key_md, st->key);
     283             : 
     284             :     /* use new key */
     285       34145 :     ciph_init(&st->ciph, st->key, BLOCK);
     286             : 
     287       34145 :     memset_s(&key_md, sizeof(key_md), 0, sizeof(key_md));
     288       34145 :     memset_s(buf, sizeof(buf), 0, sizeof(buf));
     289       34145 : }
     290             : 
     291             : /*
     292             :  * Pick a random pool.  This uses key bytes as random source.
     293             :  */
     294             : static unsigned
     295       11460 : get_rand_pool(FState * st)
     296             : {
     297         108 :     unsigned    rnd;
     298             : 
     299             :     /*
     300             :      * This slightly prefers lower pools - thats OK.
     301             :      */
     302       11460 :     rnd = st->key[st->rnd_pos] % NUM_POOLS;
     303             : 
     304       11460 :     st->rnd_pos++;
     305       11460 :     if (st->rnd_pos >= BLOCK)
     306         197 :         st->rnd_pos = 0;
     307             : 
     308       11352 :     return rnd;
     309             : }
     310             : 
     311             : /*
     312             :  * update pools
     313             :  */
     314             : static void
     315      113013 : add_entropy(FState * st, const unsigned char *data, unsigned len)
     316             : {
     317        3915 :     unsigned            pos;
     318        3915 :     unsigned char       hash[BLOCK];
     319        3915 :     MD_CTX              md;
     320             : 
     321             :     /* hash given data */
     322      113013 :     md_init(&md);
     323      113013 :     md_update(&md, data, len);
     324      113013 :     md_result(&md, hash);
     325             : 
     326             :     /*
     327             :      * Make sure the pool 0 is initialized, then update randomly.
     328             :      */
     329      113013 :     if (st->reseed_count == 0)
     330       97746 :         pos = 0;
     331             :     else
     332       11460 :         pos = get_rand_pool(st);
     333      113013 :     md_update(&st->pool[pos], hash, BLOCK);
     334             : 
     335      113013 :     if (pos == 0)
     336      101971 :         st->pool0_bytes += len;
     337             : 
     338      113013 :     memset_s(hash, sizeof(hash), 0, sizeof(hash));
     339      113013 :     memset_s(&md, sizeof(md), 0, sizeof(md));
     340      113013 : }
     341             : 
     342             : /*
     343             :  * Just take 2 next blocks as new key
     344             :  */
     345             : static void
     346     3532510 : rekey(FState * st)
     347             : {
     348     3532510 :     encrypt_counter(st, st->key);
     349     3532510 :     encrypt_counter(st, st->key + CIPH_BLOCK);
     350     3532510 :     ciph_init(&st->ciph, st->key, BLOCK);
     351     3532510 : }
     352             : 
     353             : /*
     354             :  * Hide public constants. (counter, pools > 0)
     355             :  *
     356             :  * This can also be viewed as spreading the startup
     357             :  * entropy over all of the components.
     358             :  */
     359             : static void
     360       33851 : startup_tricks(FState * st)
     361             : {
     362        1269 :     int                 i;
     363        1269 :     unsigned char       buf[BLOCK];
     364             : 
     365             :     /* Use next block as counter. */
     366       33851 :     encrypt_counter(st, st->counter);
     367             : 
     368             :     /* Now shuffle pools, excluding #0 */
     369     1084501 :     for (i = 1; i < NUM_POOLS; i++)
     370             :     {
     371     1049381 :         encrypt_counter(st, buf);
     372     1049381 :         encrypt_counter(st, buf + CIPH_BLOCK);
     373     1049381 :         md_update(&st->pool[i], buf, BLOCK);
     374             :     }
     375       33851 :     memset_s(buf, sizeof(buf), 0, sizeof(buf));
     376             : 
     377             :     /* Hide the key. */
     378       33851 :     rekey(st);
     379             : 
     380             :     /* This can be done only once. */
     381       33851 :     st->tricks_done = 1;
     382       33851 : }
     383             : 
     384             : static void
     385     3498659 : extract_data(FState * st, unsigned count, unsigned char *dst)
     386             : {
     387       47207 :     unsigned    n;
     388     3498659 :     unsigned    block_nr = 0;
     389     3498659 :     pid_t       pid = getpid();
     390             : 
     391             :     /* Should we reseed? */
     392     3498659 :     if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0)
     393       33985 :         if (enough_time_passed(st))
     394       33985 :             reseed(st);
     395             : 
     396             :     /* Do some randomization on first call */
     397     3498659 :     if (!st->tricks_done)
     398       33851 :         startup_tricks(st);
     399             : 
     400             :     /* If we forked, force a reseed again */
     401     3498659 :     if (pid != st->pid) {
     402         160 :         st->pid = pid;
     403         160 :         reseed(st);
     404             :     }
     405             : 
     406     7238254 :     while (count > 0)
     407             :     {
     408             :         /* produce bytes */
     409     3739595 :         encrypt_counter(st, st->result);
     410             : 
     411             :         /* copy result */
     412     3739595 :         if (count > CIPH_BLOCK)
     413      232628 :             n = CIPH_BLOCK;
     414             :         else
     415     3451452 :             n = count;
     416     3739595 :         memcpy(dst, st->result, n);
     417     3739595 :         dst += n;
     418     3739595 :         count -= n;
     419             : 
     420             :         /* must not give out too many bytes with one key */
     421     3739595 :         block_nr++;
     422     3739595 :         if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
     423             :         {
     424           0 :             rekey(st);
     425           0 :             block_nr = 0;
     426             :         }
     427             :     }
     428             :     /* Set new key for next request. */
     429     3498659 :     rekey(st);
     430     3498659 : }
     431             : 
     432             : /*
     433             :  * public interface
     434             :  */
     435             : 
     436             : static FState   main_state;
     437             : static int      init_done;
     438             : static int      have_entropy;
     439             : #define FORTUNA_RESEED_BYTE     10000
     440             : static unsigned resend_bytes;
     441             : 
     442             : /*
     443             :  * This mutex protects all of the above static elements from concurrent
     444             :  * access by multiple threads
     445             :  */
     446             : static HEIMDAL_MUTEX fortuna_mutex = HEIMDAL_MUTEX_INITIALIZER;
     447             : 
     448             : /*
     449             :  * Try our best to do an initial seed
     450             :  */
     451             : #define INIT_BYTES      128
     452             : 
     453             : /*
     454             :  * fortuna_mutex must be held across calls to this function
     455             :  */
     456             : 
     457             : static int
     458       37671 : fortuna_reseed(void)
     459             : {
     460       37671 :     int entropy_p = 0;
     461             : 
     462       37671 :     if (!init_done)
     463           0 :         abort();
     464             : 
     465             : #ifndef NO_RAND_UNIX_METHOD
     466             :     {
     467        1305 :         unsigned char buf[INIT_BYTES];
     468       37671 :         if ((*hc_rand_unix_method.bytes)(buf, sizeof(buf)) == 1) {
     469       37671 :             add_entropy(&main_state, buf, sizeof(buf));
     470       37671 :             entropy_p = 1;
     471       37671 :             memset_s(buf, sizeof(buf), 0, sizeof(buf));
     472             :         }
     473             :     }
     474             : #endif
     475             : #ifdef HAVE_ARC4RANDOM
     476             :     {
     477             :         uint32_t buf[INIT_BYTES / sizeof(uint32_t)];
     478             :         int i;
     479             : 
     480             :         for (i = 0; i < sizeof(buf)/sizeof(buf[0]); i++)
     481             :             buf[i] = arc4random();
     482             :         add_entropy(&main_state, (void *)buf, sizeof(buf));
     483             :         entropy_p = 1;
     484             :     }
     485             : #endif
     486             :     /*
     487             :      * Fall back to gattering data from timer and secret files, this
     488             :      * is really the last resort.
     489             :      */
     490       37671 :     if (!entropy_p) {
     491             :         /* to save stackspace */
     492           0 :         union {
     493             :             unsigned char buf[INIT_BYTES];
     494             :             unsigned char shad[1001];
     495             :         } u;
     496           0 :         int fd;
     497             : 
     498             :         /* add timer info */
     499           0 :         if ((*hc_rand_timer_method.bytes)(u.buf, sizeof(u.buf)) == 1)
     500           0 :             add_entropy(&main_state, u.buf, sizeof(u.buf));
     501             :         /* add /etc/shadow */
     502           0 :         fd = open("/etc/shadow", O_RDONLY, 0);
     503           0 :         if (fd >= 0) {
     504           0 :             rk_cloexec(fd);
     505             :             /* add_entropy will hash the buf */
     506           0 :             while (read(fd, (char *)u.shad, sizeof(u.shad)) > 0)
     507           0 :                 add_entropy(&main_state, u.shad, sizeof(u.shad));
     508           0 :             close(fd);
     509             :         }
     510             : 
     511           0 :         memset_s(&u, sizeof(u), 0, sizeof(u));
     512             : 
     513           0 :         entropy_p = 1; /* sure about this ? */
     514             :     }
     515             :     {
     516       37671 :         pid_t pid = getpid();
     517       37671 :         add_entropy(&main_state, (void *)&pid, sizeof(pid));
     518             :     }
     519             :     {
     520        1305 :         struct timeval tv;
     521       37671 :         gettimeofday(&tv, NULL);
     522       37671 :         add_entropy(&main_state, (void *)&tv, sizeof(tv));
     523             :     }
     524             : #ifdef HAVE_GETUID
     525             :     {
     526             :         uid_t u = getuid();
     527             :         add_entropy(&main_state, (void *)&u, sizeof(u));
     528             :     }
     529             : #endif
     530       37671 :     return entropy_p;
     531             : }
     532             : 
     533             : /*
     534             :  * fortuna_mutex must be held by callers of this function
     535             :  */
     536             : static int
     537     3566361 : fortuna_init(void)
     538             : {
     539     3566361 :     if (!init_done)
     540             :     {
     541       33851 :         init_state(&main_state);
     542       33851 :         init_done = 1;
     543             :     }
     544     3566361 :     if (!have_entropy)
     545       33851 :         have_entropy = fortuna_reseed();
     546     3566361 :     return (init_done && have_entropy);
     547             : }
     548             : 
     549             : 
     550             : 
     551             : static void
     552           0 : fortuna_seed(const void *indata, int size)
     553             : {
     554           0 :     HEIMDAL_MUTEX_lock(&fortuna_mutex);
     555             : 
     556           0 :     fortuna_init();
     557           0 :     add_entropy(&main_state, indata, size);
     558           0 :     if (size >= INIT_BYTES)
     559           0 :         have_entropy = 1;
     560             : 
     561           0 :     HEIMDAL_MUTEX_unlock(&fortuna_mutex);
     562           0 : }
     563             : 
     564             : static int
     565     3498659 : fortuna_bytes(unsigned char *outdata, int size)
     566             : {
     567     3498659 :     int ret = 0;
     568             : 
     569       47207 :     HEIMDAL_MUTEX_lock(&fortuna_mutex);
     570             : 
     571     3498659 :     if (!fortuna_init())
     572           0 :         goto out;
     573             : 
     574     3498659 :     resend_bytes += size;
     575     3498659 :     if (resend_bytes > FORTUNA_RESEED_BYTE || resend_bytes < size) {
     576        3820 :         resend_bytes = 0;
     577        3820 :         fortuna_reseed();
     578             :     }
     579     3498659 :     extract_data(&main_state, size, outdata);
     580     3498659 :     ret = 1;
     581             : 
     582     3498659 : out:
     583       47207 :     HEIMDAL_MUTEX_unlock(&fortuna_mutex);
     584             : 
     585     3498659 :     return ret;
     586             : }
     587             : 
     588             : static void
     589           0 : fortuna_cleanup(void)
     590             : {
     591           0 :     HEIMDAL_MUTEX_lock(&fortuna_mutex);
     592             : 
     593           0 :     init_done = 0;
     594           0 :     have_entropy = 0;
     595           0 :     memset_s(&main_state, sizeof(main_state), 0, sizeof(main_state));
     596             : 
     597           0 :     HEIMDAL_MUTEX_unlock(&fortuna_mutex);
     598           0 : }
     599             : 
     600             : static void
     601           0 : fortuna_add(const void *indata, int size, double entropi)
     602             : {
     603           0 :     fortuna_seed(indata, size);
     604           0 : }
     605             : 
     606             : static int
     607           0 : fortuna_pseudorand(unsigned char *outdata, int size)
     608             : {
     609           0 :     return fortuna_bytes(outdata, size);
     610             : }
     611             : 
     612             : static int
     613       67702 : fortuna_status(void)
     614             : {
     615        2538 :     int result;
     616             : 
     617        2538 :     HEIMDAL_MUTEX_lock(&fortuna_mutex);
     618       67702 :     result = fortuna_init();
     619        2538 :     HEIMDAL_MUTEX_unlock(&fortuna_mutex);
     620             : 
     621       67702 :     return result ? 1 : 0;
     622             : }
     623             : 
     624             : #if defined(__GNUC__) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
     625             : const RAND_METHOD hc_rand_fortuna_method = {
     626             :     .seed = fortuna_seed,
     627             :     .bytes = fortuna_bytes,
     628             :     .cleanup = fortuna_cleanup,
     629             :     .add = fortuna_add,
     630             :     .pseudorand = fortuna_pseudorand,
     631             :     .status = fortuna_status
     632             : };
     633             : #else
     634             : const RAND_METHOD hc_rand_fortuna_method = {
     635             :     fortuna_seed,
     636             :     fortuna_bytes,
     637             :     fortuna_cleanup,
     638             :     fortuna_add,
     639             :     fortuna_pseudorand,
     640             :     fortuna_status
     641             : };
     642             : #endif
     643             : 
     644             : const RAND_METHOD *
     645           0 : RAND_fortuna_method(void)
     646             : {
     647           0 :     return &hc_rand_fortuna_method;
     648             : }

Generated by: LCOV version 1.14