From 7a22503bcb92230d9afa88d16f8e426208df832f Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 19 Oct 2016 11:56:47 +0900 Subject: [PATCH 3/8] Implement last-resort method in pg_strong_random This method will be used on nix platforms in the case where any of the previous methods failed. It uses pid(), gettimeofday() and random() to grab some entropy, even if this is predictible, and processes the obtained value through a SHA-256 hash. --- src/port/pg_strong_random.c | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/src/port/pg_strong_random.c b/src/port/pg_strong_random.c index a404111..17c217a 100644 --- a/src/port/pg_strong_random.c +++ b/src/port/pg_strong_random.c @@ -18,6 +18,8 @@ #include "postgres_fe.h" #endif +#include "common/sha2.h" + #include #include @@ -29,6 +31,9 @@ #endif static bool random_from_file(char *filename, void *buf, size_t len); +#ifndef WIN32 +static bool random_from_std(void *dst, size_t len); +#endif #ifdef WIN32 /* @@ -72,6 +77,67 @@ random_from_file(char *filename, void *buf, size_t len) return true; } +#ifndef WIN32 +/* + * This is not available on Windows, and the cryptography standards available + * there are enough anyway to generate randomness. + */ +#include +#include + +/* + * Generate some random data using environment data as entropy + * through SHA-256. All the other methods failed, this can be used + * as a last resort method even if it is predictible, and rather + * slow compared to the rest. + */ +static bool +random_from_std(void *dst, size_t len) +{ + pid_t pid; + size_t remaining = len; + + /* process ID */ + pid = getpid(); + + /* + * Compute a random value by generating successive chunks worth + * of PG_SHA256_DIGEST_LENGTH bytes. + */ + while (remaining != 0) + { + int x; + struct timeval tv; + pg_sha256_ctx ctx; + uint8 sha_buf[PG_SHA256_DIGEST_LENGTH]; + + pg_sha256_init(&ctx); + pg_sha256_update(&ctx, (uint8 *) &pid, sizeof(pid)); + + /* time */ + gettimeofday(&tv, NULL); + pg_sha256_update(&ctx, (uint8 *) &tv, sizeof(tv)); + + /* pointless, but should not hurt */ + x = random(); + pg_sha256_update(&ctx, (uint8 *) &x, sizeof(x)); + pg_sha256_final(&ctx, sha_buf); + + /* copy the chunk generated in the result */ + memcpy(dst, sha_buf, Min(remaining, PG_SHA256_DIGEST_LENGTH)); + + /* and prepare to loop further */ + if (remaining >= PG_SHA256_DIGEST_LENGTH) + remaining -= PG_SHA256_DIGEST_LENGTH; + else + remaining = 0; + dst = (uint8 *) dst + PG_SHA256_DIGEST_LENGTH; + } + + return true; +} +#endif + /* * pg_strong_random * @@ -86,6 +152,8 @@ random_from_file(char *filename, void *buf, size_t len) * 2. Windows' CryptGenRandom() function * 3. /dev/urandom * 4. /dev/random + * 5. Use the internal, predictible method computing a value through SHA-256 + * with system-related entropy. * * Returns true on success, and false if none of the sources * were available. NB: It is important to check the return value! @@ -143,6 +211,14 @@ pg_strong_random(void *buf, size_t len) if (random_from_file("/dev/random", buf, len)) return true; +#ifndef WIN32 + /* + * As final method, generate some randomness using the in-house method. + */ + if (random_from_std(buf, len)) + return true; +#endif + /* None of the sources were available. */ return false; } -- 2.10.1