Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions | Variables

fortuna.c File Reference

#include "postgres.h"
#include <sys/time.h>
#include "rijndael.h"
#include "sha2.h"
#include "fortuna.h"
Include dependency graph for fortuna.c:

Go to the source code of this file.

Data Structures

struct  fortuna_state

Defines

#define NUM_POOLS   23
#define RESEED_INTERVAL   100000
#define RESEED_BYTES   (1024*1024)
#define POOL0_FILL   (256/8)
#define BLOCK   32
#define CIPH_BLOCK   16
#define MD_CTX   SHA256_CTX
#define CIPH_CTX   rijndael_ctx

Typedefs

typedef struct fortuna_state FState

Functions

static void ciph_init (CIPH_CTX *ctx, const uint8 *key, int klen)
static void ciph_encrypt (CIPH_CTX *ctx, const uint8 *in, uint8 *out)
static void md_init (MD_CTX *ctx)
static void md_update (MD_CTX *ctx, const uint8 *data, int len)
static void md_result (MD_CTX *ctx, uint8 *dst)
static void init_state (FState *st)
static void inc_counter (FState *st)
static void encrypt_counter (FState *st, uint8 *dst)
static int enough_time_passed (FState *st)
static void reseed (FState *st)
static unsigned get_rand_pool (FState *st)
static void add_entropy (FState *st, const uint8 *data, unsigned len)
static void rekey (FState *st)
static void startup_tricks (FState *st)
static void extract_data (FState *st, unsigned count, uint8 *dst)
void fortuna_add_entropy (const uint8 *data, unsigned len)
void fortuna_get_bytes (unsigned len, uint8 *dst)

Variables

static FState main_state
static int init_done = 0

Define Documentation

#define BLOCK   32

Definition at line 108 of file fortuna.c.

Referenced by add_entropy(), get_rand_pool(), rekey(), reseed(), and startup_tricks().

#define CIPH_BLOCK   16

Definition at line 111 of file fortuna.c.

Referenced by extract_data(), rekey(), and startup_tricks().

#define CIPH_CTX   rijndael_ctx

Definition at line 115 of file fortuna.c.

#define MD_CTX   SHA256_CTX

Definition at line 114 of file fortuna.c.

Referenced by add_entropy(), and reseed().

#define NUM_POOLS   23

Definition at line 89 of file fortuna.c.

#define POOL0_FILL   (256/8)

Definition at line 101 of file fortuna.c.

Referenced by extract_data().

#define RESEED_BYTES   (1024*1024)

Definition at line 95 of file fortuna.c.

Referenced by extract_data().

#define RESEED_INTERVAL   100000

Definition at line 92 of file fortuna.c.

Referenced by enough_time_passed().


Typedef Documentation

typedef struct fortuna_state FState

Definition at line 130 of file fortuna.c.


Function Documentation

static void add_entropy ( FState st,
const uint8 data,
unsigned  len 
) [static]

Definition at line 321 of file fortuna.c.

References BLOCK, get_rand_pool(), hash(), MD_CTX, md_init(), md_result(), md_update(), fortuna_state::pool, fortuna_state::pool0_bytes, and fortuna_state::reseed_count.

Referenced by fortuna_add_entropy().

{
    unsigned    pos;
    uint8       hash[BLOCK];
    MD_CTX      md;

    /* hash given data */
    md_init(&md);
    md_update(&md, data, len);
    md_result(&md, hash);

    /*
     * Make sure the pool 0 is initialized, then update randomly.
     */
    if (st->reseed_count == 0)
        pos = 0;
    else
        pos = get_rand_pool(st);
    md_update(&st->pool[pos], hash, BLOCK);

    if (pos == 0)
        st->pool0_bytes += len;

    memset(hash, 0, BLOCK);
    memset(&md, 0, sizeof(md));
}

static void ciph_encrypt ( CIPH_CTX *  ctx,
const uint8 in,
uint8 out 
) [static]

Definition at line 148 of file fortuna.c.

References rijndael_encrypt().

Referenced by encrypt_counter().

{
    rijndael_encrypt(ctx, (const uint32 *) in, (uint32 *) out);
}

static void ciph_init ( CIPH_CTX *  ctx,
const uint8 key,
int  klen 
) [static]

Definition at line 142 of file fortuna.c.

References rijndael_set_key().

