[patch 2/2] Fortuna PRNG - Mailing list pgsql-patches
From | Marko Kreen |
---|---|
Subject | [patch 2/2] Fortuna PRNG |
Date | |
Msg-id | 20050708175510.782545000@grue Whole thread Raw |
In response to | [patch 0/2] Add Fortuna PRNG to pgcrypto (Marko Kreen <marko@l-t.ee>) |
Responses |
Re: [patch 2/2] Fortuna PRNG
|
List | pgsql-patches |
- 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. Index: pgsql/contrib/pgcrypto/fortuna.c =================================================================== *** /dev/null --- pgsql/contrib/pgcrypto/fortuna.c *************** *** 0 **** --- 1,365 ---- + /* + * fortuna.c + * Fortuna-like PRNG. + * + * Copyright (c) 2005 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. + * + * $PostgreSQL$ + */ + + #include <postgres.h> + #include <sys/time.h> + #include <time.h> + + #include "rijndael.h" + #include "sha2.h" + + #include "fortuna.h" + + + /* + * Why Fortuna-like: There does not seem to be any definitive reference + * on Fortuna in the net. Instead this implementation is based on + * following references: + * + * http://en.wikipedia.org/wiki/Fortuna_(PRNG) + * - Wikipedia article + * http://jlcooke.ca/random/ + * - Jean-Luc Cooke Fortuna-based /dev/random driver for Linux. + */ + + /* + * There is some confusion about whether and how to carry forward + * the state of the pools. Seems like original Fortuna does not + * do it, resetting hash after each request. I guess expecting + * feeding to happen more often that requesting. This is absolutely + * unsuitable for pgcrypto, as nothing asynchronous happens here. + * + * J.L. Cooke fixed this by feeding previous hash to new re-initialized + * hash context. + * + * Fortuna predecessor Yarrow requires ability to query intermediate + * 'final result' from hash, without affecting it. + * + * This implementation uses the Yarrow method - asking intermediate + * results, but continuing with old state. + */ + + + /* + * Algorithm parameters + */ + + /* + * How many pools. + * + * Original Fortuna uses 32 pools, that means 32'th pool is + * used not earlier than in 13th year. This is a waste in + * pgcrypto, as we have very low-frequancy seeding. Here + * is preferable to have all entropy usable in reasonable time. + * + * With 23 pools, 23th pool is used after 9 days which seems + * more sane. + * + * In our case the minimal cycle time would be bit longer + * than the system-randomness feeding frequency. + */ + #define NUM_POOLS 23 + + /* in microseconds */ + #define RESEED_INTERVAL 100000 /* 0.1 sec */ + + /* for one big request, reseed after this many bytes */ + #define RESEED_BYTES (1024*1024) + + + /* + * Algorithm constants + */ + + /* max sources */ + #define MAX_SOURCES 8 + + /* Both cipher key size and hash result size */ + #define BLOCK 32 + + /* cipher block size */ + #define CIPH_BLOCK 16 + + /* for internal wrappers */ + #define MD_CTX SHA256_CTX + #define CIPH_CTX rijndael_ctx + + struct fortuna_state { + uint8 counter[CIPH_BLOCK]; + uint8 result[CIPH_BLOCK]; + uint8 key[BLOCK]; + MD_CTX pool[NUM_POOLS]; + CIPH_CTX ciph; + unsigned source_pos[MAX_SOURCES]; + unsigned reseed_count; + struct timeval last_reseed_time; + }; + typedef struct fortuna_state FState; + + + /* + * Use our own wrappers here. + * - Need to get intermediate result from digest, without affecting it. + * - Need re-set key on a cipher context. + * - Algorithms are guaranteed to exist. + * - No memory allocations. + */ + + static void ciph_init(CIPH_CTX *ctx, const uint8 *key, int klen) + { + rijndael_set_key(ctx, (const uint32 *)key, klen, 1); + } + + static void ciph_encrypt(CIPH_CTX *ctx, const uint8 *in, uint8 *out) + { + rijndael_encrypt(ctx, (const uint32 *)in, (uint32 *)out); + } + + static void md_init(MD_CTX *ctx) + { + SHA256_Init(ctx); + } + + static void md_update(MD_CTX *ctx, const uint8 *data, int len) + { + SHA256_Update(ctx, data, len); + } + + static void md_result(MD_CTX *ctx, uint8 *dst) + { + SHA256_CTX tmp; + memcpy(&tmp, ctx, sizeof(*ctx)); + SHA256_Final(dst, &tmp); + memset(&tmp, 0, sizeof(tmp)); + } + + + /* + * initialize state + */ + static void init_state(FState *st) + { + int i; + memset(st, 0, sizeof(*st)); + for (i = 0; i < NUM_POOLS; i++) + md_init(&st->pool[i]); + } + + /* + * Must not reseed more ofter than RESEED_PER_SEC + * times per second. + */ + static int too_often(FState *st) + { + int ok; + struct timeval tv; + struct timeval *last = &st->last_reseed_time; + + gettimeofday(&tv, NULL); + + ok = 0; + if (tv.tv_sec != last->tv_sec) + ok = 1; + else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) + ok = 1; + + memcpy(last, &tv, sizeof(tv)); + memset(&tv, 0, sizeof(tv)); + + return ok; + } + + /* + * generate new key from all the pools + */ + static void reseed(FState *st) + { + unsigned k; + unsigned n; + MD_CTX key_md; + uint8 buf[BLOCK]; + + /* check frequency */ + if (too_often(st)) + return; + + /* + * Both #0 and #1 reseed would use only pool 0. + * Just skip #0 then. + */ + n = ++st->reseed_count; + + /* + * The goal: use k-th pool only 1/(2^k) of the time. + */ + md_init(&key_md); + for (k = 0; k < NUM_POOLS; k++) { + md_result(&st->pool[k], buf); + md_update(&key_md, buf, BLOCK); + + if (n & 1 || !n) + break; + n >>= 1; + } + + /* add old key into mix too */ + md_update(&key_md, st->key, BLOCK); + + /* now we have new key */ + md_result(&key_md, st->key); + + /* use new key */ + ciph_init(&st->ciph, st->key, BLOCK); + + memset(&key_md, 0, sizeof(key_md)); + memset(buf, 0, BLOCK); + n = k = 0; + } + + /* + * update pools + */ + static void add_entropy(FState *st, unsigned src_id, const uint8 *data, unsigned len) + { + unsigned pos; + uint8 hash[BLOCK]; + MD_CTX md; + + /* just in case there's a bug somewhere */ + if (src_id >= MAX_SOURCES) + src_id = USER_ENTROPY; + + /* hash given data */ + md_init(&md); + md_update(&md, data, len); + md_result(&md, hash); + + /* update pools round-robin manner */ + pos = st->source_pos[src_id]; + md_update( &st->pool[pos], hash, BLOCK); + + if (++pos >= NUM_POOLS) + pos = 0; + st->source_pos[src_id] = pos; + + memset(hash, 0, BLOCK); + memset(&md, 0, sizeof(md)); + } + + /* + * Endianess does not matter. + * It just needs to change without repeating. + */ + static void inc_counter(FState *st) + { + uint32 *val = (uint32*)st->counter; + if (++val[0]) + return; + if (++val[1]) + return; + if (++val[2]) + return; + ++val[3]; + } + + static void extract_data(FState *st, unsigned count, uint8 *dst) + { + unsigned n; + unsigned block_nr = 0; + + /* + * Every request should be with different key, + * if possible. + */ + reseed(st); + + /* + * If the reseed didn't happen, don't use the old data + * rather encrypt again. + */ + + while (count > 0) { + /* must not give out too many bytes with one key */ + if (block_nr > (RESEED_BYTES / CIPH_BLOCK)) + { + reseed(st); + block_nr = 0; + } + + /* produce bytes */ + ciph_encrypt(&st->ciph, st->counter, st->result); + block_nr++; + + /* prepare for next time */ + inc_counter(st); + + /* copy result */ + if (count > CIPH_BLOCK) + n = CIPH_BLOCK; + else + n = count; + memcpy(dst, st->result, n); + dst += n; + count -= n; + } + } + + /* + * public interface + */ + + static FState main_state; + static int init_done = 0; + + void fortuna_add_entropy(unsigned src_id, const uint8 *data, unsigned len) + { + if (!init_done) + { + init_state(&main_state); + init_done = 1; + } + if (!data || !len) + return; + add_entropy(&main_state, src_id, data, len); + } + + void fortuna_get_bytes(unsigned len, uint8 *dst) + { + if (!init_done) + { + init_state(&main_state); + init_done = 1; + } + if (!dst || !len) + return; + extract_data(&main_state, len, dst); + } + Index: pgsql/contrib/pgcrypto/fortuna.h =================================================================== *** /dev/null --- pgsql/contrib/pgcrypto/fortuna.h *************** *** 0 **** --- 1,45 ---- + /* + * fortuna.c + * Fortuna PRNG. + * + * Copyright (c) 2005 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. + * + * $PostgreSQL$ + */ + + #ifndef __FORTUNA_H + #define __FORTUNA_H + + /* + * Event source ID's + */ + #define SYSTEM_ENTROPY 0 + #define USER_ENTROPY 1 + + void fortuna_get_bytes(unsigned len, uint8 *dst); + void fortuna_add_entropy(unsigned src_id, const uint8 *data, unsigned len); + + #endif + Index: pgsql/contrib/pgcrypto/Makefile =================================================================== *** pgsql.orig/contrib/pgcrypto/Makefile --- pgsql/contrib/pgcrypto/Makefile *************** *** 2,25 **** # $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.16 2005/07/05 23:18:44 tgl 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_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)) PG_CPPFLAGS = $(CF_CFLAGS) ! SRCS = pgcrypto.c px.c px-hmac.c px-crypt.c misc.c random.c \ crypt-gensalt.c crypt-blowfish.c crypt-des.c \ crypt-md5.c $(CF_SRCS) --- 2,21 ---- # $PostgreSQL: pgsql/contrib/pgcrypto/Makefile,v 1.16 2005/07/05 23:18:44 tgl Exp $ # ! INT_SRCS = md5.c sha1.c sha2.c internal.c blf.c rijndael.c \ ! fortuna.c random.c INT_TESTS = sha2 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 = PG_CPPFLAGS = $(CF_CFLAGS) ! 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) Index: pgsql/contrib/pgcrypto/internal.c =================================================================== *** pgsql.orig/contrib/pgcrypto/internal.c --- pgsql/contrib/pgcrypto/internal.c *************** *** 31,36 **** --- 31,37 ---- #include <postgres.h> + #include <time.h> #include "px.h" *************** *** 39,44 **** --- 40,52 ---- #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 *************** px_find_cipher(const char *name, PX_Ciph *** 784,786 **** --- 792,849 ---- *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; + } + Index: pgsql/contrib/pgcrypto/openssl.c =================================================================== *** pgsql.orig/contrib/pgcrypto/openssl.c --- pgsql/contrib/pgcrypto/openssl.c *************** *** 37,42 **** --- 37,45 ---- #include <openssl/blowfish.h> #include <openssl/cast.h> #include <openssl/des.h> + #include <openssl/rand.h> + #include <openssl/err.h> + /* * Does OpenSSL support AES? *************** px_find_cipher(const char *name, PX_Ciph *** 759,761 **** --- 762,819 ---- *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; + } + Index: pgsql/contrib/pgcrypto/px.h =================================================================== *** pgsql.orig/contrib/pgcrypto/px.h --- pgsql/contrib/pgcrypto/px.h *************** int px_find_combo(const char *name, PX *** 170,175 **** --- 170,178 ---- 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); Index: pgsql/contrib/pgcrypto/random.c =================================================================== *** pgsql.orig/contrib/pgcrypto/random.c --- pgsql/contrib/pgcrypto/random.c *************** *** 1,6 **** /* * random.c ! * Random functions. * * Copyright (c) 2001 Marko Kreen * All rights reserved. --- 1,6 ---- /* * random.c ! * Acquire randomness from system. For seeding RNG. * * Copyright (c) 2001 Marko Kreen * All rights reserved. *************** *** 34,41 **** #include "px.h" ! #if defined(RAND_DEV) #include <errno.h> #include <fcntl.h> --- 34,53 ---- #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__) ! ! #define TRY_DEV_RANDOM #include <errno.h> #include <fcntl.h> *************** safe_read(int fd, void *buf, size_t coun *** 64,157 **** return done; } ! int ! px_get_random_bytes(uint8 *dst, unsigned count) { int fd; int res; ! fd = open(RAND_DEV, O_RDONLY); if (fd == -1) ! return PXE_DEV_READ_ERROR; ! res = safe_read(fd, dst, count); close(fd); ! return res; } ! 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; /* ! * 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; ! } ! int ! px_get_random_bytes(uint8 *dst, unsigned count) ! { ! int res; ! ! if (!openssl_random_init) ! init_openssl(); ! ! 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(); ! res = RAND_pseudo_bytes(dst, count); ! if (res == 0 || res == 1) ! return count; ! return PXE_OSSL_RAND_ERROR; } - #else - #error "Invalid random source" #endif --- 76,244 ---- return done; } ! static uint8 * ! try_dev_random(uint8 *dst) { int fd; int res; ! fd = open("/dev/urandom", O_RDONLY); if (fd == -1) ! { ! fd = open("/dev/random", O_RDONLY); ! 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 ! #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) { ! 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; } ! 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; + } + --
pgsql-patches by date: