diff options
author | Werner Koch <wk@gnupg.org> | 1998-06-13 17:00:01 +0000 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 1998-06-13 17:00:01 +0000 |
commit | 9af004db0eb1d5585d8267fb45e08ba81738093c (patch) | |
tree | 92aea93b090dadad6ee24a21553c4ed29141a3e4 /cipher | |
parent | 418691fdbb60ac3f008c56e44faa83c803be01b3 (diff) | |
download | libgcrypt-9af004db0eb1d5585d8267fb45e08ba81738093c.tar.gz |
gnupg extension are now working
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/ChangeLog | 12 | ||||
-rw-r--r-- | cipher/Makefile.am | 2 | ||||
-rw-r--r-- | cipher/blowfish.c | 36 | ||||
-rw-r--r-- | cipher/cipher.c | 3 | ||||
-rw-r--r-- | cipher/dsa.c | 192 | ||||
-rw-r--r-- | cipher/dsa.h | 33 | ||||
-rw-r--r-- | cipher/dynload.c | 120 | ||||
-rw-r--r-- | cipher/dynload.h | 11 | ||||
-rw-r--r-- | cipher/elgamal.c | 229 | ||||
-rw-r--r-- | cipher/elgamal.h | 34 | ||||
-rw-r--r-- | cipher/g10c.c | 43 | ||||
-rw-r--r-- | cipher/md.c | 70 | ||||
-rw-r--r-- | cipher/md.h | 3 | ||||
-rw-r--r-- | cipher/misc.c | 175 | ||||
-rw-r--r-- | cipher/primegen.c | 2 | ||||
-rw-r--r-- | cipher/pubkey.c | 649 |
16 files changed, 1001 insertions, 613 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 6e59455a..760f52d4 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,7 +1,15 @@ +Sat Jun 13 14:16:57 1998 Werner Koch (wk@isil.d.shuttle.de) + + * pubkey.c: Major changes to allow extensions. Changed the inteface + of all public key ciphers and added the ability to load extensions + on demand. + + * misc.c: Removed. + Wed Jun 10 07:52:08 1998 Werner Koch,mobil,,, (wk@tobold) - * dynload.c: New - * cipher.c: Major changes to allow extensions. + * dynload.c: New. + * cipher.c: Major changes to allow extensions. Mon Jun 8 22:43:00 1998 Werner Koch (wk@isil.d.shuttle.de) diff --git a/cipher/Makefile.am b/cipher/Makefile.am index 53ba749a..04d1ef8e 100644 --- a/cipher/Makefile.am +++ b/cipher/Makefile.am @@ -35,7 +35,7 @@ libcipher_a_SOURCES = cipher.c \ sha1.c \ dsa.h \ dsa.c \ - misc.c \ + g10c.c \ smallprime.c diff --git a/cipher/blowfish.c b/cipher/blowfish.c index ec686e1e..65a408ef 100644 --- a/cipher/blowfish.c +++ b/cipher/blowfish.c @@ -55,9 +55,9 @@ typedef struct { u32 p[BLOWFISH_ROUNDS+2]; } BLOWFISH_context; -static void blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen ); -static void blowfish_encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ); -static void blowfish_decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ); +static void setkey( BLOWFISH_context *c, byte *key, unsigned keylen ); +static void encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ); +static void decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ); /* precomputed S boxes */ @@ -414,7 +414,7 @@ decrypt( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr ) #undef R static void -blowfish_encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) +encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) { u32 d1, d2; @@ -433,7 +433,7 @@ blowfish_encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) static void -blowfish_decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) +decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) { u32 d1, d2; @@ -461,19 +461,19 @@ selftest() byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 }; byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 }; - blowfish_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 ); - blowfish_encrypt_block( &c, buffer, plain ); + setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 ); + encrypt_block( &c, buffer, plain ); if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) ) log_error("wrong blowfish encryption\n"); - blowfish_decrypt_block( &c, buffer, buffer ); + decrypt_block( &c, buffer, buffer ); if( memcmp( buffer, plain, 8 ) ) log_bug("blowfish failed\n"); - blowfish_setkey( &c, key3, 8 ); - blowfish_encrypt_block( &c, buffer, plain3 ); + setkey( &c, key3, 8 ); + encrypt_block( &c, buffer, plain3 ); if( memcmp( buffer, cipher3, 8 ) ) log_error("wrong blowfish encryption (3)\n"); - blowfish_decrypt_block( &c, buffer, buffer ); + decrypt_block( &c, buffer, buffer ); if( memcmp( buffer, plain3, 8 ) ) log_bug("blowfish failed (3)\n"); } @@ -481,7 +481,7 @@ selftest() static void -blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen ) +setkey( BLOWFISH_context *c, byte *key, unsigned keylen ) { int i, j; u32 data, datal, datar; @@ -555,17 +555,17 @@ blowfish_setkey( BLOWFISH_context *c, byte *key, unsigned keylen ) const char * blowfish_get_info( int algo, size_t *keylen, size_t *blocksize, size_t *contextsize, - void (**setkey)( void *c, byte *key, unsigned keylen ), - void (**encrypt)( void *c, byte *outbuf, byte *inbuf ), - void (**decrypt)( void *c, byte *outbuf, byte *inbuf ) + void (**r_setkey)( void *c, byte *key, unsigned keylen ), + void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ), + void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf ) ) { *keylen = algo == CIPHER_ALGO_BLOWFISH ? 128 : 160; *blocksize = BLOWFISH_BLOCKSIZE; *contextsize = sizeof(BLOWFISH_context); - *setkey = FNCCAST_SETKEY(blowfish_setkey); - *encrypt= FNCCAST_CRYPT(blowfish_encrypt_block); - *decrypt= FNCCAST_CRYPT(blowfish_decrypt_block); + *r_setkey = FNCCAST_SETKEY(setkey); + *r_encrypt= FNCCAST_CRYPT(encrypt_block); + *r_decrypt= FNCCAST_CRYPT(decrypt_block); if( algo == CIPHER_ALGO_BLOWFISH ) return "BLOWFISH"; diff --git a/cipher/cipher.c b/cipher/cipher.c index 6ac46827..06494786 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -178,7 +178,8 @@ load_cipher_modules() continue; } /* put it into the table */ - log_info("loaded cipher %d (%s)\n", ct->algo, name); + if( g10_opt_verbose > 1 ) + log_info("loaded cipher %d (%s)\n", ct->algo, name); ct->name = name; ct_idx++; ct++; diff --git a/cipher/dsa.c b/cipher/dsa.c index d1c15c41..20011da3 100644 --- a/cipher/dsa.c +++ b/cipher/dsa.c @@ -28,6 +28,30 @@ #include "cipher.h" #include "dsa.h" +typedef struct { + MPI p; /* prime */ + MPI q; /* group order */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ +} DSA_public_key; + + +typedef struct { + MPI p; /* prime */ + MPI q; /* group order */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ + MPI x; /* secret exponent */ +} DSA_secret_key; + + +static MPI gen_k( MPI q ); +static void test_keys( DSA_secret_key *sk, unsigned qbits ); +static int check_secret_key( DSA_secret_key *sk ); +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); + /**************** * Generate a random secret exponent k less than q */ @@ -55,37 +79,23 @@ gen_k( MPI q ) return k; } -void -dsa_free_public_key( DSA_public_key *pk ) -{ - mpi_free( pk->p ); pk->p = NULL; - mpi_free( pk->q ); pk->q = NULL; - mpi_free( pk->g ); pk->g = NULL; - mpi_free( pk->y ); pk->y = NULL; -} - -void -dsa_free_secret_key( DSA_secret_key *sk ) -{ - mpi_free( sk->p ); sk->p = NULL; - mpi_free( sk->q ); sk->q = NULL; - mpi_free( sk->g ); sk->g = NULL; - mpi_free( sk->y ); sk->y = NULL; - mpi_free( sk->x ); sk->x = NULL; -} - static void -test_keys( DSA_public_key *pk, DSA_secret_key *sk, unsigned qbits ) +test_keys( DSA_secret_key *sk, unsigned qbits ) { + DSA_public_key pk; MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB ); MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB ); MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB ); + pk.p = sk->p; + pk.q = sk->q; + pk.g = sk->g; + pk.y = sk->y; mpi_set_bytes( test, qbits, get_random_byte, 0 ); - dsa_sign( out1_a, out1_b, test, sk ); - if( !dsa_verify( out1_a, out1_b, test, pk ) ) + sign( out1_a, out1_b, test, sk ); + if( !verify( out1_a, out1_b, test, &pk ) ) log_fatal("DSA:: sign, verify failed\n"); mpi_free( test ); @@ -100,9 +110,8 @@ test_keys( DSA_public_key *pk, DSA_secret_key *sk, unsigned qbits ) * Returns: 2 structures filled with all needed values * and an array with the n-1 factors of (p-1) */ -void -dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, - unsigned nbits, MPI **ret_factors ) +static void +generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors ) { MPI p; /* the prime */ MPI q; /* the 160 bit prime factor */ @@ -176,10 +185,6 @@ dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, } /* copy the stuff to the key structures */ - pk->p = mpi_copy(p); - pk->q = mpi_copy(q); - pk->g = mpi_copy(g); - pk->y = mpi_copy(y); sk->p = p; sk->q = q; sk->g = g; @@ -187,7 +192,7 @@ dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, sk->x = x; /* now we can test our keys (this should never fail!) */ - test_keys( pk, sk, qbits ); + test_keys( sk, qbits ); } @@ -196,8 +201,8 @@ dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, * Test whether the secret key is valid. * Returns: if this is a valid key. */ -int -dsa_check_secret_key( DSA_secret_key *sk ) +static int +check_secret_key( DSA_secret_key *sk ) { int rc; MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) ); @@ -214,8 +219,8 @@ dsa_check_secret_key( DSA_secret_key *sk ) * Make a DSA signature from HASH and put it into r and s. */ -void -dsa_sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey ) +static void +sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey ) { MPI k; MPI kinv; @@ -247,8 +252,8 @@ dsa_sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey ) /**************** * Returns true if the signature composed from R and S is valid. */ -int -dsa_verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey ) +static int +verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey ) { int rc; MPI w, u1, u2, v; @@ -290,3 +295,118 @@ dsa_verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey ) return rc; } + +/********************************************* + ************** interface ****************** + *********************************************/ + +int +dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ) +{ + DSA_secret_key sk; + + if( algo != PUBKEY_ALGO_DSA ) + return G10ERR_PUBKEY_ALGO; + + generate( &sk, nbits, retfactors ); + skey[0] = sk.p; + skey[1] = sk.q; + skey[2] = sk.g; + skey[3] = sk.y; + skey[4] = sk.x; + return 0; +} + + +int +dsa_check_secret_key( int algo, MPI *skey ) +{ + DSA_secret_key sk; + + if( algo != PUBKEY_ALGO_DSA ) + return G10ERR_PUBKEY_ALGO; + + sk.p = skey[0]; + sk.q = skey[1]; + sk.g = skey[2]; + sk.y = skey[3]; + sk.x = skey[4]; + if( !check_secret_key( &sk ) ) + return G10ERR_BAD_SECKEY; + + return 0; +} + + + +int +dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey ) +{ + DSA_secret_key sk; + + if( algo != PUBKEY_ALGO_DSA ) + return G10ERR_PUBKEY_ALGO; + + sk.p = skey[0]; + sk.q = skey[1]; + sk.g = skey[2]; + sk.y = skey[3]; + sk.x = skey[4]; + resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + sign( resarr[0], resarr[1], data, &sk ); + return 0; +} + +int +dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey ) +{ + DSA_public_key pk; + + if( algo != PUBKEY_ALGO_DSA ) + return G10ERR_PUBKEY_ALGO; + + pk.p = pkey[0]; + pk.q = pkey[1]; + pk.g = pkey[2]; + pk.y = pkey[3]; + if( !verify( data[0], data[1], hash, &pk ) ) + return G10ERR_BAD_SIGN; + return 0; +} + + + +unsigned +dsa_get_nbits( int algo, MPI *pkey ) +{ + if( algo != PUBKEY_ALGO_DSA ) + 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 * +dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig, + int *usage ) +{ + *npkey = 4; + *nskey = 5; + *nenc = 0; + *nsig = 2; + + switch( algo ) { + case PUBKEY_ALGO_DSA: *usage = 1; return "DSA"; + default: *usage = 0; return NULL; + } +} + + diff --git a/cipher/dsa.h b/cipher/dsa.h index 2d38a738..fe977a64 100644 --- a/cipher/dsa.h +++ b/cipher/dsa.h @@ -20,31 +20,12 @@ #ifndef G10_DSA_H #define G10_DSA_H -#include "mpi.h" - -typedef struct { - MPI p; /* prime */ - MPI q; /* group order */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ -} DSA_public_key; - - -typedef struct { - MPI p; /* prime */ - MPI q; /* group order */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ - MPI x; /* secret exponent */ -} DSA_secret_key; - - -void dsa_free_public_key( DSA_public_key *pk ); -void dsa_free_secret_key( DSA_secret_key *sk ); -int dsa_check_secret_key( DSA_secret_key *sk ); -void dsa_generate( DSA_public_key *pk, DSA_secret_key *sk, - unsigned nbits, MPI **ret_factors ); -void dsa_sign(MPI r, MPI s, MPI input, DSA_secret_key *skey); -int dsa_verify(MPI r, MPI s, MPI input, DSA_public_key *pkey); +int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); +int dsa_check_secret_key( int algo, MPI *skey ); +int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey ); +int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey ); +unsigned dsa_get_nbits( int algo, MPI *pkey ); +const char *dsa_get_info( int algo, int *npkey, int *nskey, + int *nenc, int *nsig, int *usage ); #endif /*G10_DSA_H*/ diff --git a/cipher/dynload.c b/cipher/dynload.c index b40eb405..e0b2e77e 100644 --- a/cipher/dynload.c +++ b/cipher/dynload.c @@ -71,11 +71,12 @@ register_cipher_extension( const char *fname ) /* check that it is not already registered */ for(r = extensions; r; r = r->next ) if( !compare_filenames(r->name, el->name) ) { - log_debug("extension '%s' already registered\n", el->name ); + log_info("extension '%s' already registered\n", el->name ); m_free(el); return; } - log_debug("extension '%s' registered\n", el->name ); + if( DBG_CIPHER ) + log_debug("extension '%s' registered\n", el->name ); /* and register */ el->next = extensions; extensions = el; @@ -91,7 +92,7 @@ load_extension( EXTLIST el ) int seq = 0; int class, vers; - el->handle = dlopen(el->name, RTLD_LAZY); + el->handle = dlopen(el->name, RTLD_NOW); if( !el->handle ) { log_error("%s: error loading extension: %s\n", el->name, dlerror() ); goto failure; @@ -102,7 +103,8 @@ load_extension( EXTLIST el ) goto failure; } - log_info("%s: version '%s'\n", el->name, *name ); + if( g10_opt_verbose ) + log_info("%s: version '%s'\n", el->name, *name ); sym = dlsym(el->handle, "gnupgext_enum_func"); if( (err=dlerror()) ) { @@ -111,23 +113,26 @@ load_extension( EXTLIST el ) } el->enumfunc = (void *(*)(int,int*,int*,int*))sym; - /* list the contents of the module */ - while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) { - if( vers != 1 ) { - log_error("%s: ignoring func with version %d\n", el->name, vers); - continue; - } - switch( class ) { - case 11: - case 21: - case 31: - log_info("%s: provides %s algorithm %d\n", el->name, - class == 11? "md" : - class == 21? "cipher" : "pubkey", - *(int*)sym); - break; - default: - log_debug("%s: skipping class %d\n", el->name, class); + if( g10_opt_verbose > 1 ) { + /* list the contents of the module */ + while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) { + if( vers != 1 ) { + log_info("%s: ignoring func with version %d\n",el->name,vers); + continue; + } + switch( class ) { + case 11: + case 21: + case 31: + log_info("%s: provides %s algorithm %d\n", el->name, + class == 11? "md" : + class == 21? "cipher" : "pubkey", + *(int*)sym); + break; + default: + /*log_debug("%s: skipping class %d\n", el->name, class);*/ + break; + } } } return 0; @@ -195,7 +200,78 @@ enum_gnupgext_ciphers( void **enum_context, int *algo, *algo = *(int*)sym; algname = (*finfo)( *algo, keylen, blocksize, contextsize, setkey, encrypt, decrypt ); - log_debug("found algo %d (%s)\n", *algo, algname ); + if( algname ) { + ctx->r = r; + return algname; + } + } + ctx->seq2 = 0; + } + ctx->seq1 = 0; + } + ctx->r = r; + return NULL; +} + +const char * +enum_gnupgext_pubkeys( void **enum_context, int *algo, + int *npkey, int *nskey, int *nenc, int *nsig, int *usage, + int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ), + int (**check_secret_key)( int algo, MPI *skey ), + int (**encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey ), + int (**decrypt)( int algo, MPI *result, MPI *data, MPI *skey ), + int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ), + int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey ), + unsigned (**get_nbits)( int algo, MPI *pkey ) ) +{ + EXTLIST r; + ENUMCONTEXT *ctx; + const char * (*finfo)( int, int *, int *, int *, int *, int *, + int (**)( int, unsigned, MPI *, MPI **), + int (**)( int, MPI * ), + int (**)( int, MPI *, MPI , MPI * ), + int (**)( int, MPI *, MPI *, MPI * ), + int (**)( int, MPI *, MPI , MPI * ), + int (**)( int, MPI , MPI *, MPI * ), + unsigned (**)( int , MPI * ) ); + + if( !*enum_context ) { /* init context */ + ctx = m_alloc_clear( sizeof( *ctx ) ); + ctx->r = extensions; + *enum_context = ctx; + } + else if( !algo ) { /* release the context */ + m_free(*enum_context); + *enum_context = NULL; + return NULL; + } + else + ctx = *enum_context; + + for( r = ctx->r; r; r = r->next ) { + int class, vers; + + if( r->failed ) + continue; + if( !r->handle && load_extension(r) ) + continue; + /* get a pubkey info function */ + if( ctx->sym ) + goto inner_loop; + while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) { + void *sym; + if( vers != 1 || class != 30 ) + continue; + inner_loop: + finfo = ctx->sym; + while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) { + const char *algname; + if( vers != 1 || class != 31 ) + continue; + *algo = *(int*)sym; + algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, usage, + generate, check_secret_key, encrypt, + decrypt, sign, verify, get_nbits ); if( algname ) { ctx->r = r; return algname; diff --git a/cipher/dynload.h b/cipher/dynload.h index 78f41c64..69b5d8fa 100644 --- a/cipher/dynload.h +++ b/cipher/dynload.h @@ -28,4 +28,15 @@ enum_gnupgext_ciphers( void **enum_context, int *algo, void (**decrypt)( void *c, byte *outbuf, byte *inbuf ) ); +const char * +enum_gnupgext_pubkeys( void **enum_context, int *algo, + int *npkey, int *nskey, int *nenc, int *nsig, int *usage, + int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ), + int (**check_secret_key)( int algo, MPI *skey ), + int (**encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey ), + int (**decrypt)( int algo, MPI *result, MPI *data, MPI *skey ), + int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ), + int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey ), + unsigned (**get_nbits)( int algo, MPI *pkey ) ); + #endif /*G10_CIPHER_DYNLOAD_H*/ diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 7fad35c5..b37c756c 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -31,42 +31,53 @@ #include "cipher.h" #include "elgamal.h" +typedef struct { + MPI p; /* prime */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ +} ELG_public_key; -void -elg_free_public_key( ELG_public_key *pk ) -{ - mpi_free( pk->p ); pk->p = NULL; - mpi_free( pk->g ); pk->g = NULL; - mpi_free( pk->y ); pk->y = NULL; -} -void -elg_free_secret_key( ELG_secret_key *sk ) -{ - mpi_free( sk->p ); sk->p = NULL; - mpi_free( sk->g ); sk->g = NULL; - mpi_free( sk->y ); sk->y = NULL; - mpi_free( sk->x ); sk->x = NULL; -} +typedef struct { + MPI p; /* prime */ + MPI g; /* group generator */ + MPI y; /* g^x mod p */ + MPI x; /* secret exponent */ +} ELG_secret_key; + + +static void test_keys( ELG_secret_key *sk, unsigned nbits ); +static MPI gen_k( MPI p ); +static void generate( ELG_secret_key *sk, unsigned nbits, MPI **factors ); +static int check_secret_key( ELG_secret_key *sk ); +static void encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ); +static void decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey ); +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 -test_keys( ELG_public_key *pk, ELG_secret_key *sk, unsigned nbits ) +test_keys( ELG_secret_key *sk, unsigned nbits ) { + ELG_public_key pk; MPI test = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB ); + pk.p = sk->p; + pk.g = sk->g; + pk.y = sk->y; + mpi_set_bytes( test, nbits, get_random_byte, 0 ); - elg_encrypt( out1_a, out1_b, test, pk ); - elg_decrypt( out2, out1_a, out1_b, sk ); + encrypt( out1_a, out1_b, test, &pk ); + decrypt( out2, out1_a, out1_b, sk ); if( mpi_cmp( test, out2 ) ) log_fatal("ElGamal operation: encrypt, decrypt failed\n"); - elg_sign( out1_a, out1_b, test, sk ); - if( !elg_verify( out1_a, out1_b, test, pk ) ) + sign( out1_a, out1_b, test, sk ); + if( !verify( out1_a, out1_b, test, &pk ) ) log_fatal("ElGamal operation: sign, verify failed\n"); mpi_free( test ); @@ -115,9 +126,8 @@ gen_k( MPI p ) * Returns: 2 structures filles with all needed values * and an array with n-1 factors of (p-1) */ -void -elg_generate( ELG_public_key *pk, ELG_secret_key *sk, - unsigned nbits, MPI **ret_factors ) +static void +generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors ) { MPI p; /* the prime */ MPI p_min1; @@ -186,16 +196,13 @@ elg_generate( ELG_public_key *pk, ELG_secret_key *sk, } /* copy the stuff to the key structures */ - pk->p = mpi_copy(p); - pk->g = mpi_copy(g); - pk->y = mpi_copy(y); sk->p = p; sk->g = g; sk->y = y; sk->x = x; /* now we can test our keys (this should never fail!) */ - test_keys( pk, sk, nbits - 64 ); + test_keys( sk, nbits - 64 ); mpi_free( p_min1 ); mpi_free( temp ); @@ -206,8 +213,8 @@ elg_generate( ELG_public_key *pk, ELG_secret_key *sk, * Test whether the secret key is valid. * Returns: if this is a valid key. */ -int -elg_check_secret_key( ELG_secret_key *sk ) +static int +check_secret_key( ELG_secret_key *sk ) { int rc; MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) ); @@ -219,8 +226,8 @@ elg_check_secret_key( ELG_secret_key *sk ) } -void -elg_encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ) +static void +encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ) { MPI k; @@ -249,8 +256,8 @@ elg_encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ) -void -elg_decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey ) +static void +decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey ) { MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) ); @@ -276,8 +283,8 @@ elg_decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey ) * Make an Elgamal signature out of INPUT */ -void -elg_sign(MPI a, MPI b, MPI input, ELG_secret_key *skey ) +static void +sign(MPI a, MPI b, MPI input, ELG_secret_key *skey ) { MPI k; MPI t = mpi_alloc( mpi_get_nlimbs(a) ); @@ -322,8 +329,8 @@ elg_sign(MPI a, MPI b, MPI input, ELG_secret_key *skey ) /**************** * Returns true if the signature composed of A and B is valid. */ -int -elg_verify(MPI a, MPI b, MPI input, ELG_public_key *pkey ) +static int +verify(MPI a, MPI b, MPI input, ELG_public_key *pkey ) { int rc; MPI t1; @@ -375,3 +382,151 @@ elg_verify(MPI a, MPI b, MPI input, ELG_public_key *pkey ) return rc; } +/********************************************* + ************** interface ****************** + *********************************************/ + +int +elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ) +{ + ELG_secret_key sk; + + if( !is_ELGAMAL(algo) ) + return G10ERR_PUBKEY_ALGO; + + generate( &sk, nbits, retfactors ); + skey[0] = sk.p; + skey[1] = sk.g; + skey[2] = sk.y; + skey[3] = sk.x; + return 0; +} + + +int +elg_check_secret_key( int algo, MPI *skey ) +{ + ELG_secret_key sk; + + if( !is_ELGAMAL(algo) ) + return G10ERR_PUBKEY_ALGO; + + sk.p = skey[0]; + sk.g = skey[1]; + sk.y = skey[2]; + sk.x = skey[3]; + if( !check_secret_key( &sk ) ) + return G10ERR_BAD_SECKEY; + + return 0; +} + + + +int +elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) +{ + ELG_public_key pk; + + if( !is_ELGAMAL(algo) ) + return G10ERR_PUBKEY_ALGO; + + pk.p = pkey[0]; + pk.g = pkey[1]; + pk.y = pkey[2]; + resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); + resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); + encrypt( resarr[0], resarr[1], data, &pk ); + return 0; +} + +int +elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) +{ + ELG_secret_key sk; + + if( !is_ELGAMAL(algo) ) + return G10ERR_PUBKEY_ALGO; + + sk.p = skey[0]; + sk.g = skey[1]; + sk.y = skey[2]; + sk.x = skey[3]; + *result = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) ); + decrypt( *result, data[0], data[1], &sk ); + return 0; +} + +int +elg_sign( int algo, MPI *resarr, MPI data, MPI *skey ) +{ + ELG_secret_key sk; + + if( !is_ELGAMAL(algo) ) + return G10ERR_PUBKEY_ALGO; + + sk.p = skey[0]; + sk.g = skey[1]; + sk.y = skey[2]; + sk.x = skey[3]; + resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); + sign( resarr[0], resarr[1], data, &sk ); + return 0; +} + +int +elg_verify( int algo, MPI hash, MPI *data, MPI *pkey ) +{ + ELG_public_key pk; + + if( !is_ELGAMAL(algo) ) + return G10ERR_PUBKEY_ALGO; + + pk.p = pkey[0]; + pk.g = pkey[1]; + pk.y = pkey[2]; + if( !verify( data[0], data[1], hash, &pk ) ) + return G10ERR_BAD_SIGN; + return 0; +} + + + +unsigned +elg_get_nbits( int algo, MPI *pkey ) +{ + if( !is_ELGAMAL(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 + * NOTE: This function allows signing also for ELG-E, chich is not + * okay but a bad hack to allow to work with olf gpg keys. The real check + * is done in the gnupg ocde depending on the packet version. + */ +const char * +elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig, + int *usage ) +{ + *npkey = 3; + *nskey = 4; + *nenc = 2; + *nsig = 2; + + switch( algo ) { + case PUBKEY_ALGO_ELGAMAL: *usage = 2|1; return "ELG"; + case PUBKEY_ALGO_ELGAMAL_E: *usage = 2|1; return "ELG-E"; + default: *usage = 0; return NULL; + } +} + + diff --git a/cipher/elgamal.h b/cipher/elgamal.h index d253fbd9..a4668ff9 100644 --- a/cipher/elgamal.h +++ b/cipher/elgamal.h @@ -20,31 +20,15 @@ #ifndef G10_ELGAMAL_H #define G10_ELGAMAL_H -#include "mpi.h" +int elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); +int elg_check_secret_key( int algo, MPI *skey ); +int elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ); +int elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey ); +int elg_sign( int algo, MPI *resarr, MPI data, MPI *skey ); +int elg_verify( int algo, MPI hash, MPI *data, MPI *pkey ); +unsigned elg_get_nbits( int algo, MPI *pkey ); +const char *elg_get_info( int algo, int *npkey, int *nskey, + int *nenc, int *nsig, int *usage ); -typedef struct { - MPI p; /* prime */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ -} ELG_public_key; - - -typedef struct { - MPI p; /* prime */ - MPI g; /* group generator */ - MPI y; /* g^x mod p */ - MPI x; /* secret exponent */ -} ELG_secret_key; - - -void elg_free_public_key( ELG_public_key *pk ); -void elg_free_secret_key( ELG_secret_key *sk ); -void elg_generate( ELG_public_key *pk, ELG_secret_key *sk, - unsigned nbits, MPI **factors ); -int elg_check_secret_key( ELG_secret_key *sk ); -void elg_encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey ); -void elg_decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey ); -void elg_sign(MPI a, MPI b, MPI input, ELG_secret_key *skey); -int elg_verify(MPI a, MPI b, MPI input, ELG_public_key *pkey); #endif /*G10_ELGAMAL_H*/ diff --git a/cipher/g10c.c b/cipher/g10c.c new file mode 100644 index 00000000..c6f94022 --- /dev/null +++ b/cipher/g10c.c @@ -0,0 +1,43 @@ +/* g10c.c - Wrapper for cipher functions + * Copyright (C) 1998 Free Software Foundation, Inc. + * + * This file is part of GNUPG. + * + * GNUPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GNUPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include "mpi.h" +#include "random.h" +#include "cipher.h" +#define _g10lib_INTERNAL 1 +#include "g10lib.h" + + +MPI +g10c_generate_secret_prime( unsigned nbits ) +{ + return generate_secret_prime( nbits ); +} + +byte +g10c_get_random_byte( int level ) +{ + return get_random_byte( level ); +} + + diff --git a/cipher/md.c b/cipher/md.c index 4341b396..30d7e255 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -27,6 +27,76 @@ #include "cipher.h" #include "errors.h" + + +/* Note: the first string is the one used by ascii armor */ +static struct { const char *name; int algo;} digest_names[] = { + { "MD5", DIGEST_ALGO_MD5 }, + { "SHA1", DIGEST_ALGO_SHA1 }, + { "SHA-1", DIGEST_ALGO_SHA1 }, + { "RIPEMD160", DIGEST_ALGO_RMD160 }, + { "RMD160", DIGEST_ALGO_RMD160 }, + { "RMD-160", DIGEST_ALGO_RMD160 }, + { "RIPE-MD-160", DIGEST_ALGO_RMD160 }, + { "TIGER", DIGEST_ALGO_TIGER }, + {NULL} }; + + + + +/**************** + * Map a string to the digest algo + */ +int +string_to_digest_algo( const char *string ) +{ + int i; + const char *s; + + for(i=0; (s=digest_names[i].name); i++ ) + if( !stricmp( s, string ) ) + return digest_names[i].algo; + return 0; +} + + +/**************** + * Map a digest algo to a string + */ +const char * +digest_algo_to_string( int algo ) +{ + int i; + + for(i=0; digest_names[i].name; i++ ) + if( digest_names[i].algo == algo ) + return digest_names[i].name; + return NULL; +} + + +int +check_digest_algo( int algo ) +{ + switch( algo ) { + #ifdef WITH_TIGER_HASH + case DIGEST_ALGO_TIGER: + #endif + case DIGEST_ALGO_MD5: + case DIGEST_ALGO_RMD160: + case DIGEST_ALGO_SHA1: + return 0; + default: + return G10ERR_DIGEST_ALGO; + } +} + + + + + + + /**************** * Open a message digest handle for use with algorithm ALGO. * More algorithms may be added by md_enable(). The initial algorithm diff --git a/cipher/md.h b/cipher/md.h index e55a99ee..2d45a127 100644 --- a/cipher/md.h +++ b/cipher/md.h @@ -55,6 +55,9 @@ typedef struct { } while(0) /*-- md.c --*/ +int string_to_digest_algo( const char *string ); +const char * digest_algo_to_string( int algo ); +int check_digest_algo( int algo ); MD_HANDLE md_open( int algo, int secure ); void md_enable( MD_HANDLE hd, int algo ); MD_HANDLE md_copy( MD_HANDLE a ); diff --git a/cipher/misc.c b/cipher/misc.c deleted file mode 100644 index b81a4fa4..00000000 --- a/cipher/misc.c +++ /dev/null @@ -1,175 +0,0 @@ -/* misc.c - utility functions - * Copyright (C) 1998 Free Software Foundation, Inc. - * - * This file is part of GNUPG. - * - * GNUPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GNUPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include "util.h" -#include "cipher.h" - - -static struct { const char *name; int algo;} pubkey_names[] = { - { "RSA", PUBKEY_ALGO_RSA }, - { "RSA-E", PUBKEY_ALGO_RSA_E }, - { "RSA-S", PUBKEY_ALGO_RSA_S }, - { "ELG", PUBKEY_ALGO_ELGAMAL }, - { "ELG-E", PUBKEY_ALGO_ELGAMAL_E }, - { "ELGAMAL", PUBKEY_ALGO_ELGAMAL }, - { "DSA", PUBKEY_ALGO_DSA }, - {NULL} }; - -/* Note: the first string is the one used by ascii armor */ -static struct { const char *name; int algo;} digest_names[] = { - { "MD5", DIGEST_ALGO_MD5 }, - { "SHA1", DIGEST_ALGO_SHA1 }, - { "SHA-1", DIGEST_ALGO_SHA1 }, - { "RIPEMD160", DIGEST_ALGO_RMD160 }, - { "RMD160", DIGEST_ALGO_RMD160 }, - { "RMD-160", DIGEST_ALGO_RMD160 }, - { "RIPE-MD-160", DIGEST_ALGO_RMD160 }, - { "TIGER", DIGEST_ALGO_TIGER }, - {NULL} }; - - - - - -/**************** - * Map a string to the pubkey algo - */ -int -string_to_pubkey_algo( const char *string ) -{ - int i; - const char *s; - - for(i=0; (s=pubkey_names[i].name); i++ ) - if( !stricmp( s, string ) ) - return pubkey_names[i].algo; - return 0; -} - - -/**************** - * Map a pubkey algo to a string - */ -const char * -pubkey_algo_to_string( int algo ) -{ - int i; - - if( is_ELGAMAL(algo) ) - algo = PUBKEY_ALGO_ELGAMAL; - else if( is_RSA(algo) ) - algo = PUBKEY_ALGO_RSA; - - for(i=0; pubkey_names[i].name; i++ ) - if( pubkey_names[i].algo == algo ) - return pubkey_names[i].name; - return NULL; -} - - - -/**************** - * Map a string to the digest algo - */ -int -string_to_digest_algo( const char *string ) -{ - int i; - const char *s; - - for(i=0; (s=digest_names[i].name); i++ ) - if( !stricmp( s, string ) ) - return digest_names[i].algo; - return 0; -} - - -/**************** - * Map a digest algo to a string - */ -const char * -digest_algo_to_string( int algo ) -{ - int i; - - for(i=0; digest_names[i].name; i++ ) - if( digest_names[i].algo == algo ) - return digest_names[i].name; - return NULL; -} - - - - -int -check_pubkey_algo( int algo ) -{ - return check_pubkey_algo2( algo, 0 ); -} - -/**************** - * a usage of 0 means: don't care - */ -int -check_pubkey_algo2( int algo, unsigned usage ) -{ - switch( algo ) { - case PUBKEY_ALGO_DSA: - if( usage & 2 ) - return G10ERR_WR_PUBKEY_ALGO; - return 0; - - case PUBKEY_ALGO_ELGAMAL: - case PUBKEY_ALGO_ELGAMAL_E: - return 0; - - #ifdef HAVE_RSA_CIPHER - case PUBKEY_ALGO_RSA: - return 0; - #endif - default: - return G10ERR_PUBKEY_ALGO; - } -} - - -int -check_digest_algo( int algo ) -{ - switch( algo ) { - #ifdef WITH_TIGER_HASH - case DIGEST_ALGO_TIGER: - #endif - case DIGEST_ALGO_MD5: - case DIGEST_ALGO_RMD160: - case DIGEST_ALGO_SHA1: - return 0; - default: - return G10ERR_DIGEST_ALGO; - } -} - - - diff --git a/cipher/primegen.c b/cipher/primegen.c index 26d21acb..23aa1dbe 100644 --- a/cipher/primegen.c +++ b/cipher/primegen.c @@ -112,6 +112,8 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits, /* make a pool of 3n+5 primes (this is an arbitrary value) */ m = n*3+5; + if( mode == 1 ) + m += 5; /* need some more for DSA */ if( m < 25 ) m = 25; pool = m_alloc_clear( m * sizeof *pool ); diff --git a/cipher/pubkey.c b/cipher/pubkey.c index 0a4b3430..3357ae12 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -30,18 +30,282 @@ #include "cipher.h" #include "dynload.h" + +#define TABLE_SIZE 20 + +struct pubkey_table_s { + const char *name; + int algo; + int npkey; + int nskey; + int nenc; + int nsig; + int usage; + int (*generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); + int (*check_secret_key)( int algo, MPI *skey ); + int (*encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey ); + int (*decrypt)( int algo, MPI *result, MPI *data, MPI *skey ); + int (*sign)( int algo, MPI *resarr, MPI data, MPI *skey ); + int (*verify)( int algo, MPI hash, MPI *data, MPI *pkey ); + unsigned (*get_nbits)( int algo, MPI *pkey ); +}; + +static struct pubkey_table_s pubkey_table[TABLE_SIZE]; + + + +static int +dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ) +{ log_bug("no generate() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_check_secret_key( int algo, MPI *skey ) +{ log_bug("no check_secret_key() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) +{ log_bug("no encrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) +{ log_bug("no decrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey ) +{ log_bug("no sign() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey ) +{ log_bug("no verify() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static unsigned +dummy_get_nbits( int algo, MPI *pkey ) +{ log_bug("no get_nbits() for %d\n", algo ); return 0; } + + +/**************** + * Put the static entries into the table. + */ +static void +setup_pubkey_table() +{ + + static int initialized = 0; + int i; + + if( initialized ) + return; + + i = 0; + pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL; + pubkey_table[i].name = elg_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].usage ); + pubkey_table[i].generate = elg_generate; + pubkey_table[i].check_secret_key = elg_check_secret_key; + pubkey_table[i].encrypt = elg_encrypt; + pubkey_table[i].decrypt = elg_decrypt; + pubkey_table[i].sign = elg_sign; + pubkey_table[i].verify = elg_verify; + pubkey_table[i].get_nbits = elg_get_nbits; + if( !pubkey_table[i].name ) + BUG(); + i++; + pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E; + pubkey_table[i].name = elg_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].usage ); + pubkey_table[i].generate = elg_generate; + pubkey_table[i].check_secret_key = elg_check_secret_key; + pubkey_table[i].encrypt = elg_encrypt; + pubkey_table[i].decrypt = elg_decrypt; + pubkey_table[i].sign = elg_sign; + pubkey_table[i].verify = elg_verify; + pubkey_table[i].get_nbits = elg_get_nbits; + if( !pubkey_table[i].name ) + BUG(); + i++; + pubkey_table[i].algo = PUBKEY_ALGO_DSA; + pubkey_table[i].name = dsa_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].usage ); + pubkey_table[i].generate = dsa_generate; + pubkey_table[i].check_secret_key = dsa_check_secret_key; + pubkey_table[i].encrypt = dummy_encrypt; + pubkey_table[i].decrypt = dummy_decrypt; + pubkey_table[i].sign = dsa_sign; + pubkey_table[i].verify = dsa_verify; + pubkey_table[i].get_nbits = dsa_get_nbits; + if( !pubkey_table[i].name ) + BUG(); + i++; + + for( ; i < TABLE_SIZE; i++ ) + pubkey_table[i].name = NULL; + initialized = 1; +} + + +/**************** + * Try to load all modules and return true if new modules are available + */ +static int +load_pubkey_modules() +{ + static int done = 0; + void *context = NULL; + struct pubkey_table_s *ct; + int ct_idx; + int i; + const char *name; + int any = 0; + + if( done ) + return 0; + done = 1; + for(ct_idx=0, ct = pubkey_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) { + if( !ct->name ) + break; + } + if( ct_idx >= TABLE_SIZE-1 ) + BUG(); /* table already full */ + /* now load all extensions */ + while( (name = enum_gnupgext_pubkeys( &context, &ct->algo, + &ct->npkey, &ct->nskey, &ct->nenc, + &ct->nsig, &ct->usage, + &ct->generate, + &ct->check_secret_key, + &ct->encrypt, + &ct->decrypt, + &ct->sign, + &ct->verify, + &ct->get_nbits )) ) { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == ct->algo ) + break; + if( pubkey_table[i].name ) { + log_info("skipping pubkey %d: already loaded\n", ct->algo ); + continue; + } + + if( !ct->generate ) ct->generate = dummy_generate; + if( !ct->check_secret_key ) ct->check_secret_key = + dummy_check_secret_key; + if( !ct->encrypt ) ct->encrypt = dummy_encrypt; + if( !ct->decrypt ) ct->decrypt = dummy_decrypt; + if( !ct->sign ) ct->sign = dummy_sign; + if( !ct->verify ) ct->verify = dummy_verify; + if( !ct->get_nbits ) ct->get_nbits= dummy_get_nbits; + /* put it into the table */ + if( g10_opt_verbose > 1 ) + log_info("loaded pubkey %d (%s)\n", ct->algo, name); + ct->name = name; + ct_idx++; + ct++; + any = 1; + /* check whether there are more available table slots */ + if( ct_idx >= TABLE_SIZE-1 ) { + log_info("pubkey table full; ignoring other extensions\n"); + break; + } + } + enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL ); + return any; +} + + +/**************** + * Map a string to the pubkey algo + */ +int +string_to_pubkey_algo( const char *string ) +{ + int i; + const char *s; + + setup_pubkey_table(); + do { + for(i=0; (s=pubkey_table[i].name); i++ ) + if( !stricmp( s, string ) ) + return pubkey_table[i].algo; + } while( load_pubkey_modules() ); + return 0; +} + + +/**************** + * Map a pubkey algo to a string + */ +const char * +pubkey_algo_to_string( int algo ) +{ + int i; + + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return pubkey_table[i].name; + } while( load_pubkey_modules() ); + return NULL; +} + + + +int +check_pubkey_algo( int algo ) +{ + return check_pubkey_algo2( algo, 0 ); +} + +/**************** + * a usage of 0 means: don't care + */ +int +check_pubkey_algo2( int algo, unsigned usage ) +{ + int i; + + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) { + if( (usage & 1) && !(pubkey_table[i].usage & 1) ) + return G10ERR_WR_PUBKEY_ALGO; + if( (usage & 2) && !(pubkey_table[i].usage & 2) ) + return G10ERR_WR_PUBKEY_ALGO; + return 0; /* okay */ + } + } while( load_pubkey_modules() ); + return G10ERR_PUBKEY_ALGO; +} + + + + /**************** * Return the number of public key material numbers */ int pubkey_get_npkey( int algo ) { - if( is_ELGAMAL(algo) ) - return 3; - if( is_RSA(algo) ) - return 2; - if( algo == PUBKEY_ALGO_DSA ) - return 4; + int i; + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return pubkey_table[i].npkey; + } while( load_pubkey_modules() ); return 0; } @@ -51,12 +315,13 @@ pubkey_get_npkey( int algo ) int pubkey_get_nskey( int algo ) { - if( is_ELGAMAL(algo) ) - return 4; - if( is_RSA(algo) ) - return 6; - if( algo == PUBKEY_ALGO_DSA ) - return 5; + int i; + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return pubkey_table[i].nskey; + } while( load_pubkey_modules() ); return 0; } @@ -66,12 +331,13 @@ pubkey_get_nskey( int algo ) int pubkey_get_nsig( int algo ) { - if( is_ELGAMAL(algo) ) - return 2; - if( is_RSA(algo) ) - return 1; - if( algo == PUBKEY_ALGO_DSA ) - return 2; + int i; + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return pubkey_table[i].nsig; + } while( load_pubkey_modules() ); return 0; } @@ -81,10 +347,13 @@ pubkey_get_nsig( int algo ) int pubkey_get_nenc( int algo ) { - if( is_ELGAMAL(algo) ) - return 2; - if( is_RSA(algo) ) - return 1; + int i; + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return pubkey_table[i].nenc; + } while( load_pubkey_modules() ); return 0; } @@ -94,61 +363,46 @@ pubkey_get_nenc( int algo ) unsigned pubkey_nbits( int algo, MPI *pkey ) { - if( is_ELGAMAL( algo ) ) - return mpi_get_nbits( pkey[0] ); - - if( algo == PUBKEY_ALGO_DSA ) - return mpi_get_nbits( pkey[0] ); + int i; + + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return (*pubkey_table[i].get_nbits)( algo, pkey ); + } while( load_pubkey_modules() ); + return 0; +} - if( is_RSA( algo) ) - return mpi_get_nbits( pkey[0] ); - return 0; +int +pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ) +{ + int i; + + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return (*pubkey_table[i].generate)( algo, nbits, + skey, retfactors ); + } while( load_pubkey_modules() ); + return G10ERR_PUBKEY_ALGO; } int pubkey_check_secret_key( int algo, MPI *skey ) { - int rc = 0; - - if( is_ELGAMAL(algo) ) { - ELG_secret_key sk; - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - if( !elg_check_secret_key( &sk ) ) - rc = G10ERR_BAD_SECKEY; - } - else if( algo == PUBKEY_ALGO_DSA ) { - DSA_secret_key sk; - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - if( !dsa_check_secret_key( &sk ) ) - rc = G10ERR_BAD_SECKEY; - } - #ifdef HAVE_RSA_CIPHER - else if( is_RSA(k->pubkey_algo) ) { - /* FIXME */ - RSA_secret_key sk; - assert( ndata == 1 && nskey == 6 ); - sk.n = skey[0]; - sk.e = skey[1]; - sk.d = skey[2]; - sk.p = skey[3]; - sk.q = skey[4]; - sk.u = skey[5]; - plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) ); - rsa_secret( plain, data[0], &sk ); - } - #endif - else - rc = G10ERR_PUBKEY_ALGO; - return rc; + int i; + + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return (*pubkey_table[i].check_secret_key)( algo, skey ); + } while( load_pubkey_modules() ); + return G10ERR_PUBKEY_ALGO; } @@ -161,41 +415,32 @@ pubkey_check_secret_key( int algo, MPI *skey ) int pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) { + int i, rc; + + /* FIXME: check that data fits into the key (in xxx_encrypt)*/ + + setup_pubkey_table(); if( DBG_CIPHER ) { - int i; log_debug("pubkey_encrypt: algo=%d\n", algo ); for(i=0; i < pubkey_get_npkey(algo); i++ ) log_mpidump(" pkey:", pkey[i] ); log_mpidump(" data:", data ); } - /* FIXME: check that data fits into the key */ - if( is_ELGAMAL(algo) ) { - ELG_public_key pk; - pk.p = pkey[0]; - pk.g = pkey[1]; - pk.y = pkey[2]; - resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); - resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); - elg_encrypt( resarr[0], resarr[1], data, &pk ); - } - #ifdef HAVE_RSA_CIPHER - else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) { - RSA_public_key pk; - pk.n = pkey[0]; - pk.e = pkey[1]; - resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); - rsa_public( resarr[0], data, &pk ); - } - #endif - else - return G10ERR_PUBKEY_ALGO; - if( DBG_CIPHER ) { - int i; + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) { + rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey ); + goto ready; + } + } while( load_pubkey_modules() ); + rc = G10ERR_PUBKEY_ALGO; + ready: + if( !rc && DBG_CIPHER ) { for(i=0; i < pubkey_get_nenc(algo); i++ ) log_mpidump(" encr:", resarr[i] ); } - return 0; + return rc; } @@ -210,44 +455,31 @@ pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) { - MPI plain = NULL; + int i, rc; + setup_pubkey_table(); *result = NULL; /* so the caller can always do an mpi_free */ if( DBG_CIPHER ) { - int i; log_debug("pubkey_decrypt: algo=%d\n", algo ); for(i=0; i < pubkey_get_nskey(algo); i++ ) log_mpidump(" skey:", skey[i] ); for(i=0; i < pubkey_get_nenc(algo); i++ ) log_mpidump(" data:", data[i] ); } - if( is_ELGAMAL(algo) ) { - ELG_secret_key sk; - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - plain = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) ); - elg_decrypt( plain, data[0], data[1], &sk ); - } - #ifdef HAVE_RSA_CIPHER - else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E ) { - RSA_secret_key sk; - sk.n = skey[0]; - sk.e = skey[1]; - sk.d = skey[2]; - sk.p = skey[3]; - sk.q = skey[4]; - sk.u = skey[5]; - plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) ); - rsa_secret( plain, data[0], &sk ); - } - #endif - else - return G10ERR_PUBKEY_ALGO; - *result = plain; - return 0; + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) { + rc = (*pubkey_table[i].decrypt)( algo, result, data, skey ); + goto ready; + } + } while( load_pubkey_modules() ); + rc = G10ERR_PUBKEY_ALGO; + ready: + if( !rc && DBG_CIPHER ) { + log_mpidump(" plain:", *result ); + } + return rc; } @@ -260,58 +492,30 @@ pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) int pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey ) { + int i, rc; + + setup_pubkey_table(); if( DBG_CIPHER ) { - int i; log_debug("pubkey_sign: algo=%d\n", algo ); for(i=0; i < pubkey_get_nskey(algo); i++ ) log_mpidump(" skey:", skey[i] ); log_mpidump(" data:", data ); } - if( is_ELGAMAL(algo) ) { - ELG_secret_key sk; - sk.p = skey[0]; - sk.g = skey[1]; - sk.y = skey[2]; - sk.x = skey[3]; - resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - elg_sign( resarr[0], resarr[1], data, &sk ); - } - else if( algo == PUBKEY_ALGO_DSA ) { - DSA_secret_key sk; - sk.p = skey[0]; - sk.q = skey[1]; - sk.g = skey[2]; - sk.y = skey[3]; - sk.x = skey[4]; - resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) ); - dsa_sign( resarr[0], resarr[1], data, &sk ); - } - #ifdef HAVE_RSA_CIPHER - else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) { - RSA_secret_key sk; - sk.n = skey[0]; - sk.e = skey[1]; - sk.d = skey[2]; - sk.p = skey[3]; - sk.q = skey[4]; - sk.u = skey[5]; - plain = mpi_alloc_secure( mpi_get_nlimbs(sk.n) ); - rsa_sign( plain, data[0], &sk ); - } - #endif - else - return G10ERR_PUBKEY_ALGO; - - if( DBG_CIPHER ) { - int i; + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) { + rc = (*pubkey_table[i].sign)( algo, resarr, data, skey ); + goto ready; + } + } while( load_pubkey_modules() ); + rc = G10ERR_PUBKEY_ALGO; + ready: + if( !rc && DBG_CIPHER ) { for(i=0; i < pubkey_get_nsig(algo); i++ ) log_mpidump(" sig:", resarr[i] ); } - - return 0; + return rc; } /**************** @@ -321,113 +525,18 @@ pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey ) int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey ) { - int rc = 0; - - if( is_ELGAMAL( algo ) ) { - ELG_public_key pk; - pk.p = pkey[0]; - pk.g = pkey[1]; - pk.y = pkey[2]; - if( !elg_verify( data[0], data[1], hash, &pk ) ) - rc = G10ERR_BAD_SIGN; - } - else if( algo == PUBKEY_ALGO_DSA ) { - DSA_public_key pk; - pk.p = pkey[0]; - pk.q = pkey[1]; - pk.g = pkey[2]; - pk.y = pkey[3]; - if( !dsa_verify( data[0], data[1], hash, &pk ) ) - rc = G10ERR_BAD_SIGN; - } - #ifdef HAVE_RSA_CIPHER - else if( algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_S ) { - RSA_public_key pk; - int i, j, c, old_enc; - byte *dp; - const byte *asn; - size_t mdlen, asnlen; - - pk.e = pkey[0]; - pk.n = pkey[1]; - result = mpi_alloc(40); - rsa_public( result, data[0], &pk ); - - old_enc = 0; - for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) { - if( !j ) { - if( !i && c != 1 ) - break; - else if( i && c == 0xff ) - ; /* skip the padding */ - else if( i && !c ) - j++; - else - break; + int i, rc; + + setup_pubkey_table(); + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) { + rc = (*pubkey_table[i].verify)( algo, hash, data, pkey ); + goto ready; } - else if( ++j == 18 && c != 1 ) - break; - else if( j == 19 && c == 0 ) { - old_enc++; - break; - } - } - if( old_enc ) { - log_error("old encoding scheme is not supported\n"); - rc = G10ERR_GENERAL; - goto leave; - } - - if( (rc=check_digest_algo(sig->digest_algo)) ) - goto leave; /* unsupported algo */ - md_enable( digest, sig->digest_algo ); - asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen ); - - for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0; - i++, j-- ) - if( asn[j] != c ) - break; - if( j != -1 || mpi_getbyte(result, i) ) { /* ASN is wrong */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - for(i++; (c=mpi_getbyte(result, i)) != -1; i++ ) - if( c != 0xff ) - break; - i++; - if( c != sig->digest_algo || mpi_getbyte(result, i) ) { - /* Padding or leading bytes in signature is wrong */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0] - || mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) { - /* Wrong key used to check the signature */ - rc = G10ERR_BAD_PUBKEY; - goto leave; - } - - /* complete the digest */ - md_putc( digest, sig->sig_class ); - { u32 a = sig->timestamp; - md_putc( digest, (a >> 24) & 0xff ); - md_putc( digest, (a >> 16) & 0xff ); - md_putc( digest, (a >> 8) & 0xff ); - md_putc( digest, a & 0xff ); - } - md_final( digest ); - dp = md_read( digest, sig->digest_algo ); - for(i=mdlen-1; i >= 0; i--, dp++ ) { - if( mpi_getbyte( result, i ) != *dp ) { - rc = G10ERR_BAD_SIGN; - break; - } - } - } - #endif - else - rc = G10ERR_PUBKEY_ALGO; - + } while( load_pubkey_modules() ); + rc = G10ERR_PUBKEY_ALGO; + ready: return rc; } |