Referenced by rekey(), and reseed().

{
    rijndael_set_key(ctx, (const uint32 *) key, klen, 1);
}

static void encrypt_counter ( FState st,
uint8 dst 
) [static]

Definition at line 210 of file fortuna.c.

References fortuna_state::ciph, ciph_encrypt(), fortuna_state::counter, and inc_counter().

Referenced by extract_data(), rekey(), and startup_tricks().

{
    ciph_encrypt(&st->ciph, st->counter, dst);
    inc_counter(st);
}

static int enough_time_passed ( FState st  )  [static]

Definition at line 222 of file fortuna.c.

References gettimeofday(), fortuna_state::last_reseed_time, NULL, and RESEED_INTERVAL.

Referenced by extract_data().

{
    int         ok;
    struct timeval tv;
    struct timeval *last = &st->last_reseed_time;

    gettimeofday(&tv, NULL);

    /* check how much time has passed */
    ok = 0;
    if (tv.tv_sec > last->tv_sec + 1)
        ok = 1;
    else if (tv.tv_sec == last->tv_sec + 1)
    {
        if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
            ok = 1;
    }
    else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL)
        ok = 1;

    /* reseed will happen, update last_reseed_time */
    if (ok)
        memcpy(last, &tv, sizeof(tv));

    memset(&tv, 0, sizeof(tv));

    return ok;
}

static void extract_data ( FState st,
unsigned  count,
uint8 dst 
) [static]

Definition at line 391 of file fortuna.c.

References CIPH_BLOCK, encrypt_counter(), enough_time_passed(), fortuna_state::pool0_bytes, POOL0_FILL, rekey(), reseed(), RESEED_BYTES, fortuna_state::reseed_count, fortuna_state::result, startup_tricks(), and fortuna_state::tricks_done.

Referenced by fortuna_get_bytes().

{
    unsigned    n;
    unsigned    block_nr = 0;

    /* Should we reseed? */
    if (st->pool0_bytes >= POOL0_FILL || st->reseed_count == 0)
        if (enough_time_passed(st))
            reseed(st);

    /* Do some randomization on first call */
    if (!st->tricks_done)
        startup_tricks(st);

    while (count > 0)
    {
        /* produce bytes */
        encrypt_counter(st, st->result);

        /* copy result */
        if (count > CIPH_BLOCK)
            n = CIPH_BLOCK;
        else
            n = count;
        memcpy(dst, st->result, n);
        dst += n;
        count -= n;

        /* must not give out too many bytes with one key */
        block_nr++;
        if (block_nr > (RESEED_BYTES / CIPH_BLOCK))
        {
            rekey(st);
            block_nr = 0;
        }
    }
    /* Set new key for next request. */
    rekey(st);
}

void fortuna_add_entropy ( const uint8 data,
unsigned  len 
)

Definition at line 439 of file fortuna.c.

References add_entropy(), init_done, and init_state().

Referenced by px_add_entropy(), and system_reseed().

{
    if (!init_done)
    {
        init_state(&main_state);
        init_done = 1;
    }
    if (!data || !len)
        return;
    add_entropy(&main_state, data, len);
}

void fortuna_get_bytes ( unsigned  len,
uint8 dst 
)

Definition at line 452 of file fortuna.c.

References extract_data(), init_done, and init_state().

Referenced by px_get_random_bytes().

{
    if (!init_done)
    {
        init_state(&main_state);
        init_done = 1;
    }
    if (!dst || !len)
        return;
    extract_data(&main_state, len, dst);
}

static unsigned get_rand_pool ( FState st  )  [static]

Definition at line 301 of file fortuna.c.

References BLOCK, fortuna_state::key, and fortuna_state::rnd_pos.

Referenced by add_entropy().

{
    unsigned    rnd;

    /*
     * This slightly prefers lower pools - thats OK.
     */
    rnd = st->key[st->rnd_pos] % NUM_POOLS;

    st->rnd_pos++;
    if (st->rnd_pos >= BLOCK)
        st->rnd_pos = 0;

    return rnd;
}

static void inc_counter ( FState st  )  [static]

Definition at line 193 of file fortuna.c.

References fortuna_state::counter, and val.

Referenced by encrypt_counter().

{
    uint32     *val = (uint32 *) st->counter;

    if (++val[0])
        return;
    if (++val[1])
        return;
    if (++val[2])
        return;
    ++val[3];
}

