* Use Fortuna for pseudo-random bytes too, as those need to
be high-quality also. OpenSSL internally acts same way.
* Clarify add_entropy logic - before first reseed get_rand_pool()
will return only 0, so make it explicit.
* On reseeding on first request, don't check if the pool#0 is
filled, use whatever is available.
* The counter value is already randomized, to avoid known state.
Do the same with pools. Thus no publicly known values in state.
Index: pgsql/contrib/pgcrypto/internal.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/internal.c
--- pgsql/contrib/pgcrypto/internal.c
*************** px_find_cipher(const char *name, PX_Ciph
*** 821,839 ****
*/
/*
! * Use libc for all 'public' bytes.
! *
! * That way we don't expose bytes from Fortuna
! * to the public, in case it has some bugs.
*/
int
px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
{
! int i;
!
! for (i = 0; i < count; i++)
! *dst++ = random();
! return i;
}
static time_t seed_time = 0;
--- 821,832 ----
*/
/*
! * Use always strong randomness.
*/
int
px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
{
! return px_get_random_bytes(dst, count);
}
static time_t seed_time = 0;
Index: pgsql/contrib/pgcrypto/fortuna.c
===================================================================
*** pgsql.orig/contrib/pgcrypto/fortuna.c
--- pgsql/contrib/pgcrypto/fortuna.c
*************** struct fortuna_state
*** 125,131 ****
struct timeval last_reseed_time;
unsigned pool0_bytes;
unsigned rnd_pos;
! int counter_init;
};
typedef struct fortuna_state FState;
--- 125,131 ----
struct timeval last_reseed_time;
unsigned pool0_bytes;
unsigned rnd_pos;
! int tricks_done;
};
typedef struct fortuna_state FState;
*************** add_entropy(FState * st, const uint8 *da
*** 332,338 ****
/*
* Make sure the pool 0 is initialized, then update randomly.
*/
! if (st->reseed_count == 0 && st->pool0_bytes < POOL0_FILL)
pos = 0;
else
pos = get_rand_pool(st);
--- 332,338 ----
/*
* Make sure the pool 0 is initialized, then update randomly.
*/
! if (st->reseed_count == 0)
pos = 0;
else
pos = get_rand_pool(st);
*************** rekey(FState * st)
*** 357,377 ****
}
/*
! * Fortuna relies on AES standing known-plaintext attack.
! * In case it does not, slow down the attacker by initialising
! * the couter to random value.
*/
static void
! init_counter(FState * st)
{
/* Use next block as counter. */
encrypt_counter(st, st->counter);
/* Hide the key. */
rekey(st);
! /* The counter can be shuffled only once. */
! st->counter_init = 1;
}
static void
--- 357,390 ----
}
/*
! * Hide public constants. (counter, pools > 0)
! *
! * This can also be viewed as spreading the startup
! * entropy over all of the components.
*/
static void
! startup_tricks(FState * st)
{
+ 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;
}
static void
*************** extract_data(FState * st, unsigned count
*** 380,392 ****
unsigned n;
unsigned block_nr = 0;
! /* Can we reseed? */
! if (st->pool0_bytes >= POOL0_FILL && enough_time_passed(st))
! reseed(st);
!
! /* Is counter initialized? */
! if (!st->counter_init)
! init_counter(st);
while (count > 0)
{
--- 393,406 ----
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)
{
--