Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions

random.c

/*
 * random.c
 *          Acquire randomness from system.  For seeding RNG.
 *
 * Copyright (c) 2001 Marko Kreen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.      IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $PostgreSQL: pgsql/contrib/pgcrypto/random.c,v 1.17 2006/06/08 03:29:30 momjian Exp $
 */

#include "postgres.h"

#include "px.h"

/* how many bytes to ask from system random provider */
#define RND_BYTES  32

/*
 * Try to read from /dev/urandom or /dev/random on these OS'es.
 *
 * The list can be pretty liberal, as the device not existing
 * is expected event.
 */
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
      || defined(__NetBSD__) || defined(__DragonFly__) \
      || defined(__darwin__) || defined(__SOLARIS__) \
      || defined(__hpux) || defined(__HPUX__) \
      || defined(__CYGWIN__) || defined(_AIX)

#define TRY_DEV_RANDOM

#include <fcntl.h>
#include <unistd.h>

static int
safe_read(int fd, void *buf, size_t count)
{
      int               done = 0;
      char     *p = buf;
      int               res;

      while (count)
      {
            res = read(fd, p, count);
            if (res <= 0)
            {
                  if (errno == EINTR)
                        continue;
                  return PXE_DEV_READ_ERROR;
            }
            p += res;
            done += res;
            count -= res;
      }
      return done;
}

static uint8 *
try_dev_random(uint8 *dst)
{
      int               fd;
      int               res;

      fd = open("/dev/urandom", O_RDONLY, 0);
      if (fd == -1)
      {
            fd = open("/dev/random", O_RDONLY, 0);
            if (fd == -1)
                  return dst;
      }
      res = safe_read(fd, dst, RND_BYTES);
      close(fd);
      if (res > 0)
            dst += res;
      return dst;
}
#endif

/*
 * Try to find randomness on Windows
 */
#ifdef WIN32

#define TRY_WIN32_GENRAND
#define TRY_WIN32_PERFC

#include <windows.h>
#include <wincrypt.h>

/*
 * this function is from libtomcrypt
 *
 * try to use Microsoft crypto API
 */
static uint8 *
try_win32_genrand(uint8 *dst)
{
      int               res;
      HCRYPTPROV  h = 0;

      res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
                                            (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET));
      if (!res)
            res = CryptAcquireContext(&h, NULL, MS_DEF_PROV, PROV_RSA_FULL,
                     CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET);
      if (!res)
            return dst;

      res = CryptGenRandom(h, RND_BYTES, dst);
      if (res == TRUE)
            dst += RND_BYTES;

      CryptReleaseContext(h, 0);
      return dst;
}

static uint8 *
try_win32_perfc(uint8 *dst)
{
      int               res;
      LARGE_INTEGER time;

      res = QueryPerformanceCounter(&time);
      if (!res)
            return dst;

      memcpy(dst, &time, sizeof(time));
      return dst + sizeof(time);
}
#endif   /* WIN32 */


/*
 * If we are not on Windows, then hopefully we are
 * on a unix-like system.  Use the usual suspects
 * for randomness.
 */
#ifndef WIN32

#define TRY_UNIXSTD

#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

/*
 * Everything here is predictible, only needs some patience.
 *
 * But there is a chance that the system-specific functions
 * did not work.  So keep faith and try to slow the attacker down.
 */
static uint8 *
try_unix_std(uint8 *dst)
{
      pid_t       pid;
      int               x;
      PX_MD    *md;
      struct timeval tv;
      int               res;

      /* process id */
      pid = getpid();
      memcpy(dst, (uint8 *) &pid, sizeof(pid));
      dst += sizeof(pid);

      /* time */
      gettimeofday(&tv, NULL);
      memcpy(dst, (uint8 *) &tv, sizeof(tv));
      dst += sizeof(tv);

      /* pointless, but should not hurt */
      x = random();
      memcpy(dst, (uint8 *) &x, sizeof(x));
      dst += sizeof(x);

      /* let's be desperate */
      res = px_find_digest("sha1", &md);
      if (res >= 0)
      {
            uint8    *ptr;
            uint8       stack[8192];
            int               alloc = 32 * 1024;

            px_md_update(md, stack, sizeof(stack));
            ptr = px_alloc(alloc);
            px_md_update(md, ptr, alloc);
            px_free(ptr);

            px_md_finish(md, dst);
            px_md_free(md);

            dst += 20;
      }

      return dst;
}
#endif

/*
 * try to extract some randomness for initial seeding
 *
 * dst should have room for 1024 bytes.
 */
unsigned
px_acquire_system_randomness(uint8 *dst)
{
      uint8    *p = dst;

#ifdef TRY_DEV_RANDOM
      p = try_dev_random(p);
#endif
#ifdef TRY_WIN32_GENRAND
      p = try_win32_genrand(p);
#endif
#ifdef TRY_WIN32_PERFC
      p = try_win32_perfc(p);
#endif
#ifdef TRY_UNIXSTD
      p = try_unix_std(p);
#endif
      return p - dst;
}

Generated by  Doxygen 1.6.0   Back to index