static void init_state ( FState st  )  [static]

Definition at line 179 of file fortuna.c.

References i, md_init(), and fortuna_state::pool.

Referenced by fortuna_add_entropy(), and fortuna_get_bytes().

{
    int         i;

    memset(st, 0, sizeof(*st));
    for (i = 0; i < NUM_POOLS; i++)
        md_init(&st->pool[i]);
}

static void md_init ( MD_CTX *  ctx  )  [static]

Definition at line 154 of file fortuna.c.

References SHA256_Init.

Referenced by add_entropy(), init_state(), and reseed().

{
    SHA256_Init(ctx);
}

static void md_result ( MD_CTX *  ctx,
uint8 dst 
) [static]

Definition at line 166 of file fortuna.c.

References SHA256_Final.

Referenced by add_entropy(), and reseed().

{
    SHA256_CTX  tmp;

    memcpy(&tmp, ctx, sizeof(*ctx));
    SHA256_Final(dst, &tmp);
    memset(&tmp, 0, sizeof(tmp));
}

static void md_update ( MD_CTX *  ctx,
const uint8 data,
int  len 
) [static]

Definition at line 160 of file fortuna.c.

References SHA256_Update.

Referenced by add_entropy(), reseed(), and startup_tricks().

{
    SHA256_Update(ctx, data, len);
}

static void rekey ( FState st  )  [static]

Definition at line 352 of file fortuna.c.

References BLOCK, fortuna_state::ciph, CIPH_BLOCK, ciph_init(), encrypt_counter(), and fortuna_state::key.

Referenced by extract_data(), and startup_tricks().

{
    encrypt_counter(st, st->key);
    encrypt_counter(st, st->key + CIPH_BLOCK);
    ciph_init(&st->ciph, st->key, BLOCK);
}

static void reseed ( FState st  )  [static]

Definition at line 255 of file fortuna.c.

References BLOCK, buf, fortuna_state::ciph, ciph_init(), fortuna_state::key, MD_CTX, md_init(), md_result(), md_update(), fortuna_state::pool, fortuna_state::pool0_bytes, and fortuna_state::reseed_count.

Referenced by extract_data().

{
    unsigned    k;
    unsigned    n;
    MD_CTX      key_md;
    uint8       buf[BLOCK];

    /* set pool as empty */
    st->pool0_bytes = 0;

    /*
     * Both #0 and #1 reseed would use only pool 0. Just skip #0 then.
     */
    n = ++st->reseed_count;

    /*
     * The goal: use k-th pool only 1/(2^k) of the time.
     */
    md_init(&key_md);
    for (k = 0; k < NUM_POOLS; k++)
    {
        md_result(&st->pool[k], buf);
        md_update(&key_md, buf, BLOCK);

        if (n & 1 || !n)
            break;
        n >>= 1;
    }

    /* add old key into mix too */
    md_update(&key_md, st->key, BLOCK);

    /* now we have new key */
    md_result(&key_md, st->key);

    /* use new key */
    ciph_init(&st->ciph, st->key, BLOCK);

    memset(&key_md, 0, sizeof(key_md));
    memset(buf, 0, BLOCK);
}

static void startup_tricks ( FState st  )  [static]

Definition at line 366 of file fortuna.c.

References BLOCK, buf, CIPH_BLOCK, fortuna_state::counter, encrypt_counter(), i, md_update(), fortuna_state::pool, rekey(), and fortuna_state::tricks_done.

Referenced by extract_data().

{
    int         i;
    uint8       buf[BLOCK];

    /* Use next block as counter. */
    encrypt_counter(st, st->counter);

    /* Now shuffle pools, excluding #0 */
    for (i = 1; i < NUM_POOLS; i++)
    {
        encrypt_counter(st, buf);
        encrypt_counter(st, buf + CIPH_BLOCK);
        md_update(&st->pool[i], buf, BLOCK);
    }
    memset(buf, 0, BLOCK);

    /* Hide the key. */
    rekey(st);

    /* This can be done only once. */
    st->tricks_done = 1;
}


Variable Documentation

int init_done = 0 [static]

Definition at line 436 of file fortuna.c.

Referenced by fortuna_add_entropy(), and fortuna_get_bytes().

FState main_state [static]

Definition at line 435 of file fortuna.c.