Use Windows randomness code on Cygwin
[openssl.git] / crypto / rand / rand_win.c
index 56558c4f154a865b487610200c2ad120899b4947..a7c2c9df7426bc53d4df3206793d45b4667e6d0a 100644 (file)
 #include <openssl/rand.h>
 #include "rand_lcl.h"
 
-#if defined(WINDOWS) || defined(WIN32)
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WIN32_CYGWIN)
 #include <windows.h>
 #ifndef _WIN32_WINNT
 # define _WIN32_WINNT 0x0400
  * http://developer.intel.com/design/security/rng/redist_license.htm
  */
 #define PROV_INTEL_SEC 22
-#define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider"
+#define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
 
 static void readtimer(void);
 static void readscreen(void);
@@ -152,7 +152,7 @@ typedef struct tagCURSORINFO
 #define CURSOR_SHOWING     0x00000001
 #endif /* CURSOR_SHOWING */
 
-typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV *, LPCTSTR, LPCTSTR,
+typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTW)(HCRYPTPROV *, LPCWSTR, LPCWSTR,
                                    DWORD, DWORD);
 typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV, DWORD, BYTE *);
 typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV, DWORD);
@@ -162,6 +162,7 @@ typedef BOOL (WINAPI *GETCURSORINFO)(PCURSORINFO);
 typedef DWORD (WINAPI *GETQUEUESTATUS)(UINT);
 
 typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
+typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
 typedef BOOL (WINAPI *HEAP32FIRST)(LPHEAPENTRY32, DWORD, DWORD);
 typedef BOOL (WINAPI *HEAP32NEXT)(LPHEAPENTRY32);
 typedef BOOL (WINAPI *HEAP32LIST)(HANDLE, LPHEAPLIST32);
@@ -170,7 +171,9 @@ typedef BOOL (WINAPI *THREAD32)(HANDLE, LPTHREADENTRY32);
 typedef BOOL (WINAPI *MODULE32)(HANDLE, LPMODULEENTRY32);
 
 #include <lmcons.h>
+#ifndef OPENSSL_SYS_WINCE
 #include <lmstats.h>
+#endif
 #if 1 /* The NET API is Unicode only.  It requires the use of the UNICODE
        * macro.  When UNICODE is defined LPTSTR becomes LPWSTR.  LMSTR was
        * was added to the Platform SDK to allow the NET API to be used in
@@ -191,7 +194,7 @@ int RAND_poll(void)
        HWND h;
 
        HMODULE advapi, kernel, user, netapi;
-       CRYPTACQUIRECONTEXT acquire = 0;
+       CRYPTACQUIRECONTEXTW acquire = 0;
        CRYPTGENRANDOM gen = 0;
        CRYPTRELEASECONTEXT release = 0;
 #if 1 /* There was previously a problem with NETSTATGET.  Currently, this
@@ -209,11 +212,40 @@ int RAND_poll(void)
         osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
         GetVersionEx( &osverinfo ) ;
 
+#if defined(OPENSSL_SYS_WINCE) && WCEPLATFORM!=MS_HPC_PRO
+#ifndef CryptAcquireContext
+#define CryptAcquireContext CryptAcquireContextW
+#endif
+       /* poll the CryptoAPI PRNG */
+       /* The CryptoAPI returns sizeof(buf) bytes of randomness */
+       if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+               {
+               if (CryptGenRandom(hProvider, sizeof(buf), buf))
+                       RAND_add(buf, sizeof(buf), sizeof(buf));
+               CryptReleaseContext(hProvider, 0); 
+               }
+#endif
+
+#ifndef OPENSSL_SYS_WINCE
+       /*
+        * None of below libraries are present on Windows CE, which is
+        * why we #ifndef the whole section. This also excuses us from
+        * handling the GetProcAddress issue. The trouble is that in
+        * real Win32 API GetProcAddress is available in ANSI flavor
+        * only. In WinCE on the other hand GetProcAddress is a macro
+        * most commonly defined as GetProcAddressW, which accepts
+        * Unicode argument. If we were to call GetProcAddress under
+        * WinCE, I'd recommend to either redefine GetProcAddress as
+        * GetProcAddressA (there seem to be one in common CE spec) or
+        * implement own shim routine, which would accept ANSI argument
+        * and expand it to Unicode.
+        */
+
        /* load functions dynamically - not available on all systems */
