diff options
author | Werner Koch <wk@gnupg.org> | 1999-09-18 10:17:18 +0000 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 1999-09-18 10:17:18 +0000 |
commit | a1934b9e7193801ab58529064c02edb1ee2aa57e (patch) | |
tree | c8e096d0806c4d43738ea83e40e554ae31c726f2 | |
parent | 3cc20e7cad424e807921ee52b30db262febca6ff (diff) | |
download | libgcrypt-a1934b9e7193801ab58529064c02edb1ee2aa57e.tar.gz |
See ChangeLog: Sat Sep 18 12:16:08 CEST 1999 Werner Koch
-rw-r--r-- | cipher/Makefile.am | 5 | ||||
-rw-r--r-- | cipher/cipher.c | 1 | ||||
-rw-r--r-- | cipher/rndw32.c | 265 | ||||
-rw-r--r-- | src/gcrypt.h | 30 | ||||
-rw-r--r-- | src/mdapi.c | 25 | ||||
-rw-r--r-- | src/symapi.c | 181 |
6 files changed, 458 insertions, 49 deletions
diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 3d9a5cb9..e68ee19f 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -99,4 +99,9 @@ rndlinux: $(srcdir)/rndlinux.c rndegd: $(srcdir)/rndegd.c $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndegd $(srcdir)/rndegd.c +# We need to have a better system for selection which modules +# to compile. For now this works. +rndw32: $(srcdir)/rndw32.c + echo "#!/bin/sh" >rndw32 + echo "Not usable as a module" >>rndw32 diff --git a/cipher/cipher.c b/cipher/cipher.c index 990671fc..7224ab69 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -362,6 +362,7 @@ cipher_open( int algo, int mode, int secure ) if( algo == CIPHER_ALGO_DUMMY ) hd->mode = CIPHER_MODE_DUMMY; else if( mode == CIPHER_MODE_AUTO_CFB ) { + #warning Remove this code and the AUTO:CFB macro. if( algo >= 100 ) hd->mode = CIPHER_MODE_CFB; else diff --git a/cipher/rndw32.c b/cipher/rndw32.c new file mode 100644 index 00000000..032d666a --- /dev/null +++ b/cipher/rndw32.c @@ -0,0 +1,265 @@ +/* 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 <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> +#include <string.h> + +#include <windows.h> + +#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; + +static char *entropy_dll; + +/**************** + * 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 = entropy_dll? entropy_dll : "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; + } + g10_log_info("slow and fast seeders created.\n"); + 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; + g10_log_info("rndw32: need more\n"); + } +} + +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; +} + +#ifdef USE_STATIC_RNDW32 +void +rndw32_set_dll_name( const char *name ) +{ + entropy_dll = m_strdup( name ); +} +#endif + +#ifndef IS_MODULE +void +rndw32_constructor(void) +{ + register_internal_cipher_extension( gnupgext_version, + gnupgext_enum_func ); +} +#endif + diff --git a/src/gcrypt.h b/src/gcrypt.h index 5172be62..cb4cb43f 100644 --- a/src/gcrypt.h +++ b/src/gcrypt.h @@ -61,6 +61,9 @@ enum gcry_ctl_cmds { GCRYCTL_CFB_SYNC = 3, GCRYCTL_RESET = 4, /* e.g. for MDs */ GCRYCTL_FINALIZE = 5, + GCRYCTL_GET_KEYLEN = 6, + GCRYCTL_GET_BLKLEN = 7, + GCRYCTL_TEST_ALGO = 8, }; int gcry_control( enum gcry_ctl_cmds, ... ); @@ -181,20 +184,20 @@ enum gcry_cipher_flags { #if 0 /* not yet done */ int gcry_string_to_cipher_algo( const char *string ); -const char * gcry_cipher_algo_to_string( int algo ); int gcry_check_cipher_algo( int algo ); -unsigned gcry_cipher_get_keylen( int algo ); -unsigned gcry_cipher_get_blocksize( int algo ); #endif -int gcry_cipher_open( GCRY_CIPHER_HD *rhd, int algo, int mode, unsigned flags); +GCRY_CIPHER_HD r gcry_cipher_open( int algo, int mode, unsigned flags); void gcry_cipher_close( GCRY_CIPHER_HD h ); int gcry_cipher_ctl( GCRY_CIPHER_HD h, int cmd, byte *buffer, size_t buflen); +int gcry_cipher_info( GCRY_CIPHER_HD h, int what, void *buffer, size_t *nbytes); +int gcry_cipher_algo_info( int algo, int what, void *buffer, size_t *nbytes); +const char *gcry_cipher_algo_name( int algo ); int gcry_cipher_encrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize, - byte *in, size_t inlen ); + const byte *in, size_t inlen ); int gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize, - byte *in, size_t inlen ); + const byte *in, size_t inlen ); /* some handy macros */ @@ -205,6 +208,13 @@ int gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize, #define gcry_cipher_sync(h) gcry_cipher_ctl( (h), GCRYCTL_CFB_SYNC, \ NULL, 0 ) +#define gcry_cipher_get_algo_keylen(a) \ + gcry_cipher_algo_info( (a), GCRYCTL_GET_KEYLEN, NULL, NULL ); +#define gcry_cipher_get_algo_blklen(a) \ + gcry_cipher_algo_info( (a), GCRYCTL_GET_BLKLEN, NULL, NULL ); +#define gcry_cipher_test_algo(a) \ + gcry_cipher_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL ); + /********************************************* ******* asymmetric cipher functions ******* @@ -236,16 +246,16 @@ enum gcry_md_flags { }; -int gcry_md_open( GCRY_MD_HD *ret_hd, int algo, unsigned flags ); +GCRY_MD_HD gcry_md_open( int algo, unsigned flags ); void gcry_md_close( GCRY_MD_HD hd ); int gcry_md_enable( GCRY_MD_HD hd, int algo ); GCRY_MD_HD gcry_md_copy( GCRY_MD_HD hd ); int gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen); void gcry_md_write( GCRY_MD_HD hd, const byte *buffer, size_t length); byte *gcry_md_read( GCRY_MD_HD hd, int algo ); -int gcry_md_algo( GCRY_MD_HD hd ); -size_t gcry_md_dlen( int algo ); -int gcry_md_get( GCRY_MD_HD hd, int algo, byte *buffer, int buflen ); +int gcry_md_get_algo( GCRY_MD_HD hd ); +int gcry_md_get_dlen( int algo ); +/*??int gcry_md_get( GCRY_MD_HD hd, int algo, byte *buffer, int buflen );*/ /***************************************** diff --git a/src/mdapi.c b/src/mdapi.c index a0bbc648..5fd2eb61 100644 --- a/src/mdapi.c +++ b/src/mdapi.c @@ -31,16 +31,13 @@ #include "memory.h" -int -gcry_md_open( GCRY_MD_HD *ret_hd, int algo, unsigned flags ) +GCRY_MD_HD +gcry_md_open( GCRY_MD_HD *ret_hd, int algo, unsigned int flags ) { - GCRY_MD_HD hd; - /* fixme: check that algo is available and that only valid * flag values are used */ hd = md_open( algo, (flags & GCRY_MD_FLAG_SECURE) ); - *ret_hd = hd; - return 0; + return hd; } void @@ -68,8 +65,6 @@ gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen) { if( cmd == GCRYCTL_FINALIZE ) md_final( hd ); - else if( cmd == GCRYCTL_FINALIZE ) - md_final( hd ); else return GCRYERR_INV_OP; return 0; @@ -93,16 +88,17 @@ gcry_md_read( GCRY_MD_HD hd, int algo ) } int -gcry_md_algo( GCRY_MD_HD hd ) +gcry_md_get_algo( GCRY_MD_HD hd ) { - return md_get_algo( hd ); + return md_get_algo( hd ); /* fixme: we need error handling */ } /**************** * Return the length of the digest in bytes. + * This function will return 0 in case of errors. */ -size_t -gcry_md_dlen( int algo ) +unsigned int +gcry_md_get_algo_dlen( int algo ) { /* we do some very quick checks here */ switch( algo ) @@ -110,7 +106,10 @@ gcry_md_dlen( int algo ) case GCRY_MD_MD5: return 16; case GCRY_MD_SHA1: case GCRY_MD_RMD160: return 20; - default: return 0; /* fixme: pass it to a lookup function */ + default: + /* fixme: pass it to a lookup function */ + set_lasterr( GCRYERR_INV_ALGO ); + return -1; } } diff --git a/src/symapi.c b/src/symapi.c index e2aca4e2..5cd21775 100644 --- a/src/symapi.c +++ b/src/symapi.c @@ -49,48 +49,60 @@ struct gcry_cipher_context { }; -int -gcry_cipher_open( GCRY_CIPHER_HD *ret_hd, int algo, int mode, unsigned flags ) +GCRY_CIPHER_HD +gcry_cipher_open( int algo, int mode, unsigned flags ) { GCRY_CIPHER_HD h; /* check whether the algo is available */ - if( check_cipher_algo( algo ) ) - return set_lasterr( GCRYERR_INV_ALGO ); + if( check_cipher_algo( algo ) ) { + set_lasterr( GCRYERR_INV_ALGO ); + return NULL; + } /* check flags */ - if( (flags & ~(GCRY_CIPHER_SECURE|GCRY_CIPHER_ENABLE_SYNC)) ) - return set_lasterr( GCRYERR_INV_ARG ); + if( (flags & ~(GCRY_CIPHER_SECURE|GCRY_CIPHER_ENABLE_SYNC)) ) { + set_lasterr( GCRYERR_INV_ARG ); + return NULL; + } /* map mode to internal mode */ switch( mode ) { - case GCRY_CIPHER_MODE_NONE: mode = CIPHER_MODE_DUMMY; break; - case GCRY_CIPHER_MODE_ECB: mode = CIPHER_MODE_ECB; break; + case GCRY_CIPHER_MODE_NONE: + mode = CIPHER_MODE_DUMMY; + break; + case GCRY_CIPHER_MODE_ECB: + mode = CIPHER_MODE_ECB; + break; case GCRY_CIPHER_MODE_CFB: mode = (flags & GCRY_CIPHER_ENABLE_SYNC) ? CIPHER_MODE_PHILS_CFB : CIPHER_MODE_CFB; break; - case GCRY_CIPHER_MODE_CBC: mode = CIPHER_MODE_CBC; break; + case GCRY_CIPHER_MODE_CBC: mode = CIPHER_MODE_CBC; + break; default: - return set_lasterr( GCRYERR_INV_ALGO ); + set_lasterr( GCRYERR_INV_ALGO ); + return NULL; } /* FIXME: issue a warning when CIPHER_MODE_NONE is used */ /* allocate the handle */ h = m_lib_alloc_clear( sizeof *h ); - if( !h ) - return set_lasterr( GCRYERR_NOMEM ); + if( !h ) { + set_lasterr( GCRYERR_NOMEM ); + return NULL; + } h->magic = CONTEXT_MAGIC; h->mode = mode; h->hd = cipher_open( algo, mode, (flags & GCRY_CIPHER_SECURE) ); if( !h ) { m_lib_free( h ); - return set_lasterr( GCRYERR_INTERNAL ); + set_lasterr( GCRYERR_INTERNAL ); + return NULL; } - *ret_hd = h; - return 0; + return h; } @@ -126,26 +138,143 @@ int gcry_cipher_ctl( GCRY_CIPHER_HD h, int cmd, byte *buffer, size_t buflen) } +/**************** + * Return information about the cipher handle. + * -1 is returned on error and gcry_errno() may be used to get more information + * about the error. + */ +int +gcry_cipher_info( GCRY_CIPHER_HD h, int cmd, byte *buffer, size_t *nbytes) +{ + switch( cmd ) { + default: + set_lasterr( GCRYERR_INV_OP ); + return -1; + } + return 0; +} + +/**************** + * Return information about the given cipher algorithm + * WHAT select the kind of information returned: + * GCRYCTL_GET_KEYLEN: + * Return the length of the key, if the algorithm + * supports multiple key length, the maximum supported value + * is returnd. The length is return as number of octets. + * buffer and nbytes must be zero. + * GCRYCTL_GET_BLKLEN: + * Return the blocklength of the algorithm counted in octets. + * buffer and nbytes must be zero. + * GCRYCTL_TEST_ALGO: + * Returns 0 when the specified algorithm is available for use. + * buffer and nbytes must be zero. + * + * On error the value -1 is returned and the error reason may be + * retrieved by gcry_errno(). + * Note: Because this function is in most caes used to return an + * integer value, we can make it easier for the caller to just look at + * the return value. The caller will in all cases consult the value + * and thereby detecting whether a error occured or not (i.e. while checking + * the block size) + */ +int +gcry_cipher_algo_info( int algo, int what, void *buffer, size_t *nbytes) +{ + switch( what ) { + case GCRYCTL_GET_KEYLEN: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + return -1; + } + BUG(); /* FIXME: implement this */ + break; + + case GCRYCTL_GET_BLKLEN: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + return -1; + } + ui = cipher_get_blocksize( algo ); + if( ui > 0 && ui < 10000 ) + return (int)ui; + /* the only reason is an invalid algo or a strange blocksize */ + set_lasterr( GCRYERR_INV_ALGO ); + return -1; + + case GCRYCTL_TEST_ALGO: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + return -1; + } + if( check_cipher_algo( algo ) ) { + set_lasterr( GCRYERR_INV_ALGO ); + return -1; + } + return 0; + + + default: + set_lasterr( GCRYERR_INV_OP ); + return -1; + } + return 0; +} + + +/**************** + * This function simply returns the name of the algorithm or soem constant + * string when there is no algo. It will never return NULL. + */ +const char * +gcry_cipher_algo_name( int algo ) +{ + return cipher_algo_to_string( algo ); +} + + +/**************** + * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has + * been requested, + */ int gcry_cipher_encrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize, - byte *in, size_t inlen ) + const byte *in, size_t inlen ) { - if( outsize < inlen ) - return set_lasterr( GCRYERR_TOO_SHORT ); - /* fixme: check that the inlength is a multipe of the blocksize - * if a blockoriented mode is used, or modify cipher_encrypt to - * return an error in this case */ - cipher_encrypt( h->hd, out, in, inlen ); + if( !in ) { + /* caller requested in-place encryption */ + /* actullay cipher_encrypt() does not need to know about it, but + * we may chnage this to get better performace */ + cipher_encrypt( h->hd, out, out, outsize ); + } + else { + if( outsize < inlen ) + return set_lasterr( GCRYERR_TOO_SHORT ); + /* fixme: check that the inlength is a multipe of the blocksize + * if a blockoriented mode is used, or modify cipher_encrypt to + * return an error in this case */ + cipher_encrypt( h->hd, out, in, inlen ); + } return 0; } int gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize, - byte *in, size_t inlen ) + const byte *in, size_t inlen ) { - if( outsize < inlen ) - return set_lasterr( GCRYERR_TOO_SHORT ); - cipher_decrypt( h->hd, out, in, inlen ); + if( !in ) { + /* caller requested in-place encryption */ + /* actullay cipher_encrypt() does not need to know about it, but + * we may chnage this to get better performace */ + cipher_decrypt( h->hd, out, out, outsize ); + } + else { + if( outsize < inlen ) + return set_lasterr( GCRYERR_TOO_SHORT ); + /* fixme: check that the inlength is a multipe of the blocksize + * if a blockoriented mode is used, or modify cipher_encrypt to + * return an error in this case */ + cipher_decrypt( h->hd, out, in, inlen ); + } return 0; } |