diff options
Diffstat (limited to 'contrib/pgcrypto/random.c')
-rw-r--r-- | contrib/pgcrypto/random.c | 217 |
1 files changed, 152 insertions, 65 deletions
diff --git a/contrib/pgcrypto/random.c b/contrib/pgcrypto/random.c index 7f2f5f49258..0aa4aa2836c 100644 --- a/contrib/pgcrypto/random.c +++ b/contrib/pgcrypto/random.c @@ -1,6 +1,6 @@ /* * random.c - * Random functions. + * Acquire randomness from system. For seeding RNG. * * Copyright (c) 2001 Marko Kreen * All rights reserved. @@ -26,7 +26,7 @@ * 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 $ */ @@ -34,8 +34,20 @@ #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> @@ -64,94 +76,169 @@ safe_read(int fd, void *buf, size_t count) 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 |