1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

See ChangeLog: Fri Jul 14 19:38:23 CEST 2000 Werner Koch

This commit is contained in:
Werner Koch 2000-07-14 17:34:53 +00:00
parent d1648b4d7a
commit 92cd255508
104 changed files with 5871 additions and 1540 deletions

View file

@ -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.

View file

@ -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

View file

@ -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";

View file

@ -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";

View file

@ -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;

View file

@ -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
*/

View file

@ -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;

View file

@ -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 ) {

View file

@ -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";
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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
}

View file

@ -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";
}

View file

@ -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 ) {

View file

@ -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() )

View file

@ -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)

375
cipher/rsa.c Normal file
View file

@ -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;
}
}

36
cipher/rsa.h Normal file
View file

@ -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*/

View file

@ -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";
}

View file

@ -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";
}

View file

@ -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;
}