| /* |
| * 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" |
| |
| /* 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; |
| } |