mirror of https://github.com/postgres/postgres
- Add Fortuna PRNG to pgcrypto.
- Move openssl random provider to openssl.c and builtin provider to internal.c - Make px_random_bytes use Fortuna, instead of giving error. - Retarget random.c to aquiring system randomness, for initial seeding of Fortuna. There is ATM 2 functions for Windows, reader from /dev/urandom and the regular time()/getpid() silliness. Marko Kreen
This commit is contained in:
parent
248eeb82f0
commit
4fcf8b11ff
|
@ -1,25 +1,21 @@
|
|||
#
|
||||
# $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.18 2005/07/10 03:52:56 momjian Exp $
|
||||
# $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.19 2005/07/10 03:55:28 momjian Exp $
|
||||
#
|
||||
|
||||
# if you don't have OpenSSL, you can use libc random() or /dev/urandom
|
||||
INT_CFLAGS = -DRAND_SILLY
|
||||
#INT_CFLAGS = -DRAND_DEV=\"/dev/urandom\"
|
||||
|
||||
INT_SRCS = md5.c sha1.c sha2.c internal.c blf.c rijndael.c
|
||||
INT_SRCS = md5.c sha1.c sha2.c internal.c blf.c rijndael.c \
|
||||
fortuna.c random.c
|
||||
INT_TESTS = sha2
|
||||
|
||||
OSSL_CFLAGS = -DRAND_OPENSSL
|
||||
OSSL_SRCS = openssl.c
|
||||
OSSL_TESTS = des 3des cast5
|
||||
|
||||
CF_SRCS = $(if $(subst no,,$(with_openssl)), $(OSSL_SRCS), $(INT_SRCS))
|
||||
CF_TESTS = $(if $(subst no,,$(with_openssl)), $(OSSL_TESTS), $(INT_TESTS))
|
||||
CF_CFLAGS = $(if $(subst no,,$(with_openssl)), $(OSSL_CFLAGS), $(INT_CFLAGS))
|
||||
CF_CFLAGS =
|
||||
|
||||
PG_CPPFLAGS = $(CF_CFLAGS)
|
||||
|
||||
SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c misc.c random.c \
|
||||
SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c misc.c \
|
||||
crypt-gensalt.c crypt-blowfish.c crypt-des.c \
|
||||
crypt-md5.c $(CF_SRCS)
|
||||
|
||||
|
|
|
@ -26,11 +26,12 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.17 2005/07/10 03:52:56 momjian Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.18 2005/07/10 03:55:28 momjian Exp $
|
||||
*/
|
||||
|
||||
|
||||
#include <postgres.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "px.h"
|
||||
|
||||
|
@ -39,6 +40,13 @@
|
|||
#include "sha2.h"
|
||||
#include "blf.h"
|
||||
#include "rijndael.h"
|
||||
#include "fortuna.h"
|
||||
|
||||
/*
|
||||
* How often to try to acquire system entropy. (In seconds)
|
||||
*/
|
||||
#define SYSTEM_RESEED_FREQ (3*60*60)
|
||||
|
||||
|
||||
#ifndef MD5_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
|
@ -784,3 +792,58 @@ px_find_cipher(const char *name, PX_Cipher ** res)
|
|||
*res = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Randomness provider
|
||||
*/
|
||||
|
||||
/*
|
||||
* Use libc for all 'public' bytes.
|
||||
*
|
||||
* That way we don't expose bytes from Fortuna
|
||||
* to the public, in case it has some bugs.
|
||||
*/
|
||||
int
|
||||
px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
*dst++ = random();
|
||||
return i;
|
||||
}
|
||||
|
||||
static time_t seed_time = 0;
|
||||
static void system_reseed()
|
||||
{
|
||||
uint8 buf[1024];
|
||||
int n;
|
||||
time_t t;
|
||||
|
||||
t = time(NULL);
|
||||
if (seed_time && (t - seed_time) < SYSTEM_RESEED_FREQ)
|
||||
return;
|
||||
|
||||
n = px_acquire_system_randomness(buf);
|
||||
if (n > 0)
|
||||
fortuna_add_entropy(SYSTEM_ENTROPY, buf, n);
|
||||
|
||||
seed_time = t;
|
||||
}
|
||||
|
||||
int
|
||||
px_get_random_bytes(uint8 *dst, unsigned count)
|
||||
{
|
||||
system_reseed();
|
||||
fortuna_get_bytes(count, dst);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
px_add_entropy(const uint8 *data, unsigned count)
|
||||
{
|
||||
system_reseed();
|
||||
fortuna_add_entropy(USER_ENTROPY, data, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.20 2005/07/05 18:15:36 tgl Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.21 2005/07/10 03:55:28 momjian Exp $
|
||||
*/
|
||||
|
||||
#include <postgres.h>
|
||||
|
@ -37,6 +37,9 @@
|
|||
#include <openssl/blowfish.h>
|
||||
#include <openssl/cast.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
|
||||
/*
|
||||
* Does OpenSSL support AES?
|
||||
|
@ -759,3 +762,58 @@ px_find_cipher(const char *name, PX_Cipher ** res)
|
|||
*res = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int openssl_random_init = 0;
|
||||
|
||||
/*
|
||||
* OpenSSL random should re-feeded occasionally. From /dev/urandom
|
||||
* preferably.
|
||||
*/
|
||||
static void init_openssl_rand()
|
||||
{
|
||||
if (RAND_get_rand_method() == NULL)
|
||||
RAND_set_rand_method(RAND_SSLeay());
|
||||
openssl_random_init = 1;
|
||||
}
|
||||
|
||||
int
|
||||
px_get_random_bytes(uint8 *dst, unsigned count)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!openssl_random_init)
|
||||
init_openssl_rand();
|
||||
|
||||
res = RAND_bytes(dst, count);
|
||||
if (res == 1)
|
||||
return count;
|
||||
|
||||
return PXE_OSSL_RAND_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!openssl_random_init)
|
||||
init_openssl_rand();
|
||||
|
||||
res = RAND_pseudo_bytes(dst, count);
|
||||
if (res == 0 || res == 1)
|
||||
return count;
|
||||
|
||||
return PXE_OSSL_RAND_ERROR;
|
||||
}
|
||||
|
||||
int
|
||||
px_add_entropy(const uint8 *data, unsigned count)
|
||||
{
|
||||
/*
|
||||
* estimate 0 bits
|
||||
*/
|
||||
RAND_add(data, count, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/px.h,v 1.12 2005/03/21 05:22:14 neilc Exp $
|
||||
* $PostgreSQL: pgsql/contrib/pgcrypto/px.h,v 1.13 2005/07/10 03:55:28 momjian Exp $
|
||||
*/
|
||||
|
||||
#ifndef __PX_H
|
||||
|
@ -170,6 +170,9 @@ int px_find_combo(const char *name, PX_Combo ** res);
|
|||
|
||||
int px_get_random_bytes(uint8 *dst, unsigned count);
|
||||
int px_get_pseudo_random_bytes(uint8 *dst, unsigned count);
|
||||
int px_add_entropy(const uint8 *data, unsigned count);
|
||||
|
||||
unsigned px_acquire_system_randomness(uint8 *dst);
|
||||
|
||||
const char *px_strerror(int err);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
#elif defined(RAND_SILLY)
|
||||
|
||||
int
|
||||
px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
*dst++ = random();
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
px_get_random_bytes(uint8 *dst, unsigned count)
|
||||
{
|
||||
return PXE_NO_RANDOM;
|
||||
}
|
||||
|
||||
#elif defined(RAND_OPENSSL)
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
static int openssl_random_init = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* OpenSSL random should re-feeded occasionally. From /dev/urandom
|
||||
* preferably.
|
||||
* Try to find randomness on Windows
|
||||
*/
|
||||
static void init_openssl()
|
||||
#ifdef WIN32
|
||||
|
||||
#define TRY_WIN32_GENRAND
|
||||
#define TRY_WIN32_PERFC
|
||||
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
/*
|
||||
* this function is from libtomcrypt
|
||||
*
|
||||
* try to use Microsoft crypto API
|
||||
*/
|
||||
static uint8 * try_win32_genrand(uint8 *dst)
|
||||
{
|
||||
if (RAND_get_rand_method() == NULL)
|
||||
RAND_set_rand_method(RAND_SSLeay());
|
||||
openssl_random_init = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
px_get_random_bytes(uint8 *dst, unsigned count)
|
||||
static uint8 * try_win32_perfc(uint8 *dst)
|
||||
{
|
||||
int res;
|
||||
int res;
|
||||
LARGE_INTEGER time;
|
||||
|
||||
if (!openssl_random_init)
|
||||
init_openssl();
|
||||
res = QueryPerformanceCounter(&time);
|
||||
if (!res)
|
||||
return dst;
|
||||
|
||||
res = RAND_bytes(dst, count);
|
||||
if (res == 1)
|
||||
return count;
|
||||
|
||||
return PXE_OSSL_RAND_ERROR;
|
||||
memcpy(dst, &time, sizeof(time));
|
||||
return dst + sizeof(time);
|
||||
}
|
||||
|
||||
int
|
||||
px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
|
||||
#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)
|
||||
{
|
||||
int res;
|
||||
pid_t pid;
|
||||
int x;
|
||||
PX_MD *md;
|
||||
struct timeval tv;
|
||||
int res;
|
||||
|
||||
if (!openssl_random_init)
|
||||
init_openssl();
|
||||
/* process id */
|
||||
pid = getpid();
|
||||
memcpy(dst, (uint8*)&pid, sizeof(pid));
|
||||
dst += sizeof(pid);
|
||||
|
||||
res = RAND_pseudo_bytes(dst, count);
|
||||
if (res == 0 || res == 1)
|
||||
return count;
|
||||
/* time */
|
||||
gettimeofday(&tv, NULL);
|
||||
memcpy(dst, (uint8*)&tv, sizeof(tv));
|
||||
dst += sizeof(tv);
|
||||
|
||||
return PXE_OSSL_RAND_ERROR;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Invalid random source"
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue