See ChangeLog: Tue Oct 26 14:10:21 CEST 1999 Werner Koch
[gnupg.git] / cipher / rndw32.c
1 /* rndw32.c  -  interface to the Winseed DLL
2  *      Copyright (C) 1999 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include <windows.h>
29
30 #include "types.h"
31 #include "util.h"
32 #include "dynload.h"
33
34
35 #ifdef IS_MODULE
36   #define _(a) (a)
37 #else
38   #include "i18n.h"
39 #endif
40
41
42 #define WIN32_SLOW_SEEDER       0
43 #define WIN32_FAST_SEEDER       1
44
45 #define PCP_SUCCESS             0
46 #define PCP_NULL_POINTER        1
47 #define PCP_SEEDER_FAILED       2
48 #define PCP_SEEDER_NO_MEM       3
49 #define PCP_SEEDER_TOO_SMALL    4
50 #define PCP_DLL_LOAD_FAILED     5
51 #define PCP_UNKNOWN_PLATFORM    6
52 #define PCP_ERROR_VERSION       7
53 #define PCP_DLL_FUNC            8
54 #define PCP_UNKNOWN_SEEDER_TYPE 9
55
56 typedef void *WIN32_SEEDER;
57
58 static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason);
59 static void         (WINAPI *delete_instance)( WIN32_SEEDER that );
60 static unsigned int (WINAPI *get_internal_seed_size)( WIN32_SEEDER that );
61 static void         (WINAPI *set_internal_seed_size)( WIN32_SEEDER that,
62                                                       unsigned int new_size);
63 static unsigned int (WINAPI *get_expected_seed_size)( WIN32_SEEDER that);
64 static unsigned int (WINAPI *get_seed)( WIN32_SEEDER that, byte *buffer,
65                                         unsigned int *desired_length);
66
67 static WIN32_SEEDER slow_seeder, fast_seeder;
68 static byte *entropy_buffer;
69 static size_t entropy_buffer_size;
70
71 static char *entropy_dll;
72
73 /****************
74  * Load and initialize the winseed DLL
75  * NOTE: winseed is not part of the GnuPG distribution.  It should be available
76  * at the GNU crypto FTP server site.
77  * We do not load the DLL on demand to have a better control over the
78  * location of the library.
79  */
80 static void
81 load_and_init_winseed( void )
82 {
83     int hInstance;
84     void *addr;
85     unsigned int reason = 0;
86     unsigned int n1, n2;
87     const char *dllname = entropy_dll? entropy_dll : "c:/gnupg/entropy.dll";
88
89     hInstance = LoadLibrary( dllname );
90     if( !hInstance )
91         goto failure;
92     if( !(addr = GetProcAddress( hInstance, "WS_create_instance" )) )
93         goto failure;
94     create_instance = addr;
95     if( !(addr = GetProcAddress( hInstance, "WS_delete_instance" )) )
96         goto failure;
97     delete_instance = addr;
98     if( !(addr = GetProcAddress( hInstance, "WS_get_internal_seed_size" )) )
99         goto failure;
100     get_internal_seed_size = addr;
101     if( !(addr = GetProcAddress( hInstance, "WS_set_internal_seed_size" )) )
102         goto failure;
103     set_internal_seed_size = addr;
104     if( !(addr = GetProcAddress( hInstance, "WS_get_expected_seed_size" )) )
105         goto failure;
106     get_expected_seed_size = addr;
107     if( !(addr = GetProcAddress( hInstance, "WS_get_seed" )) )
108         goto failure;
109     get_seed = addr;
110
111     /* we have all the functions - init the system */
112     slow_seeder = create_instance( WIN32_SLOW_SEEDER, &reason);
113     if( !slow_seeder ) {
114         g10_log_fatal("error creating winseed slow seeder: rc=%u\n", reason );
115         goto failure;
116     }
117     fast_seeder = create_instance( WIN32_FAST_SEEDER, &reason);
118     if( !fast_seeder ) {
119         g10_log_fatal("error creating winseed fast seeder: rc=%u\n", reason );
120         goto failure;
121     }
122     g10_log_info("slow and fast seeders created.\n");
123     n1 = get_internal_seed_size( slow_seeder );
124     g10_log_info("slow buffer size=%u\n", n1);
125     n2 = get_internal_seed_size( fast_seeder );
126     g10_log_info("fast buffer size=%u\n", n2);
127
128     entropy_buffer_size =  n1 > n2? n1: n2;
129     entropy_buffer = m_alloc( entropy_buffer_size );
130     g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );
131
132     return;
133
134   failure:
135     g10_log_fatal("error loading winseed DLL `%s'\n", dllname );
136 }
137
138
139
140
141
142 /* Note: we always use the highest level.
143  * TO boost the performance we may want to add some
144  * additional code for level 1
145  */
146 static int
147 gather_random( void (*add)(const void*, size_t, int), int requester,
148                                           size_t length, int level )
149 {
150     unsigned int result;
151     unsigned int nbytes;
152
153     if( !slow_seeder )
154         load_and_init_winseed();
155
156     /* Our estimation on how much entropy we should use is very vague.
157      * Winseed delivers some amount of entropy on each slow poll and
158      * we add it to our random pool.  Depending on the required quality
159      * level we adjust the requested length so that for higer quality
160      * we make sure to add more entropy to our pool.  However, as we don't
161      * like to waste any entropy collected by winseed, we always add
162      * at least everything we got from winseed.
163      */
164     if( level > 1 )
165         length *= 100;
166     else if( level > 0 )
167         length *= 10;
168
169     for(;;) {
170         nbytes = entropy_buffer_size;
171         result = get_seed( slow_seeder, entropy_buffer, &nbytes);
172         if( result ) {
173             g10_log_fatal("rndw32: get_seed(slow) failed: rc=%u\n", result);
174             return -1; /* actually never reached */
175         }
176         g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
177                       level, (unsigned int)length, (unsigned int)nbytes );
178         (*add)( entropy_buffer, nbytes, requester );
179         if( length <= nbytes )
180             return 0; /* okay */
181         length -= nbytes;
182         g10_log_info("rndw32: need more\n");
183     }
184 }
185
186 static int
187 gather_random_fast( void (*add)(const void*, size_t, int), int requester )
188 {
189     unsigned int result;
190     unsigned int nbytes;
191
192     if( !fast_seeder )
193         load_and_init_winseed();
194
195     /* winseed delivers a constant ammount of entropy for a fast
196      * poll.  We can simply use this and add it to the pool; no need
197      * a loop like it is used in the slow poll */
198     nbytes = entropy_buffer_size;
199     result = get_seed( fast_seeder, entropy_buffer, &nbytes);
200     if( result ) {
201         g10_log_fatal("rndw32: get_seed(fast) failed: rc=%u\n", result);
202         return -1; /* actually never reached */
203     }
204     /*g10_log_info("rndw32: fast poll got %u\n", (unsigned int)nbytes );*/
205     (*add)( entropy_buffer, nbytes, requester );
206     return 0;
207 }
208
209
210
211 #ifndef IS_MODULE
212 static
213 #endif
214 const char * const gnupgext_version = "RNDW32 ($Revision$)";
215
216 static struct {
217     int class;
218     int version;
219     void *func;
220 } func_table[] = {
221     { 40, 1, gather_random },
222     { 41, 1, gather_random_fast },
223 };
224
225
226 #ifndef IS_MODULE
227 static
228 #endif
229 void *
230 gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
231 {
232     void *ret;
233     int i = *sequence;
234
235     do {
236         if ( i >= DIM(func_table) || i < 0 ) {
237             return NULL;
238         }
239         *class = func_table[i].class;
240         *vers  = func_table[i].version;
241         ret = func_table[i].func;
242         i++;
243     } while ( what && what != *class );
244
245     *sequence = i;
246     return ret;
247 }
248
249 #ifdef USE_STATIC_RNDW32
250 void
251 rndw32_set_dll_name( const char *name )
252 {
253     entropy_dll = m_strdup( name );
254 }
255 #endif
256
257 #ifndef IS_MODULE
258 void
259 rndw32_constructor(void)
260 {
261     register_internal_cipher_extension( gnupgext_version,
262                                         gnupgext_enum_func );
263 }
264 #endif
265