[patch 2/9] Fortuna tweaks - Mailing list pgsql-patches

From Marko Kreen
Subject [patch 2/9] Fortuna tweaks
Date
Msg-id 20060711195802.524821000@localhost.localdomain
Whole thread Raw
List pgsql-patches
* 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)
      {

--

pgsql-patches by date:

Previous
From: "Marko Kreen"
Date:
Subject: small entab cleanup
Next
From: Marko Kreen
Date:
Subject: [patch 5/9] uninstall script