From 2cbd31fe26e635e170e1f417a2a015efd54ac79f Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 15 Oct 2013 14:00:37 +0000 Subject: [PATCH] * autoload.cc (CryptAcquireContextW): Remove. (CryptGenRandom): Remove. (CryptReleaseContext): Remove. (SystemFunction036): Define. Add comment to explain that this is actually the RtlGenRandom function. * fhandler.h (class fhandler_dev_random): Drop crypt_prov member. (fhandler_dev_random::fhandler_dev_random): Define inline. (fhandler_dev_random::dup): Drop declaration. * fhandler_random.cc (fhandler_dev_random::fhandler_dev_random): Remove here. (fhandler_dev_random::crypt_gen_random): Use RtlGenRandom to drop dependency to old Crypto API. (fhandler_dev_random::read): Implement an enhanced version of reading random bytes from RtlGenRandom for the sake of a better /dev/random emulation. (fhandler_dev_random::close): Just return 0 since crypt_prov doesn't exisyt anymore. (fhandler_dev_random::dup): Drop entirely for the same reason. --- winsup/cygwin/ChangeLog | 21 ++++++++ winsup/cygwin/autoload.cc | 4 +- winsup/cygwin/fhandler.h | 4 +- winsup/cygwin/fhandler_random.cc | 82 +++++++++++++++----------------- 4 files changed, 62 insertions(+), 49 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 7f1fefaa4..6b20881be 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,24 @@ +2013-10-15 Corinna Vinschen + + * autoload.cc (CryptAcquireContextW): Remove. + (CryptGenRandom): Remove. + (CryptReleaseContext): Remove. + (SystemFunction036): Define. Add comment to explain that this is + actually the RtlGenRandom function. + * fhandler.h (class fhandler_dev_random): Drop crypt_prov member. + (fhandler_dev_random::fhandler_dev_random): Define inline. + (fhandler_dev_random::dup): Drop declaration. + * fhandler_random.cc (fhandler_dev_random::fhandler_dev_random): Remove + here. + (fhandler_dev_random::crypt_gen_random): Use RtlGenRandom to drop + dependency to old Crypto API. + (fhandler_dev_random::read): Implement an enhanced version of reading + random bytes from RtlGenRandom for the sake of a better /dev/random + emulation. + (fhandler_dev_random::close): Just return 0 since crypt_prov doesn't + exisyt anymore. + (fhandler_dev_random::dup): Drop entirely for the same reason. + 2013-10-15 Corinna Vinschen * mmap.cc (mmap64): Convert pagesize from DWORD to size_t to avoid diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index ed8080258..f364cf937 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -537,9 +537,6 @@ wsock_init () LoadDLLprime (ws2_32, _wsock_init, 0) LoadDLLfunc (CreateProcessAsUserW, 44, advapi32) -LoadDLLfunc (CryptAcquireContextW, 20, advapi32) -LoadDLLfunc (CryptGenRandom, 12, advapi32) -LoadDLLfunc (CryptReleaseContext, 8, advapi32) LoadDLLfunc (DeregisterEventSource, 4, advapi32) LoadDLLfunc (LogonUserW, 24, advapi32) LoadDLLfunc (LookupAccountNameW, 28, advapi32) @@ -563,6 +560,7 @@ LoadDLLfunc (RegQueryInfoKeyW, 48, advapi32) LoadDLLfunc (RegQueryValueExW, 24, advapi32) LoadDLLfunc (RegisterEventSourceW, 8, advapi32) LoadDLLfunc (ReportEventW, 36, advapi32) +LoadDLLfunc (SystemFunction036, 8, advapi32) /* Aka "RtlGenRandom" */ LoadDLLfunc (DnsQuery_A, 24, dnsapi) LoadDLLfunc (DnsRecordListFree, 8, dnsapi) diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index fe5e3accd..f7bcb153a 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1652,7 +1652,6 @@ class fhandler_dev_zero: public fhandler_base class fhandler_dev_random: public fhandler_base { protected: - HCRYPTPROV crypt_prov; uint32_t pseudo; off_t dummy_offset; @@ -1661,14 +1660,13 @@ class fhandler_dev_random: public fhandler_base int pseudo_read (void *ptr, size_t len); public: - fhandler_dev_random (); int open (int flags, mode_t mode = 0); ssize_t __stdcall write (const void *ptr, size_t len); void __reg3 read (void *ptr, size_t& len); off_t lseek (off_t offset, int whence); int close (); - int dup (fhandler_base *child, int); + fhandler_dev_random () : fhandler_base () {} fhandler_dev_random (void *) {} void copyto (fhandler_base *x) diff --git a/winsup/cygwin/fhandler_random.cc b/winsup/cygwin/fhandler_random.cc index 56c8d107f..092c6f887 100644 --- a/winsup/cygwin/fhandler_random.cc +++ b/winsup/cygwin/fhandler_random.cc @@ -1,8 +1,7 @@ /* fhandler_random.cc: code to access /dev/random and /dev/urandom - Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2011 Red Hat, Inc. - - Written by Corinna Vinschen (vinschen@cygnus.com) + Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2011, 2013 + Red Hat, Inc. This file is part of Cygwin. @@ -23,14 +22,12 @@ details. */ #define RANDOM 8 #define URANDOM 9 +/* The system PRNG is reseeded after reading 128K bytes. */ +#define RESEED_INTERVAL (128 * 1024) + #define PSEUDO_MULTIPLIER (6364136223846793005LL) #define PSEUDO_SHIFTVAL (21) -fhandler_dev_random::fhandler_dev_random () - : fhandler_base (), crypt_prov ((HCRYPTPROV) NULL) -{ -} - int fhandler_dev_random::open (int flags, mode_t) { @@ -41,22 +38,18 @@ fhandler_dev_random::open (int flags, mode_t) return 1; } +/* There's a bug in ntsecapi.h (Mingw as well as MSFT). SystemFunction036 + is, in fact, a WINAPI function, but it's not defined as such. Therefore + we have to do it correctly here. */ +#define RtlGenRandom SystemFunction036 +extern "C" BOOLEAN WINAPI RtlGenRandom (PVOID, ULONG); + bool fhandler_dev_random::crypt_gen_random (void *ptr, size_t len) { - if (!crypt_prov - && !CryptAcquireContextW (&crypt_prov, NULL, MS_DEF_PROV_W, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET) - && !CryptAcquireContextW (&crypt_prov, NULL, MS_DEF_PROV_W, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET - | CRYPT_NEWKEYSET)) + if (!RtlGenRandom (ptr, len)) { - debug_printf ("%E = CryptAquireContext()"); - return false; - } - if (!CryptGenRandom (crypt_prov, len, (BYTE *)ptr)) - { - debug_printf ("%E = CryptGenRandom()"); + debug_printf ("%E = RtlGenRandom()"); return false; } return true; @@ -127,20 +120,35 @@ fhandler_dev_random::read (void *ptr, size_t& len) return; } - if (crypt_gen_random (ptr, len)) - return; - - /* 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 (dev () == FH_URANDOM) + /* /dev/random has to provide high quality random numbers. Therefore we + re-seed the system PRNG for each block of 512 bytes. This results in + sufficiently random sequences, comparable to the Linux /dev/random. */ + if (dev () == FH_RANDOM) { - len = pseudo_read (ptr, len); - return; + void *dummy = malloc (RESEED_INTERVAL); + if (!dummy) + { + __seterrno (); + len = (size_t) -1; + return; + } + for (size_t offset = 0; offset < len; offset += 512) + { + if (!crypt_gen_random (dummy, RESEED_INTERVAL) || + !crypt_gen_random ((PBYTE) ptr + offset, len - offset)) + { + __seterrno (); + len = (size_t) -1; + break; + } + } + free (dummy); } - __seterrno (); - len = (size_t) -1; + /* If device is /dev/urandom, just use system RNG as is, with our own + PRNG as fallback. */ + else if (!crypt_gen_random (ptr, len)) + len = pseudo_read (ptr, len); } off_t @@ -174,17 +182,5 @@ fhandler_dev_random::lseek (off_t off, int whence) int fhandler_dev_random::close () { - if (!have_execed && crypt_prov) - while (!CryptReleaseContext (crypt_prov, 0) - && GetLastError () == ERROR_BUSY) - Sleep (10); - return 0; -} - -int -fhandler_dev_random::dup (fhandler_base *child, int) -{ - fhandler_dev_random *fhr = (fhandler_dev_random *) child; - fhr->crypt_prov = (HCRYPTPROV)NULL; return 0; }