aboutsummaryrefslogtreecommitdiff
path: root/contrib/pgcrypto/random.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pgcrypto/random.c')
-rw-r--r--contrib/pgcrypto/random.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/contrib/pgcrypto/random.c b/contrib/pgcrypto/random.c
new file mode 100644
index 00000000000..d72679e412d
--- /dev/null
+++ b/contrib/pgcrypto/random.c
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ *
+ * contrib/pgcrypto/random.c
+ */
+
+#include "postgres.h"
+
+#include "px.h"
+#include "utils/memdebug.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);
+
+ /* hash of uninitialized stack and heap allocations */
+ res = px_find_digest("sha1", &md);
+ if (res >= 0)
+ {
+ uint8 *ptr;
+ uint8 stack[8192];
+ int alloc = 32 * 1024;
+
+ VALGRIND_MAKE_MEM_DEFINED(stack, sizeof(stack));
+ px_md_update(md, stack, sizeof(stack));
+ ptr = px_alloc(alloc);
+ VALGRIND_MAKE_MEM_DEFINED(ptr, 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;
+}