From 9602ffc30b29e48544c3d947367e118ad8c61c92 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 24 Jul 2000 11:33:02 +0000 Subject: [PATCH] * 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/ChangeLog | 8 +++ winsup/cygwin/fhandler.h | 5 ++ winsup/cygwin/fhandler_random.cc | 103 ++++++++++++++++++++++++++----- 3 files changed, 100 insertions(+), 16 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 556a61a14..37e60c37a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,11 @@ +Mon Jul 24 13:26:00 2000 Corinna Vinschen + + * 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(). + Sun Jul 23 23:11:00 2000 Corinna Vinschen * fhandler.h: Add comment. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 9ff028ad0..ba6319b4f 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -743,6 +743,11 @@ class fhandler_dev_random: public fhandler_base protected: int unit; HCRYPTPROV crypt_prov; + long pseudo; + + BOOL crypt_gen_random (void *ptr, size_t len); + int pseudo_write (const void *ptr, size_t len); + int pseudo_read (void *ptr, size_t len); public: fhandler_dev_random (const char *name, int unit); 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,9 +35,76 @@ fhandler_dev_random::open (const char *, int flags, mode_t) return 1; } -int -fhandler_dev_random::write (const void *, size_t len) +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::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::write (const void *ptr, size_t len) +{ + if (!len) + return 0; + if (!ptr) + { + set_errno (EINVAL); + return -1; + } + + /* 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; } @@ -42,22 +113,22 @@ fhandler_dev_random::read (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)) - { - __seterrno (); - return -1; - } - return len; + + 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