/* rndw32.c - interface to the Winseed DLL * Copyright (C) 1999 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include "types.h" #include "util.h" #include "dynload.h" #ifdef IS_MODULE #define _(a) (a) #else #include "i18n.h" #endif #define WIN32_SLOW_SEEDER 0 #define WIN32_FAST_SEEDER 1 #define PCP_SUCCESS 0 #define PCP_NULL_POINTER 1 #define PCP_SEEDER_FAILED 2 #define PCP_SEEDER_NO_MEM 3 #define PCP_SEEDER_TOO_SMALL 4 #define PCP_DLL_LOAD_FAILED 5 #define PCP_UNKNOWN_PLATFORM 6 #define PCP_ERROR_VERSION 7 #define PCP_DLL_FUNC 8 #define PCP_UNKNOWN_SEEDER_TYPE 9 typedef void *WIN32_SEEDER; static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason); static void (WINAPI *delete_instance)( WIN32_SEEDER that ); static unsigned int (WINAPI *get_internal_seed_size)( WIN32_SEEDER that ); static void (WINAPI *set_internal_seed_size)( WIN32_SEEDER that, unsigned int new_size); static unsigned int (WINAPI *get_expected_seed_size)( WIN32_SEEDER that); static unsigned int (WINAPI *get_seed)( WIN32_SEEDER that, byte *buffer, unsigned int *desired_length); static WIN32_SEEDER slow_seeder, fast_seeder; static byte *entropy_buffer; static size_t entropy_buffer_size; /**************** * Load and initialize the winseed DLL * NOTE: winseed is not part of the GnuPG distribution. It should be available * at the GNU crypto FTP server site. * We do not load the DLL on demand to have a better control over the * location of the library. */ static void load_and_init_winseed( void ) { int hInstance; void *addr; unsigned int reason = 0; unsigned int n1, n2; const char *dllname; dllname = read_w32_registry_string( "HKEY_LOCAL_MACHINE", "Software\\GNU\\GnuPG", "EntropyDLL" ); if( !dllname ) dllname = "c:/gnupg/entropy.dll"; hInstance = LoadLibrary( dllname ); if( !hInstance ) goto failure; if( !(addr = GetProcAddress( hInstance, "WS_create_instance" )) ) goto failure; create_instance = addr; if( !(addr = GetProcAddress( hInstance, "WS_delete_instance" )) ) goto failure; delete_instance = addr; if( !(addr = GetProcAddress( hInstance, "WS_get_internal_seed_size" )) ) goto failure; get_internal_seed_size = addr; if( !(addr = GetProcAddress( hInstance, "WS_set_internal_seed_size" )) ) goto failure; set_internal_seed_size = addr; if( !(addr = GetProcAddress( hInstance, "WS_get_expected_seed_size" )) ) goto failure; get_expected_seed_size = addr; if( !(addr = GetProcAddress( hInstance, "WS_get_seed" )) ) goto failure; get_seed = addr; /* we have all the functions - init the system */ slow_seeder = create_instance( WIN32_SLOW_SEEDER, &reason); if( !slow_seeder ) { g10_log_fatal("error creating winseed slow seeder: rc=%u\n", reason ); goto failure; } fast_seeder = create_instance( WIN32_FAST_SEEDER, &reason); if( !fast_seeder ) { g10_log_fatal("error creating winseed fast seeder: rc=%u\n", reason ); goto failure; } n1 = get_internal_seed_size( slow_seeder ); /*g10_log_info("slow buffer size=%u\n", n1);*/ n2 = get_internal_seed_size( fast_seeder ); /*g10_log_info("fast buffer size=%u\n", n2);*/ entropy_buffer_size = n1 > n2? n1: n2; entropy_buffer = m_alloc( entropy_buffer_size ); /*g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );*/ return; failure: g10_log_fatal("error loading winseed DLL `%s'\n", dllname ); } /* Note: we always use the highest level. * TO boost the performance we may want to add some * additional code for level 1 */ static int gather_random( void (*add)(const void*, size_t, int), int requester, size_t length, int level ) { unsigned int result; unsigned int nbytes; if( !slow_seeder ) load_and_init_winseed(); /* Our estimation on how much entropy we should use is very vague. * Winseed delivers some amount of entropy on each slow poll and * we add it to our random pool. Depending on the required quality * level we adjust the requested length so that for higer quality * we make sure to add more entropy to our pool. However, as we don't * like to waste any entropy collected by winseed, we always add * at least everything we got from winseed. */ if( level > 1 ) length *= 100; else if( level > 0 ) length *= 10; for(;;) { nbytes = entropy_buffer_size; result = get_seed( slow_seeder, entropy_buffer, &nbytes); if( result ) { g10_log_fatal("rndw32: get_seed(slow) failed: rc=%u\n", result); return -1; /* actually never reached */ } /*g10_log_info("rndw32: slow poll level %d, need %u, got %u\n", level, (unsigned int)length, (unsigned int)nbytes );*/ (*add)( entropy_buffer, nbytes, requester ); if( length <= nbytes ) return 0; /* okay */ length -= nbytes; } } static int gather_random_fast( void (*add)(const void*, size_t, int), int requester ) { unsigned int result; unsigned int nbytes; if( !fast_seeder ) load_and_init_winseed(); /* winseed delivers a constant ammount of entropy for a fast * poll. We can simply use this and add it to the pool; no need * a loop like it is used in the slow poll */ nbytes = entropy_buffer_size; result = get_seed( fast_seeder, entropy_buffer, &nbytes); if( result ) { g10_log_fatal("rndw32: get_seed(fast) failed: rc=%u\n", result); return -1; /* actually never reached */ } /*g10_log_info("rndw32: fast poll got %u\n", (unsigned int)nbytes );*/ (*add)( entropy_buffer, nbytes, requester ); return 0; } #ifndef IS_MODULE static #endif const char * const gnupgext_version = "RNDW32 ($Revision$)"; static struct { int class; int version; void *func; } func_table[] = { { 40, 1, gather_random }, { 41, 1, gather_random_fast }, }; #ifndef IS_MODULE static #endif void * gnupgext_enum_func( int what, int *sequence, int *class, int *vers ) { void *ret; int i = *sequence; do { if ( i >= DIM(func_table) || i < 0 ) { return NULL; } *class = func_table[i].class; *vers = func_table[i].version; ret = func_table[i].func; i++; } while ( what && what != *class ); *sequence = i; return ret; } #ifndef IS_MODULE void rndw32_constructor(void) { register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func ); } #endif