diff options
Diffstat (limited to 'contrib/pgcrypto/random.c')
-rw-r--r-- | contrib/pgcrypto/random.c | 247 |
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; +} |