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.  */
37static size_t filler_used;
38static size_t filler_length;
39static unsigned char *filler_buffer;
40
41static void
42filler (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
52static void
53fillup_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
64int
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
105void
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}
200