#
-# $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.18 2005/07/10 03:52:56 momjian Exp $
+# $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.19 2005/07/10 03:55:28 momjian Exp $
#
-# if you don't have OpenSSL, you can use libc random() or /dev/urandom
-INT_CFLAGS = -DRAND_SILLY
-#INT_CFLAGS = -DRAND_DEV=\"/dev/urandom\"
-
-INT_SRCS = md5.c sha1.c sha2.c internal.c blf.c rijndael.c
+INT_SRCS = md5.c sha1.c sha2.c internal.c blf.c rijndael.c \
+ fortuna.c random.c
INT_TESTS = sha2
-OSSL_CFLAGS = -DRAND_OPENSSL
OSSL_SRCS = openssl.c
OSSL_TESTS = des 3des cast5
CF_SRCS = $(if $(subst no,,$(with_openssl)), $(OSSL_SRCS), $(INT_SRCS))
CF_TESTS = $(if $(subst no,,$(with_openssl)), $(OSSL_TESTS), $(INT_TESTS))
-CF_CFLAGS = $(if $(subst no,,$(with_openssl)), $(OSSL_CFLAGS), $(INT_CFLAGS))
+CF_CFLAGS =
PG_CPPFLAGS = $(CF_CFLAGS)
-SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c misc.c random.c \
+SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c misc.c \
crypt-gensalt.c crypt-blowfish.c crypt-des.c \
crypt-md5.c $(CF_SRCS)
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.17 2005/07/10 03:52:56 momjian Exp $
+ * $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.18 2005/07/10 03:55:28 momjian Exp $
*/
#include <postgres.h>
+#include <time.h>
#include "px.h"
#include "sha2.h"
#include "blf.h"
#include "rijndael.h"
+#include "fortuna.h"
+
+/*
+ * How often to try to acquire system entropy. (In seconds)
+ */
+#define SYSTEM_RESEED_FREQ (3*60*60)
+
#ifndef MD5_DIGEST_LENGTH
#define MD5_DIGEST_LENGTH 16
*res = c;
return 0;
}
+
+/*
+ * Randomness provider
+ */
+
+/*
+ * 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;
+static void system_reseed()
+{
+ uint8 buf[1024];
+ int n;
+ time_t t;
+
+ t = time(NULL);
+ if (seed_time && (t - seed_time) < SYSTEM_RESEED_FREQ)
+ return;
+
+ n = px_acquire_system_randomness(buf);
+ if (n > 0)
+ fortuna_add_entropy(SYSTEM_ENTROPY, buf, n);
+
+ seed_time = t;
+}
+
+int
+px_get_random_bytes(uint8 *dst, unsigned count)
+{
+ system_reseed();
+ fortuna_get_bytes(count, dst);
+ return 0;
+}
+
+int
+px_add_entropy(const uint8 *data, unsigned count)
+{
+ system_reseed();
+ fortuna_add_entropy(USER_ENTROPY, data, count);
+ return 0;
+}
+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.20 2005/07/05 18:15:36 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.21 2005/07/10 03:55:28 momjian Exp $
*/
#include <postgres.h>
#include <openssl/blowfish.h>
#include <openssl/cast.h>
#include <openssl/des.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+
/*
* Does OpenSSL support AES?
*res = c;
return 0;
}
+
+
+static int openssl_random_init = 0;
+
+/*
+ * OpenSSL random should re-feeded occasionally. From /dev/urandom
+ * preferably.
+ */
+static void init_openssl_rand()
+{
+ if (RAND_get_rand_method() == NULL)
+ RAND_set_rand_method(RAND_SSLeay());
+ openssl_random_init = 1;
+}
+
+int
+px_get_random_bytes(uint8 *dst, unsigned count)
+{
+ int res;
+
+ if (!openssl_random_init)
+ init_openssl_rand();
+
+ res = RAND_bytes(dst, count);
+ if (res == 1)
+ return count;
+
+ return PXE_OSSL_RAND_ERROR;
+}
+
+int
+px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
+{
+ int res;
+
+ if (!openssl_random_init)
+ init_openssl_rand();
+
+ res = RAND_pseudo_bytes(dst, count);
+ if (res == 0 || res == 1)
+ return count;
+
+ return PXE_OSSL_RAND_ERROR;
+}
+
+int
+px_add_entropy(const uint8 *data, unsigned count)
+{
+ /*
+ * estimate 0 bits
+ */
+ RAND_add(data, count, 0);
+ return 0;
+}
+
/*
* random.c
- * Random functions.
+ * Acquire randomness from system. For seeding RNG.
*
* Copyright (c) 2001 Marko Kreen
* All rights reserved.
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $PostgreSQL: pgsql/contrib/pgcrypto/random.c,v 1.10 2005/03/21 05:22:14 neilc Exp $
+ * $PostgreSQL: pgsql/contrib/pgcrypto/random.c,v 1.11 2005/07/10 03:55:28 momjian Exp $
*/
#include "px.h"
+/* how many bytes to ask from system random provider */
+#define RND_BYTES 32
-#if defined(RAND_DEV)
+/*
+ * 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__)
+
+#define TRY_DEV_RANDOM
#include <errno.h>
#include <fcntl.h>
return done;
}
-int
-px_get_random_bytes(uint8 *dst, unsigned count)
+static uint8 *
+try_dev_random(uint8 *dst)
{
int fd;
int res;
- fd = open(RAND_DEV, O_RDONLY);
+ fd = open("/dev/urandom", O_RDONLY);
if (fd == -1)
- return PXE_DEV_READ_ERROR;
- res = safe_read(fd, dst, count);
+ {
+ fd = open("/dev/random", O_RDONLY);
+ if (fd == -1)
+ return dst;
+ }
+ res = safe_read(fd, dst, RND_BYTES);
close(fd);
- return res;
+ if (res > 0)
+ dst += res;
+ return dst;
}
-int
-px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
-{
- return px_get_random_bytes(dst, count);
-}
+#endif
-#elif defined(RAND_SILLY)
+/*
+ * Try to find randomness on Windows
+ */
+#ifdef WIN32
-int
-px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
-{
- int i;
+#define TRY_WIN32_GENRAND
+#define TRY_WIN32_PERFC
- for (i = 0; i < count; i++)
- *dst++ = random();
- return i;
-}
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+#include <wincrypt.h>
-int
-px_get_random_bytes(uint8 *dst, unsigned count)
+/*
+ * this function is from libtomcrypt
+ *
+ * try to use Microsoft crypto API
+ */
+static uint8 * try_win32_genrand(uint8 *dst)
{
- return PXE_NO_RANDOM;
+ 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, NUM_BYTES, dst);
+ if (res == TRUE)
+ dst += len;
+
+ CryptReleaseContext(h, 0);
+ return dst;
}
-#elif defined(RAND_OPENSSL)
-
-#include <openssl/evp.h>
-#include <openssl/blowfish.h>
-#include <openssl/rand.h>
-#include <openssl/err.h>
+static uint8 * try_win32_perfc(uint8 *dst)
+{
+ int res;
+ LARGE_INTEGER time;
-static int openssl_random_init = 0;
+ res = QueryPerformanceCounter(&time);
+ if (!res)
+ return dst;
-/*
- * OpenSSL random should re-feeded occasionally. From /dev/urandom
- * preferably.
- */
-static void init_openssl()
-{
- if (RAND_get_rand_method() == NULL)
- RAND_set_rand_method(RAND_SSLeay());
- openssl_random_init = 1;
+ memcpy(dst, &time, sizeof(time));
+ return dst + sizeof(time);
}
-int
-px_get_random_bytes(uint8 *dst, unsigned count)
-{
- int res;
+#endif /* WIN32 */
- if (!openssl_random_init)
- init_openssl();
- res = RAND_bytes(dst, count);
- if (res == 1)
- return count;
+/*
+ * If we are not on Windows, then hopefully we are
+ * on a unix-like system. Use the usual suspects
+ * for randomness.
+ */
+#ifndef WIN32
- return PXE_OSSL_RAND_ERROR;
-}
+#define TRY_UNIXSTD
-int
-px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
+#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)
{
- int res;
+ 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;
+ }
- if (!openssl_random_init)
- init_openssl();
+ return dst;
+}
- res = RAND_pseudo_bytes(dst, count);
- if (res == 0 || res == 1)
- return count;
+#endif
- return PXE_OSSL_RAND_ERROR;
+/*
+ * 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;
}
-#else
-#error "Invalid random source"
-#endif