-       advapi = LoadLibrary("ADVAPI32.DLL");
-       kernel = LoadLibrary("KERNEL32.DLL");
-       user = LoadLibrary("USER32.DLL");
-       netapi = LoadLibrary("NETAPI32.DLL");
+       advapi = LoadLibrary(TEXT("ADVAPI32.DLL"));
+       kernel = LoadLibrary(TEXT("KERNEL32.DLL"));
+       user = LoadLibrary(TEXT("USER32.DLL"));
+       netapi = LoadLibrary(TEXT("NETAPI32.DLL"));
 
 #if 1 /* There was previously a problem with NETSTATGET.  Currently, this
        * section is still experimental, but if all goes well, this conditional
@@ -249,7 +281,7 @@ int RAND_poll(void)
        if (netapi)
                FreeLibrary(netapi);
 #endif /* 1 */
+
         /* It appears like this can cause an exception deep within ADVAPI32.DLL
          * at random times on Windows 2000.  Reported by Jeffrey Altman.  
          * Only use it on NT.
@@ -280,16 +312,25 @@ int RAND_poll(void)
                        bufsz += 8192;
 
                        length = bufsz;
-                       rc = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global",
+                       rc = RegQueryValueEx(HKEY_PERFORMANCE_DATA, TEXT("Global"),
                                NULL, NULL, buf, &length);
                        }
                if (rc == ERROR_SUCCESS)
                        {
                         /* For entropy count assume only least significant
                         * byte of each DWORD is random.
-                         */
+                        */
                        RAND_add(&length, sizeof(length), 0);
                        RAND_add(buf, length, length / 4.0);
+
+                       /* Close the Registry Key to allow Windows to cleanup/close
+                        * the open handle
+                        * Note: The 'HKEY_PERFORMANCE_DATA' key is implicitly opened
+                        *       when the RegQueryValueEx above is done.  However, if
+                        *       it is not explicitly closed, it can cause disk
+                        *       partition manipulation problems.
+                        */
+                       RegCloseKey(HKEY_PERFORMANCE_DATA);
                        }
                if (buf)
                        free(buf);
