Fix a problem with select and high fds.
[libgcrypt.git] / random / rndw32ce.c
1 /* rndw32ce.c  -  W32CE entropy gatherer
2  * Copyright (C) 2010 Free Software Foundation, Inc.
3  *
4  * Libgcrypt is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as
6  * published by the Free Software Foundation; either version 2.1 of
7  * the License, or (at your option) any later version.
8  *
9  * Libgcrypt is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <config.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <stdint.h>
24
25 #include <windows.h>
26 #include <wincrypt.h>
27
28 #include "types.h"
29 #include "g10lib.h"
30 #include "rand-internal.h"
31
32
33 /* The Microsoft docs say that it is suggested to see the buffer with
34    some extra random.  We do this, despite that it is a questionable
35    suggestion as the OS as better means of collecting entropy than an
36    application.  */
37 static size_t filler_used;
38 static size_t filler_length;
39 static unsigned char *filler_buffer;
40
41 static void
42 filler (const void *data, size_t datalen, enum random_origins dummy)
43 {
44   (void)dummy;
45   if (filler_used + datalen > filler_length)
46     datalen = filler_length - filler_used;
47   memcpy (filler_buffer + filler_used, data, datalen);
48   filler_used += datalen;
49 }
50
51
52 static void
53 fillup_buffer (unsigned char *buffer, size_t length)
54 {
55   filler_used = 0;
56   filler_length = length;
57   filler_buffer = buffer;
58
59   while (filler_used < length)
60     _gcry_rndw32ce_gather_random_fast (filler, 0);
61 }
62
63
64 int
65 _gcry_rndw32ce_gather_random (void (*add)(const void*, size_t,
66                                           enum random_origins),
67                               enum random_origins origin,
68                               size_t length, int level )
69 {
70   HCRYPTPROV prov;
71   unsigned char buffer [256];
72   DWORD buflen;
73
74   if (!level)
75     return 0;
76
77   /* Note that LENGTH is not really important because the caller
78      checks the returned lengths and calls this function until it
79      feels that enough entropy has been gathered.  */
80
81   buflen = sizeof buffer;
82   if (length+8 < buflen)
83     buflen = length+8;  /* Return a bit more than requested.  */
84
85   if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL,
86                            (CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
87     log_debug ("CryptAcquireContext failed: rc=%d\n", (int)GetLastError ());
88   else
89     {
90       fillup_buffer (buffer, buflen);
91       if (!CryptGenRandom (prov, buflen, buffer))
92         log_debug ("CryptGenRandom(%d) failed: rc=%d\n",
93                    (int)buflen, (int)GetLastError ());
94       else
95         (*add) (buffer, buflen, origin);
96       CryptReleaseContext (prov, 0);
97       wipememory (buffer, sizeof buffer);
98     }
99
100   return 0;
101 }
102
103
104
105 void
106 _gcry_rndw32ce_gather_random_fast (void (*add)(const void*, size_t,
107                                              enum random_origins),
108                                    enum random_origins origin)
109 {
110
111   /* Add word sized values.  */
112   {
113 #   define ADD(t,f)  do {                                          \
114       t along = (f);                                               \
115       memcpy (bufptr, &along, sizeof (along));                     \
116       bufptr += sizeof (along);                                    \
117     } while (0)
118     unsigned char buffer[20*sizeof(ulong)], *bufptr;
119
120     bufptr = buffer;
121     ADD (HWND,   GetActiveWindow ());
122     ADD (HWND,   GetCapture ());
123     ADD (HWND,   GetClipboardOwner ());
124     ADD (HANDLE, GetCurrentProcess ());
125     ADD (DWORD,  GetCurrentProcessId ());
126     ADD (HANDLE, GetCurrentThread ());
127     ADD (DWORD,  GetCurrentThreadId ());
128     ADD (HWND,   GetDesktopWindow ());
129     ADD (HWND,   GetFocus ());
130     ADD (DWORD,  GetMessagePos ());
131     ADD (HWND,   GetOpenClipboardWindow ());
132     ADD (HWND,   GetProcessHeap ());
133     ADD (DWORD,  GetQueueStatus (QS_ALLEVENTS));
134     ADD (DWORD,  GetTickCount ());
135
136     gcry_assert ( bufptr-buffer < sizeof (buffer) );
137     (*add) ( buffer, bufptr-buffer, origin );
138 #   undef ADD
139   }
140
141   /* Get multiword system information: Current caret position, current
142      mouse cursor position.  */
143   {
144     POINT point;
145
146     GetCaretPos (&point);
147     (*add) ( &point, sizeof (point), origin );
148     GetCursorPos (&point);
149     (*add) ( &point, sizeof (point), origin );
150   }
151
152   /* Get percent of memory in use, bytes of physical memory, bytes of
153      free physical memory, bytes in paging file, free bytes in paging
154      file, user bytes of address space, and free user bytes.  */
155   {
156     MEMORYSTATUS memoryStatus;
157
158     memoryStatus.dwLength = sizeof (MEMORYSTATUS);
159     GlobalMemoryStatus (&memoryStatus);
160     (*add) ( &memoryStatus, sizeof (memoryStatus), origin );
161   }
162
163
164   /* Get thread and process creation time, exit time, time in kernel
165      mode, and time in user mode in 100ns intervals.  */
166   {
167     HANDLE handle;
168     FILETIME creationTime, exitTime, kernelTime, userTime;
169
170     handle = GetCurrentThread ();
171     GetThreadTimes (handle, &creationTime, &exitTime,
172                     &kernelTime, &userTime);
173     (*add) ( &creationTime, sizeof (creationTime), origin );
174     (*add) ( &exitTime, sizeof (exitTime), origin );
175     (*add) ( &kernelTime, sizeof (kernelTime), origin );
176     (*add) ( &userTime, sizeof (userTime), origin );
177
178     handle = GetCurrentThread ();
179     GetThreadTimes (handle, &creationTime, &exitTime,
180                      &kernelTime, &userTime);
181     (*add) ( &creationTime, sizeof (creationTime), origin );
182     (*add) ( &exitTime, sizeof (exitTime), origin );
183     (*add) ( &kernelTime, sizeof (kernelTime), origin );
184     (*add) ( &userTime, sizeof (userTime), origin );
185
186   }
187
188
189   /* In case the OEM provides a high precision timer get this.  If
190      none is available the default implementation returns the
191      GetTickCount.  */
192   {
193     LARGE_INTEGER performanceCount;
194
195     if (QueryPerformanceCounter (&performanceCount))
196       (*add) (&performanceCount, sizeof (performanceCount), origin);
197   }
198
199 }