* 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)
        {

--

---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to