@@ -298,8 +339,13 @@ int RAND_poll(void)
 
        if (advapi)
                {
-               acquire = (CRYPTACQUIRECONTEXT) GetProcAddress(advapi,
-                       "CryptAcquireContextA");
+               /*
+                * If it's available, then it's available in both ANSI
+                * and UNICODE flavors even in Win9x, documentation says.
+                * We favor Unicode...
+                */
+               acquire = (CRYPTACQUIRECONTEXTW) GetProcAddress(advapi,
+                       "CryptAcquireContextW");
                gen = (CRYPTGENRANDOM) GetProcAddress(advapi,
                        "CryptGenRandom");
                release = (CRYPTRELEASECONTEXT) GetProcAddress(advapi,
@@ -316,7 +362,7 @@ int RAND_poll(void)
                        if (gen(hProvider, sizeof(buf), buf) != 0)
                                {
                                RAND_add(buf, sizeof(buf), 0);
-#ifdef DEBUG
+#if 0
                                printf("randomness from PROV_RSA_FULL\n");
 #endif
                                }
@@ -329,7 +375,7 @@ int RAND_poll(void)
                        if (gen(hProvider, sizeof(buf), buf) != 0)
                                {
                                RAND_add(buf, sizeof(buf), sizeof(buf));
-#ifdef DEBUG
+#if 0
                                printf("randomness from PROV_INTEL_SEC\n");
 #endif
                                }
@@ -340,17 +386,6 @@ int RAND_poll(void)
         if (advapi)
                FreeLibrary(advapi);
 
-       /* timer data */
-       readtimer();
-       
-       /* memory usage statistics */
-       GlobalMemoryStatus(&m);
-       RAND_add(&m, sizeof(m), 1);
-
-       /* process ID */
-       w = GetCurrentProcessId();
-       RAND_add(&w, sizeof(w), 1);
-
        if (user)
                {
                GETCURSORINFO cursor;
@@ -405,7 +440,7 @@ int RAND_poll(void)
         * This seeding method was proposed in Peter Gutmann, Software
         * Generation of Practically Strong Random Numbers,
         * http://www.usenix.org/publications/library/proceedings/sec98/gutmann.html
-     * revised version at http://www.cryptoengines.com/~peter/06_random.pdf
+        * revised version at http://www.cryptoengines.com/~peter/06_random.pdf
         * (The assignment of entropy estimates below is arbitrary, but based
         * on Peter's analysis the full poll appears to be safe. Additional
         * interactive seeding is encouraged.)
@@ -414,6 +449,7 @@ int RAND_poll(void)
        if (kernel)
                {
                CREATETOOLHELP32SNAPSHOT snap;
+               CLOSETOOLHELP32SNAPSHOT close_snap;
                HANDLE handle;
 
                HEAP32FIRST heap_first;
@@ -431,6 +467,8 @@ int RAND_poll(void)
 
                snap = (CREATETOOLHELP32SNAPSHOT)
                        GetProcAddress(kernel, "CreateToolhelp32Snapshot");
+               close_snap = (CLOSETOOLHELP32SNAPSHOT)
+                       GetProcAddress(kernel, "CloseToolhelp32Snapshot");
                heap_first = (HEAP32FIRST) GetProcAddress(kernel, "Heap32First");
                heap_next = (HEAP32NEXT) GetProcAddress(kernel, "Heap32Next");
                heaplist_first = (HEAP32LIST) GetProcAddress(kernel, "Heap32ListFirst");
@@ -446,7 +484,7 @@ int RAND_poll(void)
                        heaplist_next && process_first && process_next &&
                        thread_first && thread_next && module_first &&
                        module_next && (handle = snap(TH32CS_SNAPALL,0))
-                       != NULL)
+                       != INVALID_HANDLE_VALUE)
                        {
                        /* heap list and heap walking */
                         /* HEAPLIST32 contains 3 fields that will change with
@@ -508,14 +546,28 @@ int RAND_poll(void)
                                do
                                        RAND_add(&m, m.dwSize, 9);
                                while (module_next(handle, &m));
-
-                       CloseHandle(handle);
+                       if (close_snap)
+                               close_snap(handle);
+                       else
+                               CloseHandle(handle);
                        }
 
                FreeLibrary(kernel);
                }
+#endif /* !OPENSSL_SYS_WINCE */
+
+       /* timer data */
+       readtimer();
+       
+       /* memory usage statistics */
+       GlobalMemoryStatus(&m);
+       RAND_add(&m, sizeof(m), 1);
 
-#ifdef DEBUG
+       /* process ID */
+       w = GetCurrentProcessId();
+       RAND_add(&w, sizeof(w), 1);
+
+#if 0
        printf("Exiting RAND_poll\n");
 #endif
 
@@ -575,14 +627,15 @@ static void readtimer(void)
        DWORD w;
        LARGE_INTEGER l;
        static int have_perfc = 1;
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && defined(_M_X86)
        static int have_tsc = 1;
        DWORD cyclecount;
 
        if (have_tsc) {
          __try {
            __asm {
-             rdtsc
+             _emit 0x0f
+             _emit 0x31
              mov cyclecount, eax
              }
            RAND_add(&cyclecount, sizeof(cyclecount), 1);
@@ -613,7 +666,7 @@ static void readtimer(void)
  * Created 960901 by Gertjan van Oosten, gertjan@West.NL, West Consulting B.V.
  *
  * Code adapted from
- * <URL:http://www.microsoft.com/kb/developr/win_dk/q97193.htm>;
+ * <URL:http://support.microsoft.com/default.aspx?scid=kb;[LN];97193>;
  * the original copyright message is:
  *
  *   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
@@ -627,6 +680,7 @@ static void readtimer(void)
 
 static void readscreen(void)
 {
+#if !defined(OPENSSL_SYS_WINCE) && !defined(OPENSSL_SYS_WIN32_CYGWIN)
   HDC          hScrDC;         /* screen DC */
   HDC          hMemDC;         /* memory DC */
   HBITMAP      hBitmap;        /* handle for our bitmap */
@@ -640,7 +694,7 @@ static void readscreen(void)
   int          n = 16;         /* number of screen lines to grab at a time */
 
   /* Create a screen DC and a memory DC compatible to screen DC */
-  hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
+  hScrDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
   hMemDC = CreateCompatibleDC(hScrDC);
 
   /* Get screen resolution */
@@ -687,6 +741,7 @@ static void readscreen(void)
   DeleteObject(hBitmap);
   DeleteDC(hMemDC);
   DeleteDC(hScrDC);
+#endif /* !OPENSSL_SYS_WINCE */
 }
 
 #endif