From 9602ffc30b29e48544c3d947367e118ad8c61c92 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 24 Jul 2000 11:33:02 +0000 Subject: * fhandler.h (class fhandler_dev_random): Add members for managing pseudo randomness. * fhandler_random.cc: Rearrange. Use pseudo random number generator as entropy source if system entropy isn't available and if device is used as /dev/urandom. Allow initializing device by calling write(). --- winsup/cygwin/fhandler_random.cc | 93 +++++++++++++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 11 deletions(-) (limited to 'winsup/cygwin/fhandler_random.cc') diff --git a/winsup/cygwin/fhandler_random.cc b/winsup/cygwin/fhandler_random.cc index 9b784a853..9991c3b7e 100644 --- a/winsup/cygwin/fhandler_random.cc +++ b/winsup/cygwin/fhandler_random.cc @@ -1,4 +1,4 @@ -/* fhandler_dev_random.cc: code to access /dev/random +/* fhandler_dev_random.cc: code to access /dev/random and /dev/urandom Copyright 2000 Cygnus Solutions. @@ -11,11 +11,15 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include +#include #include "winsup.h" #define RANDOM 8 #define URANDOM 9 +#define PSEUDO_MULTIPLIER (6364136223846793005LL) +#define PSEUDO_SHIFTVAL (21) + fhandler_dev_random::fhandler_dev_random (const char *name, int nunit) : fhandler_base (FH_RANDOM, name), unit(nunit), @@ -31,35 +35,102 @@ fhandler_dev_random::open (const char *, int flags, mode_t) return 1; } +BOOL +fhandler_dev_random::crypt_gen_random (void *ptr, size_t len) +{ + if (!crypt_prov + && !CryptAcquireContext (&crypt_prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET) + && !CryptAcquireContext (&crypt_prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET + | CRYPT_NEWKEYSET)) + { + debug_printf ("%E = CryptAquireContext()"); + return FALSE; + } + if (!CryptGenRandom (crypt_prov, len, (BYTE *)ptr)) + { + debug_printf ("%E = CryptGenRandom()"); + return FALSE; + } + return TRUE; +} + int -fhandler_dev_random::write (const void *, size_t len) +fhandler_dev_random::pseudo_write (const void *ptr, size_t len) { + /* Use buffer to mess up the pseudo random number generator. */ + for (size_t i = 0; i < len; ++i) + pseudo = (pseudo + ((unsigned char *)ptr)[i]) * PSEUDO_MULTIPLIER + 1; return len; } int -fhandler_dev_random::read (void *ptr, size_t len) +fhandler_dev_random::write (const void *ptr, size_t len) { if (!len) return 0; - if (!crypt_prov - && !CryptAcquireContext (&crypt_prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET) - && !CryptAcquireContext (&crypt_prov, NULL, MS_DEF_PROV, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET - | CRYPT_NEWKEYSET )) + if (!ptr) { - __seterrno (); + set_errno (EINVAL); return -1; } - if (!CryptGenRandom (crypt_prov, len, (BYTE *)ptr)) + + /* Limit len to a value <= 512 since we don't want to overact. + Copy to local buffer because CryptGenRandom violates const. */ + unsigned char buf[512]; + size_t limited_len = len <= 512 ? len : 512; + memcpy (buf, ptr, limited_len); + + /* Mess up system entropy source. Return error if device is /dev/random. */ + if (!crypt_gen_random (buf, limited_len) && unit == RANDOM) { __seterrno (); return -1; } + /* Mess up the pseudo random number generator. */ + pseudo_write (buf, limited_len); return len; } +int +fhandler_dev_random::pseudo_read (void *ptr, size_t len) +{ + /* Use pseudo random number generator as fallback entropy source. + This multiplier was obtained from Knuth, D.E., "The Art of + Computer Programming," Vol 2, Seminumerical Algorithms, Third + Edition, Addison-Wesley, 1998, p. 106 (line 26) & p. 108 */ + for (size_t i = 0; i < len; ++i) + { + pseudo = pseudo * PSEUDO_MULTIPLIER + 1; + ((unsigned char *)ptr)[i] = (pseudo >> PSEUDO_SHIFTVAL) & UCHAR_MAX; + } + return len; +} + +int +fhandler_dev_random::read (void *ptr, size_t len) +{ + if (!len) + return 0; + if (!ptr) + { + set_errno (EINVAL); + return -1; + } + + if (crypt_gen_random (ptr, len)) + return len; + /* If device is /dev/urandom, use pseudo number generator as fallback. + Don't do this for /dev/random since it's intended for uses that need + very high quality randomness. */ + if (unit == URANDOM) + return pseudo_read (ptr, len); + + __seterrno (); + return -1; +} + off_t fhandler_dev_random::lseek (off_t, int) { -- cgit v1.2.3