232 lines
5.5 KiB
C++
232 lines
5.5 KiB
C++
/*
|
|
* 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 "knl/knl_variable.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 = (char*)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 = NULL;
|
|
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 = NULL;
|
|
uint8 stack[8192];
|
|
int alloc = 32 * 1024;
|
|
|
|
px_md_update(md, stack, sizeof(stack));
|
|
ptr = (uint8*)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;
|
|
}
|