summaryrefslogtreecommitdiff
path: root/cipher
diff options
context:
space:
mode:
Diffstat (limited to 'cipher')
-rw-r--r--cipher/ChangeLog82
-rw-r--r--cipher/Makefile.am19
-rw-r--r--cipher/blowfish.c9
-rw-r--r--cipher/cast5.c10
-rw-r--r--cipher/des.c9
-rw-r--r--cipher/dsa.c19
-rw-r--r--cipher/elgamal.c141
-rw-r--r--cipher/md.c10
-rw-r--r--cipher/md5.c8
-rw-r--r--cipher/primegen.c25
-rw-r--r--cipher/pubkey.c59
-rw-r--r--cipher/random.c204
-rw-r--r--cipher/rmd160.c8
-rw-r--r--cipher/rndegd.c11
-rw-r--r--cipher/rndunix.c53
-rw-r--r--cipher/rndw32.c739
-rw-r--r--cipher/rsa.c375
-rw-r--r--cipher/rsa.h36
-rw-r--r--cipher/sha1.c8
-rw-r--r--cipher/tiger.c8
-rw-r--r--cipher/twofish.c28
21 files changed, 1722 insertions, 139 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 49595a93..877a2ad2 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,85 @@
+Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@>
+
+ * md.c (gcry_md_ctl): Support GCRYCTL_{START,STOP}_DUMP.
+
+ * Makefile.am: Never compile mingw32 as module.
+
+ * Makefile.am: Tweaked module build and removed libtool
+
+ * Makefile.am: Replaced -O1 by -O. Suggested by Alec Habig.
+
+ * elgamal.c (sign): Removed inactive code.
+
+ * rsa.c, rsa.h: New based on the old module version (only in CVS for now).
+ * pubkey.c (setup_pubkey_table): Added commented support for RSA.
+
+ * rndunix.c (waitpid): New. For UTS 2.1. All by Dave Dykstra.
+ (my_popen): Do the FD_CLOEXEC only if it is available
+ (start_gatherer): Cope with missing _SC_OPEN_MAX
+
+ * rndunix.c: Add some more headers for QNX. By Sam Roberts.
+
+ * rndegd.c (gather_random): Shortcut level 0.
+ * rndunix.c (gather_random): Ditto.
+ * rndw32.c (gather_random): Ditto.
+
+ * rndw32.c: Replaced with code from Cryptlib and commented the old stuff.
+ * rndw32.c: Add some debuging code enabled by an environment variable.
+
+ * random.c (read_seed_file): Binary open for DOSish system
+ (update_random_seed_file): Ditto.
+ * random.c [MINGW32]: Include process.h for getpid.
+ * random.c (fast_random_poll): Add clock_gettime() as fallback for
+ system which support this POSIX.4 fucntion. By Sam Roberts.
+
+ * random.c (read_seed_file): Removed the S_ISLNK test becuase it
+ is already covered by !S_ISREG and is not defined in Unixware.
+ Reported by Dave Dykstra.
+ (update_random_seed_file): Silently ignore update request when pool
+ is not filled.
+
+ * random.c (read_seed_file): New.
+ (set_random_seed_file): New.
+ (read_pool): Try to read the seeding file.
+ (update_random_seed_file): New.
+
+ (read_pool): Do an initial extra seeding when level 2 quality random
+ is requested the first time. This requestes at least POOLSIZE/2 bytes
+ of entropy. Compined with the seeding file this should make normal
+ random bytes cheaper and increase the quality of the random bytes
+ used for key generation.
+
+ * random.c (read_pool): Print a more friendly error message in
+ cases when too much random is requested in one call.
+
+ * random.c (fast_random_poll): Check whether RUSAGE_SELF is defined;
+ this is not the case for some ESIX and Unixware, although they have
+ getrusage().
+
+ * primegen.c (generate_elg_prime): All primes are now generated with
+ the lowest random quality level. Because they are public anyway we
+ don't need stronger random and by this we do not drain the systems
+ entropy so much.
+
+ * primegen.c (register_primegen_progress): New.
+ * dsa.c (register_pk_dsa_progress): New.
+ * elgamal.c (register_pk_elg_progress): New.
+
+ * elgamal.c (wiener_map): New.
+ (gen_k): Use a much smaller k.
+ (generate): Calculate the qbits using the wiener map and
+ choose an x at a size comparable to the one choosen in gen_k
+
+ * rmd160.c (rmd160_get_info): Moved casting to the left side due to a
+ problem with UTS4.3. Suggested by Dave Dykstra.
+ * sha1.c (sha1_get_info): Ditto.
+ * tiger.c (tiger_get_info): Ditto.
+ * md5.c (md5_get_info): Ditto
+ * des.c (des_get_info): Ditto.
+ * blowfish.c (blowfish_get_info): Ditto.
+ * cast5.c (cast5_get_info): Ditto.
+ * twofish.c (twofish_get_info): Ditto.
+
Fri Mar 24 11:25:45 CET 2000 Werner Koch <wk@openit.de>
* md.c (md_open): Add hmac arg and allocate space for the pads.
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index aa766bbc..9792419f 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -5,15 +5,8 @@ INCLUDES = -I$(top_srcdir)/gcrypt
noinst_LTLIBRARIES = libcipher.la
-# The configure script greps the module names from the following lines.
-# You must also add all these names to EXTRA_PROGRAMS some lines below
-# and EXTRA_foo_SOURCES entries.
-# Hmmm is there a more easy way to do this? (EXTRA_PROGRAMS
-# might also list programs which are not modules)
-# MODULES: rndunix rndlinux rndegd rndw32
-# MODULES: sha1 rmd160 md5 tiger
-EXTRA_PROGRAMS = rndunix rndlinux rndegd rndw32 \
- sha1 rmd160 md5 tiger
+# The configure script greps the module names from the EXTRA_PROGRAMS line
+EXTRA_PROGRAMS = rndlinux rndunix rndegd rndw32 sha1 rmd160 md5 tiger
EXTRA_rndlinux_SOURCES = rndlinux.c
EXTRA_rndunix_SOURCES = rndunix.c
@@ -73,7 +66,7 @@ libcipher_la_LIBADD = @STATIC_CIPHER_OBJS@
tiger: $(srcdir)/tiger.c
`echo $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o tiger $(srcdir)/tiger.c | \
- sed -e 's/-O[2-9s]*/-O1/g' `
+ sed -e 's/-O[2-9s]*/-O/g' `
tiger.o: $(srcdir)/tiger.c
`echo $(COMPILE) -c $(srcdir)/tiger.c | sed -e 's/-O[2-9s]*/-O1/g' `
@@ -98,9 +91,3 @@ 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/blowfish.c b/cipher/blowfish.c
index e7f047ff..2bdb3b5e 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -584,9 +584,12 @@ blowfish_get_info( int algo, size_t *keylen,
*keylen = 128;
*blocksize = BLOWFISH_BLOCKSIZE;
*contextsize = sizeof(BLOWFISH_context);
- *r_setkey = FNCCAST_SETKEY(bf_setkey);
- *r_encrypt= FNCCAST_CRYPT(encrypt_block);
- *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+ *(int (**)(BLOWFISH_context*, byte*, unsigned))r_setkey
+ = bf_setkey;
+ *(void (**)(BLOWFISH_context*, byte*, byte*))r_encrypt
+ = encrypt_block;
+ *(void (**)(BLOWFISH_context*, byte*, byte*))r_decrypt
+ = decrypt_block;
if( algo == CIPHER_ALGO_BLOWFISH )
return "BLOWFISH";
diff --git a/cipher/cast5.c b/cipher/cast5.c
index aaa0a42e..64f6bb0e 100644
--- a/cipher/cast5.c
+++ b/cipher/cast5.c
@@ -610,9 +610,13 @@ cast5_get_info( int algo, size_t *keylen,
*keylen = 128;
*blocksize = CAST5_BLOCKSIZE;
*contextsize = sizeof(CAST5_context);
- *r_setkey = FNCCAST_SETKEY(cast_setkey);
- *r_encrypt= FNCCAST_CRYPT(encrypt_block);
- *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+ *(int (**)(CAST5_context*, byte*, unsigned))r_setkey
+ = cast_setkey;
+ *(void (**)(CAST5_context*, byte*, byte*))r_encrypt
+ = encrypt_block;
+ *(void (**)(CAST5_context*, byte*, byte*))r_decrypt
+ = decrypt_block;
+
if( algo == CIPHER_ALGO_CAST5 )
return "CAST5";
diff --git a/cipher/des.c b/cipher/des.c
index af5b5845..9c3c5419 100644
--- a/cipher/des.c
+++ b/cipher/des.c
@@ -1001,9 +1001,12 @@ des_get_info( int algo, size_t *keylen,
*keylen = 192;
*blocksize = 8;
*contextsize = sizeof(struct _tripledes_ctx);
- *r_setkey = FNCCAST_SETKEY(do_tripledes_setkey);
- *r_encrypt= FNCCAST_CRYPT(do_tripledes_encrypt);
- *r_decrypt= FNCCAST_CRYPT(do_tripledes_decrypt);
+ *(int (**)(struct _tripledes_ctx*, byte*, unsigned))r_setkey
+ = do_tripledes_setkey;
+ *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_encrypt
+ = do_tripledes_encrypt;
+ *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_decrypt
+ = do_tripledes_decrypt;
return "3DES";
}
return NULL;
diff --git a/cipher/dsa.c b/cipher/dsa.c
index 1f132ae0..255fa372 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -1,5 +1,5 @@
/* dsa.c - DSA signature scheme
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -52,13 +52,28 @@ static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_dsa_progress ( void (*cb)( void *, int), void *cb_data )
+{
+ progress_cb = cb;
+ progress_cb_data = cb_data;
+}
+
+
static void
progress( int c )
{
- fputc( c, stderr );
+ if ( progress_cb )
+ progress_cb ( progress_cb_data, c );
+ else
+ fputc( c, stderr );
}
+
/****************
* Generate a random secret exponent k less than q
*/
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index 02995e02..f2c029b3 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -1,5 +1,5 @@
/* elgamal.c - ElGamal Public Key encryption
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
@@ -56,13 +56,67 @@ static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey);
static int verify(MPI a, MPI b, MPI input, ELG_public_key *pkey);
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_elg_progress ( void (*cb)( void *, int), void *cb_data )
+{
+ progress_cb = cb;
+ progress_cb_data = cb_data;
+}
+
+
static void
progress( int c )
{
- fputc( c, stderr );
+ if ( progress_cb )
+ progress_cb ( progress_cb_data, c );
+ else
+ fputc( c, stderr );
}
+/****************
+ * Michael Wiener's table on subgroup sizes to match field sizes
+ * (floating around somewhere - Fixme: need a reference)
+ */
+static unsigned int
+wiener_map( unsigned int n )
+{
+ static struct { unsigned int p_n, q_n; } t[] =
+ { /* p q attack cost */
+ { 512, 119 }, /* 9 x 10^17 */
+ { 768, 145 }, /* 6 x 10^21 */
+ { 1024, 165 }, /* 7 x 10^24 */
+ { 1280, 183 }, /* 3 x 10^27 */
+ { 1536, 198 }, /* 7 x 10^29 */
+ { 1792, 212 }, /* 9 x 10^31 */
+ { 2048, 225 }, /* 8 x 10^33 */
+ { 2304, 237 }, /* 5 x 10^35 */
+ { 2560, 249 }, /* 3 x 10^37 */
+ { 2816, 259 }, /* 1 x 10^39 */
+ { 3072, 269 }, /* 3 x 10^40 */
+ { 3328, 279 }, /* 8 x 10^41 */
+ { 3584, 288 }, /* 2 x 10^43 */
+ { 3840, 296 }, /* 4 x 10^44 */
+ { 4096, 305 }, /* 7 x 10^45 */
+ { 4352, 313 }, /* 1 x 10^47 */
+ { 4608, 320 }, /* 2 x 10^48 */
+ { 4864, 328 }, /* 2 x 10^49 */
+ { 5120, 335 }, /* 3 x 10^50 */
+ { 0, 0 }
+ };
+ int i;
+
+ for(i=0; t[i].p_n; i++ ) {
+ if( n <= t[i].p_n )
+ return t[i].q_n;
+ }
+ /* not in table - use some arbitrary high number ;-) */
+ return n / 8 + 200;
+}
+
static void
test_keys( ELG_secret_key *sk, unsigned nbits )
{
@@ -104,38 +158,44 @@ gen_k( MPI p )
MPI k = mpi_alloc_secure( 0 );
MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
MPI p_1 = mpi_copy(p);
- unsigned int nbits = mpi_get_nbits(p);
- unsigned int nbytes = (nbits+7)/8;
+ unsigned int orig_nbits = mpi_get_nbits(p);
+ unsigned int nbits, nbytes;
char *rndbuf = NULL;
+ /* IMO using a k much lesser than p is sufficient and it greatly
+ * improves the encryption performance. We use Wiener's table
+ * and add a large safety margin.
+ */
+ nbits = wiener_map( orig_nbits ) * 3 / 2;
+ if( nbits >= orig_nbits )
+ BUG();
+
+ nbytes = (nbits+7)/8;
if( DBG_CIPHER )
log_debug("choosing a random k ");
mpi_sub_ui( p_1, p, 1);
for(;;) {
- if( DBG_CIPHER )
- progress('.');
if( !rndbuf || nbits < 32 ) {
g10_free(rndbuf);
rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM );
}
else { /* change only some of the higher bits */
- /* we could imporove this by directly requesting more memory
+ /* we could improve this by directly requesting more memory
* at the first call to get_random_bytes() and use this the here
- * maybe it is easier to do this directly in random.c */
+ * maybe it is easier to do this directly in random.c
+ * Anyway, it is highly inlikely that we will ever reach this code
+ */
char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
memcpy( rndbuf, pp, 4 );
g10_free(pp);
+ log_debug("gen_k: tsss, never expected to reach this\n");
}
mpi_set_buffer( k, rndbuf, nbytes, 0 );
for(;;) {
- /* make sure that the number is of the exact lenght */
- if( mpi_test_bit( k, nbits-1 ) )
- mpi_set_highbit( k, nbits-1 );
- else {
- mpi_set_highbit( k, nbits-1 );
- mpi_clear_bit( k, nbits-1 );
- }
+ /* Hmm, actually we don't need this step here
+ * because we use k much smaller than p - we do it anyway
+ * just in case the keep on adding a one to k ;) */
if( !(mpi_cmp( k, p_1 ) < 0) ) { /* check: k < (p-1) */
if( DBG_CIPHER )
progress('+');
@@ -149,6 +209,8 @@ gen_k( MPI p )
if( mpi_gcd( temp, k, p_1 ) )
goto found; /* okay, k is relatively prime to (p-1) */
mpi_add_ui( k, k, 1 );
+ if( DBG_CIPHER )
+ progress('.');
}
}
found:
@@ -167,7 +229,7 @@ gen_k( MPI p )
* and an array with n-1 factors of (p-1)
*/
static void
-generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
+generate( ELG_secret_key *sk, unsigned int nbits, MPI **ret_factors )
{
MPI p; /* the prime */
MPI p_min1;
@@ -175,19 +237,15 @@ generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
MPI x; /* the secret exponent */
MPI y;
MPI temp;
- unsigned qbits;
+ unsigned int qbits;
+ unsigned int xbits;
byte *rndbuf;
p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
temp = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
- if( nbits < 512 )
- qbits = 120;
- else if( nbits <= 1024 )
- qbits = 160;
- else if( nbits <= 2048 )
- qbits = 200;
- else
- qbits = 240;
+ qbits = wiener_map( nbits );
+ if( qbits & 1 ) /* better have a even one */
+ qbits++;
g = mpi_alloc(1);
p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
mpi_sub_ui(p_min1, p, 1);
@@ -198,18 +256,26 @@ generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
* This must be a very good random number because this is the
* secret part. The prime is public and may be shared anyway,
* so a random generator level of 1 is used for the prime.
+ *
+ * I don't see a reason to have a x of about the same size
+ * as the p. It should be sufficient to have one about the size
+ * of q or the later used k plus a large safety margin. Decryption
+ * will be much faster with such an x.
*/
- x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
+ xbits = qbits * 3 / 2;
+ if( xbits >= nbits )
+ BUG();
+ x = mpi_alloc_secure( xbits/BITS_PER_MPI_LIMB );
if( DBG_CIPHER )
- log_debug("choosing a random x ");
+ log_debug("choosing a random x of size %u", xbits );
rndbuf = NULL;
do {
if( DBG_CIPHER )
progress('.');
if( rndbuf ) { /* change only some of the higher bits */
- if( nbits < 16 ) {/* should never happen ... */
+ if( xbits < 16 ) {/* should never happen ... */
g10_free(rndbuf);
- rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+ rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
GCRY_VERY_STRONG_RANDOM );
}
else {
@@ -220,11 +286,11 @@ generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
}
}
else {
- rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+ rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
GCRY_VERY_STRONG_RANDOM );
}
- mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 );
- mpi_clear_highbit( x, nbits+1 );
+ mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 );
+ mpi_clear_highbit( x, xbits+1 );
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
g10_free(rndbuf);
@@ -311,7 +377,6 @@ decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
/* output = b/(a^x) mod p */
-
gcry_mpi_powm( t1, a, skey->x, skey->p );
mpi_invm( t1, t1, skey->p );
mpi_mulm( output, b, t1, skey->p );
@@ -351,10 +416,6 @@ sign(MPI a, MPI b, MPI input, ELG_secret_key *skey )
gcry_mpi_powm( a, skey->g, k, skey->p );
mpi_mul(t, skey->x, a );
mpi_subm(t, input, t, p_1 );
- while( mpi_is_neg(t) ) {
- BUG(); /* That is nonsense code - left over from a very early test?*/
- mpi_add(t, t, p_1);
- }
mpi_invm(inv, k, p_1 );
mpi_mulm(b, t, inv, p_1 );
@@ -557,7 +618,7 @@ elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
-unsigned
+unsigned int
elg_get_nbits( int algo, MPI *pkey )
{
if( !is_ELGAMAL(algo) )
@@ -587,10 +648,10 @@ elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
*nsig = 2;
switch( algo ) {
- case PUBKEY_ALGO_ELGAMAL:
+ case GCRY_PK_ELG:
*use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
return "ELG";
- case PUBKEY_ALGO_ELGAMAL_E:
+ case GCRY_PK_ELG_E:
*use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
return "ELG-E";
default: *use = 0; return NULL;
diff --git a/cipher/md.c b/cipher/md.c
index 98795206..e8ac8ac2 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -562,6 +562,12 @@ gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen)
else if ( !(rc = prepare_macpads( hd, buffer, buflen )) )
gcry_md_reset( hd );
}
+ else if( cmd == GCRYCTL_START_DUMP ) {
+ md_start_debug( hd, buffer );
+ }
+ else if( cmd == GCRYCTL_STOP_DUMP ) {
+ md_stop_debug( hd );
+ }
else
rc = GCRYERR_INV_OP;
return set_lasterr( rc );
@@ -834,7 +840,7 @@ gcry_md_algo_info( int algo, int what, void *buffer, size_t *nbytes)
-void
+static void
md_start_debug( GCRY_MD_HD md, const char *suffix )
{
static int idx=0;
@@ -851,7 +857,7 @@ md_start_debug( GCRY_MD_HD md, const char *suffix )
log_debug("md debug: can't open %s\n", buf );
}
-void
+static void
md_stop_debug( GCRY_MD_HD md )
{
if( md->ctx->debug ) {
diff --git a/cipher/md5.c b/cipher/md5.c
index 161d4430..c4351f1f 100644
--- a/cipher/md5.c
+++ b/cipher/md5.c
@@ -344,10 +344,10 @@ md5_get_info( int algo, size_t *contextsize,
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 16;
- *r_init = (void (*)(void *))md5_init;
- *r_write = (void (*)(void *, byte*, size_t))md5_write;
- *r_final = (void (*)(void *))md5_final;
- *r_read = (byte *(*)(void *))md5_read;
+ *(void (**)(MD5_CONTEXT *))r_init = md5_init;
+ *(void (**)(MD5_CONTEXT *, byte*, size_t))r_write = md5_write;
+ *(void (**)(MD5_CONTEXT *))r_final = md5_final;
+ *(byte *(**)(MD5_CONTEXT *))r_read = md5_read;
return "MD5";
}
diff --git a/cipher/primegen.c b/cipher/primegen.c
index 2f16b083..f5dca859 100644
--- a/cipher/primegen.c
+++ b/cipher/primegen.c
@@ -1,5 +1,5 @@
/* primegen.c - prime number generator
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -38,11 +38,24 @@ static int check_prime( MPI prime, MPI val_2 );
static int is_prime( MPI n, int steps, int *count );
static void m_out_of_n( char *array, int m, int n );
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_primegen_progress ( void (*cb)( void *, int), void *cb_data )
+{
+ progress_cb = cb;
+ progress_cb_data = cb_data;
+}
+
static void
progress( int c )
{
- fputc( c, stderr );
+ if ( progress_cb )
+ progress_cb ( progress_cb_data, c );
+ else
+ fputc( c, stderr );
}
@@ -117,8 +130,8 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
pbits, req_qbits, qbits, fbits, n );
prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB );
- q = gen_prime( qbits, 0, 1 );
- q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL;
+ q = gen_prime( qbits, 0, 0 );
+ q_factor = mode==1? gen_prime( req_qbits, 0, 0 ) : NULL;
/* allocate an array to hold the factors + 2 for later usage */
factors = g10_xcalloc( n+2, sizeof *factors );
@@ -177,7 +190,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
count1 = 0;
qbits++;
progress('>');
- q = gen_prime( qbits, 0, 1 );
+ q = gen_prime( qbits, 0, 0 );
goto next_try;
}
}
@@ -188,7 +201,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
count2 = 0;
qbits--;
progress('<');
- q = gen_prime( qbits, 0, 1 );
+ q = gen_prime( qbits, 0, 0 );
goto next_try;
}
}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 3ace1d83..b139720d 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1,5 +1,5 @@
/* pubkey.c - pubkey dispatcher
- * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -30,6 +30,9 @@
#include "cipher.h"
#include "elgamal.h"
#include "dsa.h"
+#if 0
+#include "rsa.h"
+#endif
#include "dynload.h"
/* FIXME: use set_lasterr() */
@@ -193,6 +196,60 @@ setup_pubkey_table(void)
BUG();
i++;
+ #if 0
+ pubkey_table[i].algo = PUBKEY_ALGO_RSA;
+ pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+ &pubkey_table[i].npkey,
+ &pubkey_table[i].nskey,
+ &pubkey_table[i].nenc,
+ &pubkey_table[i].nsig,
+ &pubkey_table[i].use );
+ pubkey_table[i].generate = rsa_generate;
+ pubkey_table[i].check_secret_key = rsa_check_secret_key;
+ pubkey_table[i].encrypt = rsa_encrypt;
+ pubkey_table[i].decrypt = rsa_decrypt;
+ pubkey_table[i].sign = rsa_sign;
+ pubkey_table[i].verify = rsa_verify;
+ pubkey_table[i].get_nbits = rsa_get_nbits;
+ if( !pubkey_table[i].name )
+ BUG();
+ i++;
+ pubkey_table[i].algo = PUBKEY_ALGO_RSA_E;
+ pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+ &pubkey_table[i].npkey,
+ &pubkey_table[i].nskey,
+ &pubkey_table[i].nenc,
+ &pubkey_table[i].nsig,
+ &pubkey_table[i].use );
+ pubkey_table[i].generate = rsa_generate;
+ pubkey_table[i].check_secret_key = rsa_check_secret_key;
+ pubkey_table[i].encrypt = rsa_encrypt;
+ pubkey_table[i].decrypt = rsa_decrypt;
+ pubkey_table[i].sign = dummy_sign;
+ pubkey_table[i].verify = dummy_verify;
+ pubkey_table[i].get_nbits = rsa_get_nbits;
+ if( !pubkey_table[i].name )
+ BUG();
+ i++;
+ pubkey_table[i].algo = PUBKEY_ALGO_RSA_S;
+ pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+ &pubkey_table[i].npkey,
+ &pubkey_table[i].nskey,
+ &pubkey_table[i].nenc,
+ &pubkey_table[i].nsig,
+ &pubkey_table[i].use );
+ pubkey_table[i].generate = rsa_generate;
+ pubkey_table[i].check_secret_key = rsa_check_secret_key;
+ pubkey_table[i].encrypt = dummy_encrypt;
+ pubkey_table[i].decrypt = dummy_decrypt;
+ pubkey_table[i].sign = rsa_sign;
+ pubkey_table[i].verify = rsa_verify;
+ pubkey_table[i].get_nbits = rsa_get_nbits;
+ if( !pubkey_table[i].name )
+ BUG();
+ i++;
+ #endif
+
for( ; i < TABLE_SIZE; i++ )
pubkey_table[i].name = NULL;
}
diff --git a/cipher/random.c b/cipher/random.c
index 38991a18..f8faeebf 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -1,5 +1,5 @@
/* random.c - random number generator
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -36,15 +36,22 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <fcntl.h>
#ifdef HAVE_GETHRTIME
#include <sys/times.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
#include <sys/times.h>
#endif
+#ifdef HAVE_CLOCK_GETTIME
+ #include <time.h>
+#endif
#ifdef HAVE_GETRUSAGE
#include <sys/resource.h>
#endif
+#ifdef __MINGW32__
+ #include <process.h>
+#endif
#include "g10lib.h"
#include "rmd.h"
#include "random.h"
@@ -89,6 +96,9 @@ static size_t pool_writepos;
static int pool_filled;
static int pool_balance;
static int just_mixed;
+static int did_initial_extra_seeding;
+static char *seed_file_name;
+static int allow_seed_file_update;
static int secure_alloc;
static int quick_test;
@@ -274,6 +284,139 @@ mix_pool(byte *pool)
}
}
+void
+set_random_seed_file( const char *name )
+{
+ if( seed_file_name )
+ BUG();
+ seed_file_name = g10_xstrdup( name );
+}
+
+/****************
+ * Read in a seed form the random_seed file
+ * and return true if this was successful
+ */
+static int
+read_seed_file()
+{
+ int fd;
+ struct stat sb;
+ unsigned char buffer[POOLSIZE];
+ int n;
+
+ if( !seed_file_name )
+ return 0;
+
+ #ifdef HAVE_DOSISH_SYSTEM
+ fd = open( seed_file_name, O_RDONLY | O_BINARY );
+ #else
+ fd = open( seed_file_name, O_RDONLY );
+ #endif
+ if( fd == -1 && errno == ENOENT) {
+ allow_seed_file_update = 1;
+ return 0;
+ }
+
+ if( fd == -1 ) {
+ log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+ return 0;
+ }
+ if( fstat( fd, &sb ) ) {
+ log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+ close(fd);
+ return 0;
+ }
+ if( !S_ISREG(sb.st_mode) ) {
+ log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+ close(fd);
+ return 0;
+ }
+ if( !sb.st_size ) {
+ log_info(_("note: random_seed file is empty\n") );
+ close(fd);
+ allow_seed_file_update = 1;
+ return 0;
+ }
+ if( sb.st_size != POOLSIZE ) {
+ log_info(_("warning: invalid size of random_seed file - not used\n") );
+ close(fd);
+ return 0;
+ }
+ do {
+ n = read( fd, buffer, POOLSIZE );
+ } while( n == -1 && errno == EINTR );
+ if( n != POOLSIZE ) {
+ log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ add_randomness( buffer, POOLSIZE, 0 );
+ /* add some minor entropy to the pool now (this will also force a mixing) */
+ { pid_t x = getpid();
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ { time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ { clock_t x = clock();
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ /* And read a few bytes from our entropy source. By using
+ * a level of 0 this will not block and might not return anything
+ * with some entropy drivers, however the rndlinux driver will use
+ * /dev/urandom and return some stuff - Do not read to much as we
+ * want to be friendly to the scare system entropy resource. */
+ read_random_source( 0, 16, 0 );
+
+ allow_seed_file_update = 1;
+ return 1;
+}
+
+void
+update_random_seed_file()
+{
+ ulong *sp, *dp;
+ int fd, i;
+
+ if( !seed_file_name || !is_initialized || !pool_filled )
+ return;
+ if( !allow_seed_file_update ) {
+ log_info(_("note: random_seed file not updated\n"));
+ return;
+ }
+
+
+ /* copy the entropy pool to a scratch pool and mix both of them */
+ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+ i < POOLWORDS; i++, dp++, sp++ ) {
+ *dp = *sp + ADD_VALUE;
+ }
+ mix_pool(rndpool); rndstats.mixrnd++;
+ mix_pool(keypool); rndstats.mixkey++;
+
+ #ifdef HAVE_DOSISH_SYSTEM
+ fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+ S_IRUSR|S_IWUSR );
+ #else
+ fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+ #endif
+ if( fd == -1 ) {
+ log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+ return;
+ }
+ do {
+ i = write( fd, keypool, POOLSIZE );
+ } while( i == -1 && errno == EINTR );
+ if( i != POOLSIZE ) {
+ log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
+ }
+ if( close(fd) )
+ log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
+}
+
static void
read_pool( byte *buffer, size_t length, int level )
@@ -281,8 +424,31 @@ read_pool( byte *buffer, size_t length, int level )
int i;
ulong *sp, *dp;
- if( length >= POOLSIZE )
- BUG(); /* not allowed */
+ if( length >= POOLSIZE ) {
+ log_fatal(_("too many random bits requested; the limit is %d\n"),
+ POOLSIZE*8-1 );
+ }
+
+ if( !pool_filled ) {
+ if( read_seed_file() )
+ pool_filled = 1;
+ }
+
+ /* For level 2 quality (key generation) we alwas make
+ * sure that the pool has been seeded enough initially */
+ if( level == 2 && !did_initial_extra_seeding ) {
+ size_t needed;
+
+ pool_balance = 0;
+ needed = length - pool_balance;
+ if( needed < POOLSIZE/2 )
+ needed = POOLSIZE/2;
+ else if( needed > POOLSIZE )
+ BUG();
+ read_random_source( 3, needed, 2 );
+ pool_balance += needed;
+ did_initial_extra_seeding=1;
+ }
/* for level 2 make sure that there is enough random in the pool */
if( level == 2 && pool_balance < length ) {
@@ -347,6 +513,12 @@ read_pool( byte *buffer, size_t length, int level )
/****************
* Add LENGTH bytes of randomness from buffer to the pool.
* source may be used to specify the randomness source.
+ * Source is:
+ * 0 - used ony for initialization
+ * 1 - fast random poll function
+ * 2 - normal poll function
+ * 3 - used when level 2 random quality has been requested
+ * to do an extra pool seed.
*/
static void
add_randomness( const void *buffer, size_t length, int source )
@@ -410,6 +582,13 @@ fast_random_poll()
add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
}
+ #elif HAVE_CLOCK_GETTIME
+ { struct timespec tv;
+ if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+ BUG();
+ add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+ add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
+ }
#else /* use times */
#ifndef HAVE_DOSISH_SYSTEM
{ struct tms buf;
@@ -419,13 +598,28 @@ fast_random_poll()
#endif
#endif
#ifdef HAVE_GETRUSAGE
+ #ifndef RUSAGE_SELF
+ #ifdef __GCC__
+ #warning There is no RUSAGE_SELF on this system
+ #endif
+ #else
{ struct rusage buf;
if( getrusage( RUSAGE_SELF, &buf ) )
BUG();
add_randomness( &buf, sizeof buf, 1 );
memset( &buf, 0, sizeof buf );
}
+ #endif
#endif
+ /* time and clock are availabe on all systems - so
+ * we better do it just in case one of the above functions
+ * didn't work */
+ { time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), 1 );
+ }
+ { clock_t x = clock();
+ add_randomness( &x, sizeof(x), 1 );
+ }
}
@@ -472,9 +666,9 @@ gather_faked( void (*add)(const void*, size_t, int), int requester,
#endif
initialized=1;
#ifdef HAVE_RAND
- srand( time(NULL) * getpid());
+ srand(make_timestamp()*getpid());
#else
- srandom( time(NULL) * getpid());
+ srandom(make_timestamp()*getpid());
#endif
}
diff --git a/cipher/rmd160.c b/cipher/rmd160.c
index 7b230087..fb9d6fa5 100644
--- a/cipher/rmd160.c
+++ b/cipher/rmd160.c
@@ -562,10 +562,10 @@ rmd160_get_info( int algo, size_t *contextsize,
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 20;
- *r_init = (void (*)(void *))rmd160_init;
- *r_write = (void (*)(void *, byte*, size_t))rmd160_write;
- *r_final = (void (*)(void *))rmd160_final;
- *r_read = (byte *(*)(void *))rmd160_read;
+ *(void (**)(RMD160_CONTEXT *))r_init = rmd160_init;
+ *(void (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
+ *(void (**)(RMD160_CONTEXT *))r_final = rmd160_final;
+ *(byte *(**)(RMD160_CONTEXT *))r_read = rmd160_read;
return "RIPEMD160";
}
diff --git a/cipher/rndegd.c b/cipher/rndegd.c
index 4d5f0ef3..f6870cdd 100644
--- a/cipher/rndegd.c
+++ b/cipher/rndegd.c
@@ -1,5 +1,5 @@
/* rndegd.c - interface to the EGD
- * Copyright (C) 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -117,9 +117,13 @@ do_read( int fd, void *buf, size_t nbytes )
-/* Note: we always use the highest level.
+/****************
+ * Note: we always use the highest level.
* TO boost the performance we may want to add some
* additional code for level 1
+ *
+ * Using a level of 0 should never block and better add nothing
+ * to the pool. So this is just a dummy for EGD.
*/
static int
gather_random( void (*add)(const void*, size_t, int), int requester,
@@ -133,7 +137,8 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
if( !length )
return 0;
-
+ if( !level )
+ return 0;
restart:
if( do_restart ) {
diff --git a/cipher/rndunix.c b/cipher/rndunix.c
index 4ab9f65f..99a416ea 100644
--- a/cipher/rndunix.c
+++ b/cipher/rndunix.c
@@ -77,7 +77,7 @@
#ifndef __QNX__
#include <sys/resource.h>
#endif /* __QNX__ */
-#ifdef _AIX
+#if defined( _AIX ) || defined( __QNX__ )
#include <sys/select.h>
#endif /* _AIX */
#ifndef __QNX__
@@ -91,6 +91,10 @@
#endif /* __hpux 9.x, after that it's in unistd.h */
#include <sys/wait.h>
/* #include <kitchensink.h> */
+#ifdef __QNX__
+#include <signal.h>
+#include <process.h>
+#endif /* __QNX__ */
#include <errno.h>
#include "types.h" /* for byte and u32 typedefs */
@@ -100,7 +104,13 @@
#include "g10lib.h"
#ifndef EAGAIN
- #define EAGAIN EWOULDBLOCK
+#define EAGAIN EWOULDBLOCK
+#endif
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
#endif
#define GATHER_BUFSIZE 49152 /* Usually about 25K are filled */
@@ -306,6 +316,32 @@ typedef struct {
char data[500]; /* gathered data */
} GATHER_MSG;
+#ifndef HAVE_WAITPID
+pid_t
+waitpid(pid_t pid, int *statptr, int options)
+{
+ #ifdef HAVE_WAIT4
+ return wait4(pid, statptr, options, NULL);
+ #else
+ /* If wait4 is also not available, try wait3 for SVR3 variants */
+ /* Less ideal because can't actually request a specific pid */
+ /* For that reason, first check to see if pid is for an */
+ /* existing process. */
+ int tmp_pid, dummystat;;
+ if (kill(pid, 0) == -1) {
+ errno = ECHILD;
+ return -1;
+ }
+ if (statptr == NULL)
+ statptr = &dummystat;
+ while (((tmp_pid = wait3(statptr, options, 0)) != pid) &&
+ (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
+ ;
+ return tmp_pid;
+ #endif
+}
+#endif
+
/* Under SunOS popen() doesn't record the pid of the child process. When
* pclose() is called, instead of calling waitpid() for the correct child, it
* calls wait() repeatedly until the right child is reaped. The problem is
@@ -376,7 +412,9 @@ my_popen(struct RI *entry)
* close on exec, so new children won't see it */
close(pipedes[STDOUT_FILENO]);
+#ifdef FD_CLOEXEC
fcntl(pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
+#endif
stream = fdopen(pipedes[STDIN_FILENO], "r");
@@ -616,6 +654,7 @@ start_gatherer( int pipefd )
}
/* close all files but the ones we need */
{ int nmax, n1, n2, i;
+ #ifdef _SC_OPEN_MAX
if( (nmax=sysconf( _SC_OPEN_MAX )) < 0 ) {
#ifdef _POSIX_OPEN_MAX
nmax = _POSIX_OPEN_MAX;
@@ -623,6 +662,9 @@ start_gatherer( int pipefd )
nmax = 20; /* assume a reasonable value */
#endif
}
+ #else
+ nmax = 20; /* assume a reasonable value */
+ #endif
n1 = fileno( stderr );
n2 = dbgfp? fileno( dbgfp ) : -1;
for(i=0; i < nmax; i++ ) {
@@ -718,6 +760,10 @@ read_a_msg( int fd, GATHER_MSG *msg )
}
+/****************
+ * Using a level of 0 should never block and better add nothing
+ * to the pool. So this is just a dummy for this gatherer.
+ */
static int
gather_random( void (*add)(const void*, size_t, int), int requester,
size_t length, int level )
@@ -727,6 +773,9 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
GATHER_MSG msg;
size_t n;
+ if( !level )
+ return 0;
+
if( !gatherer_pid ) {
/* make sure we are not setuid */
if( getuid() != geteuid() )
diff --git a/cipher/rndw32.c b/cipher/rndw32.c
index c1045851..25830693 100644
--- a/cipher/rndw32.c
+++ b/cipher/rndw32.c
@@ -1,5 +1,6 @@
-/* rndw32.c - interface to the Winseed DLL
- * Copyright (C) 1999 Free Software Foundation, Inc.
+/* rndw32.c - W32 entropy gatherer
+ * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ * Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
*
* This file is part of GnuPG.
*
@@ -16,6 +17,46 @@
* 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
+ *
+ *************************************************************************
+ * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann.
+ * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
+ * copyright notice:
+ *
+ * This module is part of the cryptlib continuously seeded pseudorandom
+ * number generator. For usage conditions, see lib_rand.c
+ *
+ * [Here is the notice from lib_rand.c, which is now called dev_sys.c]
+ *
+ * This module and the misc/rnd*.c modules represent the cryptlib
+ * continuously seeded pseudorandom number generator (CSPRNG) as described in
+ * my 1998 Usenix Security Symposium paper "The generation of random numbers
+ * for cryptographic purposes".
+ *
+ * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
+ * 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG
+ * modules and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice
+ * and this permission notice in its entirety.
+ *
+ * 2. Redistributions in binary form must reproduce the copyright notice in
+ * the documentation and/or other materials provided with the distribution.
+ *
+ * 3. A copy of any bugfixes or enhancements made must be provided to the
+ * author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
+ * baseline version of the code.
+ *
+ * ALTERNATIVELY, the code may be distributed under the terms of the GNU
+ * General Public License, version 2 or any later version published by the
+ * Free Software Foundation, in which case the provisions of the GNU GPL are
+ * required INSTEAD OF the above restrictions.
+ *
+ * Although not required under the terms of the GPL, it would still be nice if
+ * you could make any changes available to the author to allow a consistent
+ * code base to be maintained
+ *************************************************************************
*/
#include <config.h>
@@ -27,10 +68,16 @@
#include <windows.h>
+
#include "types.h"
#include "g10lib.h"
#include "dynload.h"
+/* We do not use the netropy DLL anymore because a standalone program is
+ * easier to maintain and */
+/*#define USE_ENTROPY_DLL*/
+
+
#ifdef IS_MODULE
#define _(a) (a)
@@ -39,6 +86,10 @@
#endif
+static int debug_me;
+
+#ifdef USE_ENTROPY_DLL
+
#define WIN32_SLOW_SEEDER 0
#define WIN32_FAST_SEEDER 1
@@ -53,6 +104,17 @@
#define PCP_DLL_FUNC 8
#define PCP_UNKNOWN_SEEDER_TYPE 9
+
+/****************
+ * We sometimes get a SEEDER_TOO_SMALL error, in which case we increment
+ * the internal buffer by SEEDER_INC_CHUNK until we reach MAX_SEEDER_SIZE
+ * MAX_SEEDER_SIZE is used as an arbitrary limit to protect against
+ * bugs in Winseed.
+ */
+#define MAX_SEEDER_SIZE 500000
+#define SEEDER_INC_CHUNK 50000
+
+
typedef void *WIN32_SEEDER;
static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason);
@@ -68,8 +130,6 @@ 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
@@ -80,11 +140,17 @@ static char *entropy_dll;
static void
load_and_init_winseed( void )
{
- int hInstance;
+ HANDLE hInstance;
void *addr;
unsigned int reason = 0;
unsigned int n1, n2;
- const char *dllname = entropy_dll? entropy_dll : "c:/gnupg/entropy.dll";
+ 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 )
@@ -119,15 +185,14 @@ load_and_init_winseed( void )
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);
+ /*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);
+ /*g10_log_info("fast buffer size=%u\n", n2);*/
entropy_buffer_size = n1 > n2? n1: n2;
- entropy_buffer = g10_xmalloc( entropy_buffer_size );
- g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );
+ entropy_buffer = m_alloc( entropy_buffer_size );
+ /*g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );*/
return;
@@ -150,13 +215,16 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
unsigned int result;
unsigned int nbytes;
+ if( !level )
+ return 0;
+
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
+ * level we adjust the requested length so that for higher 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.
@@ -169,17 +237,35 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
for(;;) {
nbytes = entropy_buffer_size;
result = get_seed( slow_seeder, entropy_buffer, &nbytes);
+ if( result == PCP_SEEDER_TOO_SMALL ) {
+ unsigned int n1 = get_internal_seed_size( slow_seeder );
+
+ if( n1 > MAX_SEEDER_SIZE ) {
+ g10_log_fatal("rndw32: internal seeder problem (size=%u)\n",
+ n1);
+ return -1; /* actually never reached */
+ }
+ n1 += SEEDER_INC_CHUNK;
+ set_internal_seed_size( slow_seeder, n1 );
+ if( n1 > entropy_buffer_size ) {
+ entropy_buffer_size = n1;
+ entropy_buffer = m_realloc( entropy_buffer,
+ entropy_buffer_size );
+ }
+ continue;
+ }
+
+
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 );
+ /*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");
}
}
@@ -206,6 +292,619 @@ gather_random_fast( void (*add)(const void*, size_t, int), int requester )
return 0;
}
+#else /* !USE_ENTROPY_DLL */
+/* This is the new code which does not require the entropy.dll */
+
+/*
+ * Definitions which are missing from the current GNU Windows32Api
+ */
+
+#define TH32CS_SNAPHEAPLIST 1
+#define TH32CS_SNAPPROCESS 2
+#define TH32CS_SNAPTHREAD 4
+#define TH32CS_SNAPMODULE 8
+#define TH32CS_SNAPALL (1|2|4|8)
+#define TH32CS_INHERIT 0x80000000
+
+#define IOCTL_DISK_PERFORMANCE 0x00070020
+#define VER_PLATFORM_WIN32_WINDOWS 1
+
+
+typedef struct {
+ DWORD dwSize;
+ DWORD th32ProcessID;
+ DWORD th32HeapID;
+ DWORD dwFlags;
+} HEAPLIST32;
+
+typedef struct {
+ DWORD dwSize;
+ HANDLE hHandle;
+ DWORD dwAddress;
+ DWORD dwBlockSize;
+ DWORD dwFlags;
+ DWORD dwLockCount;
+ DWORD dwResvd;
+ DWORD th32ProcessID;
+ DWORD th32HeapID;
+} HEAPENTRY32;
+
+typedef struct {
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ProcessID;
+ DWORD th32DefaultHeapID;
+ DWORD th32ModuleID;
+ DWORD cntThreads;
+ DWORD th32ParentProcessID;
+ LONG pcPriClassBase;
+ DWORD dwFlags;
+ char szExeFile[260];
+} PROCESSENTRY32;
+
+typedef struct {
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ThreadID;
+ DWORD th32OwnerProcessID;
+ LONG tpBasePri;
+ LONG tpDeltaPri;
+ DWORD dwFlags;
+} THREADENTRY32;
+
+typedef struct {
+ DWORD dwSize;
+ DWORD th32ModuleID;
+ DWORD th32ProcessID;
+ DWORD GlblcntUsage;
+ DWORD ProccntUsage;
+ BYTE *modBaseAddr;
+ DWORD modBaseSize;
+ HMODULE hModule;
+ char szModule[256];
+ char szExePath[260];
+} MODULEENTRY32;
+
+
+
+/* Type definitions for function pointers to call Toolhelp32 functions
+ * used with the windows95 gatherer */
+typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
+typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
+typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
+typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
+typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
+ DWORD th32HeapID);
+typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
+typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
+
+/* Type definitions for function pointers to call NetAPI32 functions */
+typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
+ DWORD dwLevel, DWORD dwOptions,
+ LPBYTE * lpBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
+
+
+/* When we query the performance counters, we allocate an initial buffer and
+ * then reallocate it as required until RegQueryValueEx() stops returning
+ * ERROR_MORE_DATA. The following values define the initial buffer size and
+ * step size by which the buffer is increased
+ */
+#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */
+#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */
+
+
+static void
+slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
+{
+ static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
+ static MODULEWALK pModule32First = NULL;
+ static MODULEWALK pModule32Next = NULL;
+ static PROCESSWALK pProcess32First = NULL;
+ static PROCESSWALK pProcess32Next = NULL;
+ static THREADWALK pThread32First = NULL;
+ static THREADWALK pThread32Next = NULL;
+ static HEAPLISTWALK pHeap32ListFirst = NULL;
+ static HEAPLISTWALK pHeap32ListNext = NULL;
+ static HEAPFIRST pHeap32First = NULL;
+ static HEAPNEXT pHeap32Next = NULL;
+ HANDLE hSnapshot;
+
+
+ /* initialize the Toolhelp32 function pointers */
+ if ( !pCreateToolhelp32Snapshot ) {
+ HANDLE hKernel;
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: init toolkit\n" );
+
+ /* Obtain the module handle of the kernel to retrieve the addresses
+ * of the Toolhelp32 functions */
+ if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
+ g10_log_fatal ( "rndw32: can't get module handle\n" );
+ }
+
+ /* Now get pointers to the functions */
+ pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
+ "CreateToolhelp32Snapshot");
+ pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
+ pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
+ pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
+ "Process32First");
+ pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
+ "Process32Next");
+ pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
+ pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
+ pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
+ "Heap32ListFirst");
+ pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
+ "Heap32ListNext");
+ pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
+ pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
+
+ if ( !pCreateToolhelp32Snapshot
+ || !pModule32First || !pModule32Next
+ || !pProcess32First || !pProcess32Next
+ || !pThread32First || !pThread32Next
+ || !pHeap32ListFirst || !pHeap32ListNext
+ || !pHeap32First || !pHeap32Next ) {
+ g10_log_fatal ( "rndw32: failed to get a toolhep function\n" );
+ }
+ }
+
+ /* Take a snapshot of everything we can get to which is currently
+ * in the system */
+ if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
+ g10_log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" );
+ }
+
+ /* Walk through the local heap */
+ { HEAPLIST32 hl32;
+ hl32.dwSize = sizeof (HEAPLIST32);
+ if (pHeap32ListFirst (hSnapshot, &hl32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk heap\n" );
+ do {
+ HEAPENTRY32 he32;
+
+ /* First add the information from the basic Heaplist32 struct */
+ (*add) ( &hl32, sizeof (hl32), requester );
+
+ /* Now walk through the heap blocks getting information
+ * on each of them */
+ he32.dwSize = sizeof (HEAPENTRY32);
+ if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
+ do {
+ (*add) ( &he32, sizeof (he32), requester );
+ } while (pHeap32Next (&he32));
+ }
+ } while (pHeap32ListNext (hSnapshot, &hl32));
+ }
+ }
+
+
+ /* Walk through all processes */
+ { PROCESSENTRY32 pe32;
+ pe32.dwSize = sizeof (PROCESSENTRY32);
+ if (pProcess32First (hSnapshot, &pe32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk processes\n" );
+ do {
+ (*add) ( &pe32, sizeof (pe32), requester );
+ } while (pProcess32Next (hSnapshot, &pe32));
+ }
+ }
+
+ /* Walk through all threads */
+ { THREADENTRY32 te32;
+ te32.dwSize = sizeof (THREADENTRY32);
+ if (pThread32First (hSnapshot, &te32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk threads\n" );
+ do {
+ (*add) ( &te32, sizeof (te32), requester );
+ } while (pThread32Next (hSnapshot, &te32));
+ }
+ }
+
+ /* Walk through all modules associated with the process */
+ { MODULEENTRY32 me32;
+ me32.dwSize = sizeof (MODULEENTRY32);
+ if (pModule32First (hSnapshot, &me32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk modules\n" );
+ do {
+ (*add) ( &me32, sizeof (me32), requester );
+ } while (pModule32Next (hSnapshot, &me32));
+ }
+ }
+
+ CloseHandle (hSnapshot);
+}
+
+
+
+static void
+slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
+{
+ static int is_initialized = 0;
+ static NETSTATISTICSGET pNetStatisticsGet = NULL;
+ static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
+ static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
+ static int is_workstation = 1;
+
+ static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
+ PERF_DATA_BLOCK *pPerfData;
+ HANDLE hDevice, hNetAPI32 = NULL;
+ DWORD dwSize, status;
+ int nDrive;
+
+ if ( !is_initialized ) {
+ HKEY hKey;
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
+ /* Find out whether this is an NT server or workstation if necessary */
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+ BYTE szValue[32];
+ dwSize = sizeof (szValue);
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
+ status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
+ szValue, &dwSize);
+ if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {
+ /* Note: There are (at least) three cases for ProductType:
+ * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
+ * NT Server acting as a Domain Controller */
+ is_workstation = 0;
+ if ( debug_me )
+ log_debug ("rndw32: this is a NT server\n");
+ }
+ RegCloseKey (hKey);
+ }
+
+ /* Initialize the NetAPI32 function pointers if necessary */
+ if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
+ pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
+ "NetStatisticsGet");
+ pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
+ "NetApiBufferSize");
+ pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
+ "NetApiBufferFree");
+
+ if ( !pNetStatisticsGet
+ || !pNetApiBufferSize || !pNetApiBufferFree ) {
+ FreeLibrary (hNetAPI32);
+ hNetAPI32 = NULL;
+ g10_log_debug ("rndw32: No NETAPI found\n" );
+ }
+ }
+
+ is_initialized = 1;
+ }
+
+ /* Get network statistics. Note: Both NT Workstation and NT Server by
+ * default will be running both the workstation and server services. The
+ * heuristic below is probably useful though on the assumption that the
+ * majority of the network traffic will be via the appropriate service.
+ * In any case the network statistics return almost no randomness */
+ { LPBYTE lpBuffer;
+ if (hNetAPI32 && !pNetStatisticsGet (NULL,
+ is_workstation ? L"LanmanWorkstation" :
+ L"LanmanServer", 0, 0, &lpBuffer) ) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
+ pNetApiBufferSize (lpBuffer, &dwSize);
+ (*add) ( lpBuffer, dwSize,requester );
+ pNetApiBufferFree (lpBuffer);
+ }
+ }
+
+ /* Get disk I/O statistics for all the hard drives */
+ for (nDrive = 0;; nDrive++) {
+ DISK_PERFORMANCE diskPerformance;
+ char szDevice[50];
+
+ /* Check whether we can access this device */
+ sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
+ hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (hDevice == INVALID_HANDLE_VALUE)
+ break;
+
+ /* Note: This only works if you have turned on the disk performance
+ * counters with 'diskperf -y'. These counters are off by default */
+ if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
+ &diskPerformance, sizeof (DISK_PERFORMANCE),
+ &dwSize, NULL))
+ {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
+ nDrive );
+ (*add) ( &diskPerformance, dwSize, requester );
+ }
+ else {
+ log_info ("NOTE: you should run 'diskperf -y' "
+ "to enable the disk statistics\n");
+ }
+ CloseHandle (hDevice);
+ }
+
+ #if 0 /* we don't need this in GnuPG */
+ /* Wait for any async keyset driver binding to complete. You may be
+ * wondering what this call is doing here... the reason it's necessary is
+ * because RegQueryValueEx() will hang indefinitely if the async driver
+ * bind is in progress. The problem occurs in the dynamic loading and
+ * linking of driver DLL's, which work as follows:
+ *
+ * hDriver = LoadLibrary( DRIVERNAME );
+ * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
+ * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
+ *
+ * If RegQueryValueEx() is called while the GetProcAddress()'s are in
+ * progress, it will hang indefinitely. This is probably due to some
+ * synchronisation problem in the NT kernel where the GetProcAddress()
+ * calls affect something like a module reference count or function
+ * reference count while RegQueryValueEx() is trying to take a snapshot
+ * of the statistics, which include the reference counts. Because of
+ * this, we have to wait until any async driver bind has completed
+ * before we can call RegQueryValueEx() */
+ waitSemaphore (SEMAPHORE_DRIVERBIND);
+ #endif
+
+ /* Get information from the system performance counters. This can take
+ * a few seconds to do. In some environments the call to
+ * RegQueryValueEx() can produce an access violation at some random time
+ * in the future, adding a short delay after the following code block
+ * makes the problem go away. This problem is extremely difficult to
+ * reproduce, I haven't been able to get it to occur despite running it
+ * on a number of machines. The best explanation for the problem is that
+ * on the machine where it did occur, it was caused by an external driver
+ * or other program which adds its own values under the
+ * HKEY_PERFORMANCE_DATA key. The NT kernel calls the required external
+ * modules to map in the data, if there's a synchronisation problem the
+ * external module would write its data at an inappropriate moment,
+ * causing the access violation. A low-level memory checker indicated
+ * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
+ * interminable number of calls down inside RegQueryValueEx(), was
+ * overwriting memory (it wrote twice the allocated size of a buffer to a
+ * buffer allocated by the NT kernel). This may be what's causing the
+ * problem, but since it's in the kernel there isn't much which can be
+ * done.
+ *
+ * In addition to these problems the code in RegQueryValueEx() which
+ * estimates the amount of memory required to return the performance
+ * counter information isn't very accurate, since it always returns a
+ * worst-case estimate which is usually nowhere near the actual amount
+ * required. For example it may report that 128K of memory is required,
+ * but only return 64K of data */
+ { pPerfData = m_alloc (cbPerfData);
+ for (;;) {
+ dwSize = cbPerfData;
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
+ status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
+ NULL, (LPBYTE) pPerfData, &dwSize);
+ if (status == ERROR_SUCCESS) {
+ if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
+ (*add) ( pPerfData, dwSize, requester );
+ }
+ else
+ g10_log_debug ( "rndw32: no PERF signature\n");
+ break;
+ }
+ else if (status == ERROR_MORE_DATA) {
+ cbPerfData += PERFORMANCE_BUFFER_STEP;
+ pPerfData = m_realloc (pPerfData, cbPerfData);
+ }
+ else {
+ g10_log_debug ( "rndw32: get performance data problem\n");
+ break;
+ }
+ }
+ m_free (pPerfData);
+ }
+ /* Although this isn't documented in the Win32 API docs, it's necessary
+ to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
+ implicitly opened on the first call to RegQueryValueEx()). If this
+ isn't done then any system components which provide performance data
+ can't be removed or changed while the handle remains active */
+ RegCloseKey (HKEY_PERFORMANCE_DATA);
+}
+
+
+static int
+gather_random( void (*add)(const void*, size_t, int), int requester,
+ size_t length, int level )
+{
+ static int is_initialized;
+ static int is_windows95;
+
+
+ if( !level )
+ return 0;
+ /* We don't differentiate between level 1 and 2 here because
+ * there is no nternal entropy pool as a scary resource. It may
+ * all work slower, but because our entropy source will never
+ * block but deliver some not easy to measure entropy, we assume level 2
+ */
+
+
+ if ( !is_initialized ) {
+ OSVERSIONINFO osvi = { sizeof( osvi ) };
+ DWORD platform;
+
+ GetVersionEx( &osvi );
+ platform = osvi.dwPlatformId;
+ is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS;
+
+ if ( platform == VER_PLATFORM_WIN32s ) {
+ g10_log_fatal("can't run on a W32s platform\n" );
+ }
+ is_initialized = 1;
+ if ( debug_me )
+ log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
+ }
+
+
+ if ( debug_me )
+ log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n",
+ requester, (unsigned int)length, level );
+
+ if (is_windows95 ) {
+ slow_gatherer_windows95( add, requester );
+ }
+ else {
+ slow_gatherer_windowsNT( add, requester );
+ }
+
+ return 0;
+}
+
+
+
+static int
+gather_random_fast( void (*add)(const void*, size_t, int), int requester )
+{
+ static int addedFixedItems = 0;
+
+ if ( debug_me )
+ log_debug ("rndw32#gather_random_fast: req=%d\n", requester );
+
+ /* Get various basic pieces of system information: Handle of active
+ * window, handle of window with mouse capture, handle of clipboard owner
+ * handle of start of clpboard viewer list, pseudohandle of current
+ * process, current process ID, pseudohandle of current thread, current
+ * thread ID, handle of desktop window, handle of window with keyboard
+ * focus, whether system queue has any events, cursor position for last
+ * message, 1 ms time for last message, handle of window with clipboard
+ * open, handle of process heap, handle of procs window station, types of
+ * events in input queue, and milliseconds since Windows was started */
+ { byte buffer[20*sizeof(ulong)], *bufptr;
+ bufptr = buffer;
+ #define ADD(f) do { ulong along = (ulong)(f); \
+ memcpy (bufptr, &along, sizeof (along) ); \
+ bufptr += sizeof (along); } while (0)
+ ADD ( GetActiveWindow ());
+ ADD ( GetCapture ());
+ ADD ( GetClipboardOwner ());
+ ADD ( GetClipboardViewer ());
+ ADD ( GetCurrentProcess ());
+ ADD ( GetCurrentProcessId ());
+ ADD ( GetCurrentThread ());
+ ADD ( GetCurrentThreadId ());
+ ADD ( GetDesktopWindow ());
+ ADD ( GetFocus ());
+ ADD ( GetInputState ());
+ ADD ( GetMessagePos ());
+ ADD ( GetMessageTime ());
+ ADD ( GetOpenClipboardWindow ());
+ ADD ( GetProcessHeap ());
+ ADD ( GetProcessWindowStation ());
+ ADD ( GetQueueStatus (QS_ALLEVENTS));
+ ADD ( GetTickCount ());
+
+ assert ( bufptr-buffer < sizeof (buffer) );
+ (*add) ( buffer, bufptr-buffer, requester );
+ #undef ADD
+ }
+
+ /* Get multiword system information: Current caret position, current
+ * mouse cursor position */
+ { POINT point;
+ GetCaretPos (&point);
+ (*add) ( &point, sizeof (point), requester );
+ GetCursorPos (&point);
+ (*add) ( &point, sizeof (point), requester );
+ }
+
+ /* Get percent of memory in use, bytes of physical memory, bytes of free
+ * physical memory, bytes in paging file, free bytes in paging file, user
+ * bytes of address space, and free user bytes */
+ { MEMORYSTATUS memoryStatus;
+ memoryStatus.dwLength = sizeof (MEMORYSTATUS);
+ GlobalMemoryStatus (&memoryStatus);
+ (*add) ( &memoryStatus, sizeof (memoryStatus), requester );
+ }
+
+ /* Get thread and process creation time, exit time, time in kernel mode,
+ and time in user mode in 100ns intervals */
+ { HANDLE handle;
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ DWORD minimumWorkingSetSize, maximumWorkingSetSize;
+
+ handle = GetCurrentThread ();
+ GetThreadTimes (handle, &creationTime, &exitTime,
+ &kernelTime, &userTime);
+ (*add) ( &creationTime, sizeof (creationTime), requester );
+ (*add) ( &exitTime, sizeof (exitTime), requester );
+ (*add) ( &kernelTime, sizeof (kernelTime), requester );
+ (*add) ( &userTime, sizeof (userTime), requester );
+
+ handle = GetCurrentProcess ();
+ GetProcessTimes (handle, &creationTime, &exitTime,
+ &kernelTime, &userTime);
+ (*add) ( &creationTime, sizeof (creationTime), requester );
+ (*add) ( &exitTime, sizeof (exitTime), requester );
+ (*add) ( &kernelTime, sizeof (kernelTime), requester );
+ (*add) ( &userTime, sizeof (userTime), requester );
+
+ /* Get the minimum and maximum working set size for the current process */
+ GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
+ &maximumWorkingSetSize);
+ (*add) ( &minimumWorkingSetSize,
+ sizeof (&minimumWorkingSetSize), requester );
+ (*add) ( &maximumWorkingSetSize,
+ sizeof (&maximumWorkingSetSize), requester );
+ }
+
+
+ /* The following are fixed for the lifetime of the process so we only
+ * add them once */
+ if (!addedFixedItems) {
+ STARTUPINFO startupInfo;
+
+ /* Get name of desktop, console window title, new window position and
+ * size, window flags, and handles for stdin, stdout, and stderr */
+ startupInfo.cb = sizeof (STARTUPINFO);
+ GetStartupInfo (&startupInfo);
+ (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
+ addedFixedItems = 1;
+ }
+
+ /* The performance of QPC varies depending on the architecture it's
+ * running on and on the OS. Under NT it reads the CPU's 64-bit timestamp
+ * counter (at least on a Pentium and newer '486's, it hasn't been tested
+ * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
+ * timer. There are vague mumblings in the docs that it may fail if the
+ * appropriate hardware isn't available (possibly '386's or MIPS machines
+ * running NT), but who's going to run NT on a '386? */
+ { LARGE_INTEGER performanceCount;
+ if (QueryPerformanceCounter (&performanceCount)) {
+ if ( debug_me )
+ log_debug ("rndw32#gather_random_fast: perf data\n");
+ (*add) (&performanceCount, sizeof (&performanceCount), requester);
+ }
+ else { /* Millisecond accuracy at best... */
+ DWORD aword = GetTickCount ();
+ (*add) (&aword, sizeof (aword), requester );
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+
+#endif /* !USE_ENTROPY_DLL */
#ifndef IS_MODULE
@@ -232,6 +931,8 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
void *ret;
int i = *sequence;
+ debug_me = !!getenv("DEBUG_RNDW32");
+
do {
if ( i >= DIM(func_table) || i < 0 ) {
return NULL;
@@ -246,14 +947,6 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
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)
diff --git a/cipher/rsa.c b/cipher/rsa.c
new file mode 100644
index 00000000..5d852cd8
--- /dev/null
+++ b/cipher/rsa.c
@@ -0,0 +1,375 @@
+/* rsa.c - RSA function
+ * Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
+ * Copyright (C) 2000 Free Software Foundation, Inc.
+ ***********************************************************************
+ * ATTENTION: This code should not be used in the United States
+ * before the U.S. Patent #4,405,829 expires on September 20, 2000!
+ ***********************************************************************
+ *
+ * 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 <string.h>
+#include "util.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "rsa.h"
+
+
+typedef struct {
+ MPI n; /* modulus */
+ MPI e; /* exponent */
+} RSA_public_key;
+
+
+typedef struct {
+ MPI n; /* public modulus */
+ MPI e; /* public exponent */
+ MPI d; /* exponent */
+ MPI p; /* prime p. */
+ MPI q; /* prime q. */
+ MPI u; /* inverse of p mod q. */
+} RSA_secret_key;
+
+
+static void test_keys( RSA_secret_key *sk, unsigned nbits );
+static void generate( RSA_secret_key *sk, unsigned nbits );
+static int check_secret_key( RSA_secret_key *sk );
+static void public(MPI output, MPI input, RSA_public_key *skey );
+static void secret(MPI output, MPI input, RSA_secret_key *skey );
+
+
+static void
+test_keys( RSA_secret_key *sk, unsigned nbits )
+{
+ RSA_public_key pk;
+ MPI test = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ MPI out1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ MPI out2 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+
+ pk.n = sk->n;
+ pk.e = sk->e;
+ { char *p = get_random_bits( nbits, 0, 0 );
+ mpi_set_buffer( test, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ public( out1, test, &pk );
+ secret( out2, out1, sk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("RSA operation: public, secret failed\n");
+ secret( out1, test, sk );
+ public( out2, out1, &pk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("RSA operation: secret, public failed\n");
+ mpi_free( test );
+ mpi_free( out1 );
+ mpi_free( out2 );
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS
+ * Returns: 2 structures filles with all needed values
+ */
+static void
+generate( RSA_secret_key *sk, unsigned nbits )
+{
+ MPI p, q; /* the two primes */
+ MPI d; /* the private key */
+ MPI u;
+ MPI t1, t2;
+ MPI n; /* the public key */
+ MPI e; /* the exponent */
+ MPI phi; /* helper: (p-a)(q-1) */
+ MPI g;
+ MPI f;
+
+ /* select two (very secret) primes */
+ p = generate_secret_prime( nbits / 2 );
+ q = generate_secret_prime( nbits / 2 );
+ if( mpi_cmp( p, q ) > 0 ) /* p shall be smaller than q (for calc of u)*/
+ mpi_swap(p,q);
+ /* calculate Euler totient: phi = (p-1)(q-1) */
+ t1 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ t2 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ phi = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ g = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ f = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_sub_ui( t1, p, 1 );
+ mpi_sub_ui( t2, q, 1 );
+ mpi_mul( phi, t1, t2 );
+ mpi_gcd(g, t1, t2);
+ mpi_fdiv_q(f, phi, g);
+ /* multiply them to make the private key */
+ n = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_mul( n, p, q );
+ /* find a public exponent */
+ e = mpi_alloc( (6+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_set_ui( e, 17); /* start with 17 */
+ while( !mpi_gcd(t1, e, phi) ) /* (while gcd is not 1) */
+ mpi_add_ui( e, e, 2);
+ /* calculate the secret key d = e^1 mod phi */
+ d = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_invm(d, e, f );
+ /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+ u = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_invm(u, p, q );
+
+ if( DBG_CIPHER ) {
+ log_mpidump(" p= ", p );
+ log_mpidump(" q= ", q );
+ log_mpidump("phi= ", phi );
+ log_mpidump(" g= ", g );
+ log_mpidump(" f= ", f );
+ log_mpidump(" n= ", n );
+ log_mpidump(" e= ", e );
+ log_mpidump(" d= ", d );
+ log_mpidump(" u= ", u );
+ }
+
+ mpi_free(t1);
+ mpi_free(t2);
+ mpi_free(phi);
+ mpi_free(f);
+ mpi_free(g);
+
+ sk->n = n;
+ sk->e = e;
+ sk->p = p;
+ sk->q = q;
+ sk->d = d;
+ sk->u = u;
+
+ /* now we can test our keys (this should never fail!) */
+ test_keys( sk, nbits - 64 );
+}
+
+
+/****************
+ * Test wether the secret key is valid.
+ * Returns: true if this is a valid key.
+ */
+static int
+check_secret_key( RSA_secret_key *sk )
+{
+ int rc;
+ MPI temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 );
+
+ mpi_mul(temp, sk->p, sk->q );
+ rc = mpi_cmp( temp, sk->n );
+ mpi_free(temp);
+ return !rc;
+}
+
+
+
+/****************
+ * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
+ *
+ * c = m^e mod n
+ *
+ * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
+ */
+static void
+public(MPI output, MPI input, RSA_public_key *pkey )
+{
+ if( output == input ) { /* powm doesn't like output and input the same */
+ MPI x = mpi_alloc( mpi_get_nlimbs(input)*2 );
+ mpi_powm( x, input, pkey->e, pkey->n );
+ mpi_set(output, x);
+ mpi_free(x);
+ }
+ else
+ mpi_powm( output, input, pkey->e, pkey->n );
+}
+
+/****************
+ * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
+ *
+ * m = c^d mod n
+ *
+ * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY.
+ *
+ * FIXME: We should better use the Chinese Remainder Theorem
+ */
+static void
+secret(MPI output, MPI input, RSA_secret_key *skey )
+{
+ mpi_powm( output, input, skey->d, skey->n );
+}
+
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+
+int
+rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+ RSA_secret_key sk;
+
+ if( !is_RSA(algo) )
+ return G10ERR_PUBKEY_ALGO;
+
+ generate( &sk, nbits );
+ skey[0] = sk.n;
+ skey[1] = sk.e;
+ skey[2] = sk.d;
+ skey[3] = sk.p;
+ skey[4] = sk.q;
+ skey[5] = sk.u;
+ /* make an empty list of factors */
+ *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
+ return 0;
+}
+
+
+int
+rsa_check_secret_key( int algo, MPI *skey )
+{
+ RSA_secret_key sk;
+
+ if( !is_RSA(algo) )
+ return G10ERR_PUBKEY_ALGO;
+
+ sk.n = skey[0];
+ sk.e = skey[1];
+ sk.d = skey[2];
+ sk.p = skey[3];
+ sk.q = skey[4];
+ sk.u = skey[5];
+ if( !check_secret_key( &sk ) )
+ return G10ERR_BAD_SECKEY;
+
+ return 0;
+}
+
+
+
+int
+rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
+{
+ RSA_public_key pk;
+
+ if( algo != 1 && algo != 2 )
+ return G10ERR_PUBKEY_ALGO;
+
+ pk.n = pkey[0];
+ pk.e = pkey[1];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.n ) );
+ public( resarr[0], data, &pk );
+ return 0;
+}
+
+int
+rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{
+ RSA_secret_key sk;
+
+ if( algo != 1 && algo != 2 )
+ return G10ERR_PUBKEY_ALGO;
+
+ sk.n = skey[0];
+ sk.e = skey[1];
+ sk.d = skey[2];
+ sk.p = skey[3];
+ sk.q = skey[4];
+ sk.u = skey[5];
+ *result = mpi_alloc_secure( mpi_get_nlimbs( sk.n ) );
+ secret( *result, data[0], &sk );
+ return 0;
+}
+
+int
+rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+ RSA_secret_key sk;
+
+ if( algo != 1 && algo != 3 )
+ return G10ERR_PUBKEY_ALGO;
+
+ sk.n = skey[0];
+ sk.e = skey[1];
+ sk.d = skey[2];
+ sk.p = skey[3];
+ sk.q = skey[4];
+ sk.u = skey[5];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.n ) );
+ secret( resarr[0], data, &sk );
+
+ return 0;
+}
+
+int
+rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *opaque, MPI tmp), void *opaquev )
+{
+ RSA_public_key pk;
+ MPI result;
+ int rc;
+
+ if( algo != 1 && algo != 3 )
+ return G10ERR_PUBKEY_ALGO;
+ pk.n = pkey[0];
+ pk.e = pkey[1];
+ result = mpi_alloc( (160+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB);
+ public( result, data[0], &pk );
+ /*rc = (*cmp)( opaquev, result );*/
+ rc = mpi_cmp( result, hash )? G10ERR_BAD_SIGN:0;
+ mpi_free(result);
+
+ return rc;
+}
+
+
+unsigned int
+rsa_get_nbits( int algo, MPI *pkey )
+{
+ if( !is_RSA(algo) )
+ return 0;
+ return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm. We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ * the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ * 1 set : allows encryption
+ */
+const char *
+rsa_get_info( int algo,
+ int *npkey, int *nskey, int *nenc, int *nsig, int *usage )
+{
+ *npkey = 2;
+ *nskey = 6;
+ *nenc = 1;
+ *nsig = 1;
+
+ switch( algo ) {
+ case 1: *usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; return "RSA";
+ case 2: *usage = PUBKEY_USAGE_ENC; return "RSA-E";
+ case 3: *usage = PUBKEY_USAGE_SIG; return "RSA-S";
+ default:*usage = 0; return NULL;
+ }
+}
+
diff --git a/cipher/rsa.h b/cipher/rsa.h
new file mode 100644
index 00000000..8b60ecbb
--- /dev/null
+++ b/cipher/rsa.h
@@ -0,0 +1,36 @@
+/* rsa.h
+ * Copyright (C) 1997,1998 by Werner Koch (dd9jn)
+ * Copyright (C) 2000 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
+ */
+#ifndef G10_RSA_H
+#define G10_RSA_H
+
+int rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int rsa_check_secret_key( int algo, MPI *skey );
+int rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
+int rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
+int rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI), void *opaquev );
+unsigned rsa_get_nbits( int algo, MPI *pkey );
+const char *rsa_get_info( int algo, int *npkey, int *nskey,
+ int *nenc, int *nsig, int *use );
+
+
+#endif /*G10_RSA_H*/
diff --git a/cipher/sha1.c b/cipher/sha1.c
index f231e37b..aa3ac092 100644
--- a/cipher/sha1.c
+++ b/cipher/sha1.c
@@ -337,10 +337,10 @@ sha1_get_info( int algo, size_t *contextsize,
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 20;
- *r_init = (void (*)(void *))sha1_init;
- *r_write = (void (*)(void *, byte*, size_t))sha1_write;
- *r_final = (void (*)(void *))sha1_final;
- *r_read = (byte *(*)(void *))sha1_read;
+ *(void (**)(SHA1_CONTEXT *))r_init = sha1_init;
+ *(void (**)(SHA1_CONTEXT *, byte*, size_t))r_write = sha1_write;
+ *(void (**)(SHA1_CONTEXT *))r_final = sha1_final;
+ *(byte *(**)(SHA1_CONTEXT *))r_read = sha1_read;
return "SHA1";
}
diff --git a/cipher/tiger.c b/cipher/tiger.c
index 0e42160a..abe449ab 100644
--- a/cipher/tiger.c
+++ b/cipher/tiger.c
@@ -899,10 +899,10 @@ tiger_get_info( int algo, size_t *contextsize,
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 24;
- *r_init = (void (*)(void *))tiger_init;
- *r_write = (void (*)(void *, byte*, size_t))tiger_write;
- *r_final = (void (*)(void *))tiger_final;
- *r_read = (byte *(*)(void *))tiger_read;
+ *(void (**)(TIGER_CONTEXT *))r_init = tiger_init;
+ *(void (**)(TIGER_CONTEXT *, byte*, size_t))r_write = tiger_write;
+ *(void (**)(TIGER_CONTEXT *))r_final = tiger_final;
+ *(byte *(**)(TIGER_CONTEXT *))r_read = tiger_read;
return "TIGER";
}
diff --git a/cipher/twofish.c b/cipher/twofish.c
index 1eea4b8e..5766021c 100644
--- a/cipher/twofish.c
+++ b/cipher/twofish.c
@@ -34,10 +34,6 @@
/* Prototype for the self-test function. */
static const char *selftest(void);
-/* Macros used by the info function. */
-#define FNCCAST_SETKEY(f) ((int(*)(void*, byte*, unsigned))(f))
-#define FNCCAST_CRYPT(f) ((void(*)(void*, byte*, byte*))(f))
-
/* Structure for an expanded Twofish key. s contains the key-dependent
* S-boxes composed with the MDS matrix; w contains the eight "whitening"
* subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. Note
@@ -990,16 +986,20 @@ twofish_get_info (int algo, size_t *keylen,
*keylen = algo==10? 256 : 128;
*blocksize = 16;
*contextsize = sizeof (TWOFISH_context);
- *r_setkey = FNCCAST_SETKEY (twofish_setkey);
- *r_encrypt= FNCCAST_CRYPT (twofish_encrypt);
- *r_decrypt= FNCCAST_CRYPT (twofish_decrypt);
-
- if( algo == 10 )
- return "TWOFISH";
- if (algo == 102) /* This algorithm number is assigned for
- * experiments, so we can use it */
- return "TWOFISH128";
- return NULL;
+
+ *(int (**)(TWOFISH_context*, const byte*, const unsigned))r_setkey
+ = twofish_setkey;
+ *(void (**)(const TWOFISH_context*, byte*, const byte*))r_encrypt
+ = twofish_encrypt;
+ *(void (**)(const TWOFISH_context*, byte*, const byte*))r_decrypt
+ = twofish_decrypt;
+
+ if( algo == 10 )
+ return "TWOFISH";
+ if (algo == 102) /* This algorithm number is assigned for
+ * experiments, so we can use it */
+ return "TWOFISH128";
+ return NULL;
}