diff options
author | Werner Koch <[email protected]> | 1999-10-26 12:14:37 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 1999-10-26 12:14:37 +0000 |
commit | cf70ca8d68eb836b952f2c234f064b1afc205962 (patch) | |
tree | aa33afbc79efd1f8538e5286b13d900321a8f14b /cipher | |
parent | Changed the way it works - now needs an extra program to to most tasks. (diff) | |
download | gnupg-cf70ca8d68eb836b952f2c234f064b1afc205962.tar.gz gnupg-cf70ca8d68eb836b952f2c234f064b1afc205962.zip |
See ChangeLog: Tue Oct 26 14:10:21 CEST 1999 Werner Koch
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/ChangeLog | 18 | ||||
-rw-r--r-- | cipher/cipher.c | 366 | ||||
-rw-r--r-- | cipher/elgamal.c | 4 | ||||
-rw-r--r-- | cipher/md.c | 430 | ||||
-rw-r--r-- | cipher/pubkey.c | 83 |
5 files changed, 735 insertions, 166 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog index 944510a38..ea23ca182 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -1,3 +1,21 @@ +Tue Oct 26 14:10:21 CEST 1999 Werner Koch <[email protected]> + + * elgamal.c (sign): Hugh found strange code here. Replaced by BUG(). + + * cipher.c: Merged with gcrypt/symapi.c. + + * pubkey.c (string_to_pubkey_algo): Renamed function to ... + (gcry_pk_map_name): ... this. + (pubkey_algo_to_string): Renamed function to ... + (gcry_pk_algo_name): ... this. + (gcry_pk_algo_info): New. + * pubkey.c: Merged with gcrypt/pkapi.c. + + * md.c (md_reset): Clear finalized; thanks to Ulf Moeller for + fixing this bug. + + * md.c: Merged with gcrypt/mdapi.c + Wed Sep 15 14:39:59 CEST 1999 Michael Roth <[email protected]> * des.c: Various speed improvements: One bit pre rotation diff --git a/cipher/cipher.c b/cipher/cipher.c index 7224ab69d..277dd13f0 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -24,6 +24,8 @@ #include <string.h> #include <errno.h> #include <assert.h> + +#include "g10lib.h" #include "util.h" #include "errors.h" #include "cipher.h" @@ -32,9 +34,10 @@ #include "cast5.h" #include "dynload.h" - #define MAX_BLOCKSIZE 16 #define TABLE_SIZE 10 +#define CTX_MAGIC_NORMAL 0x24091964 +#define CTX_MAGIC_SECURE 0x46919042 struct cipher_table_s { const char *name; @@ -50,10 +53,11 @@ struct cipher_table_s { static struct cipher_table_s cipher_table[TABLE_SIZE]; static int disabled_algos[TABLE_SIZE]; - -struct cipher_handle_s { +struct gcry_cipher_handle { + int magic; int algo; int mode; + unsigned int flags; size_t blocksize; byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */ byte lastiv[MAX_BLOCKSIZE]; @@ -209,16 +213,13 @@ load_cipher_modules(void) } - - - - - /**************** - * Map a string to the cipher algo + * Map a string to the cipher algo. + * Returns: The algo ID of the cipher for the gioven name or + * 0 if the name is not known. */ int -string_to_cipher_algo( const char *string ) +gcry_cipher_map_name( const char *string ) { int i; const char *s; @@ -234,7 +235,7 @@ string_to_cipher_algo( const char *string ) /**************** * Map a cipher algo to a string */ -const char * +static const char * cipher_algo_to_string( int algo ) { int i; @@ -247,8 +248,20 @@ cipher_algo_to_string( int algo ) return NULL; } +/**************** + * This function simply returns the name of the algorithm or some constant + * string when there is no algo. It will never return NULL. + */ +const char * +gcry_cipher_algo_name( int algo ) +{ + const char *s = cipher_algo_to_string( algo ); + return s? s: ""; +} -void + + +static void disable_cipher_algo( int algo ) { int i; @@ -266,7 +279,7 @@ disable_cipher_algo( int algo ) /**************** * Return 0 if the cipher algo is available */ -int +static int check_cipher_algo( int algo ) { int i; @@ -285,7 +298,7 @@ check_cipher_algo( int algo ) } -unsigned +static unsigned cipher_get_keylen( int algo ) { int i; @@ -305,7 +318,7 @@ cipher_get_keylen( int algo ) return 0; } -unsigned +static unsigned cipher_get_blocksize( int algo ) { int i; @@ -328,70 +341,98 @@ cipher_get_blocksize( int algo ) /**************** * Open a cipher handle for use with algorithm ALGO, in mode MODE - * and put it into secure memory if SECURE is true. + * and return the handle. Return NULL and set the internal error variable + * if something goes wrong. */ -CIPHER_HANDLE -cipher_open( int algo, int mode, int secure ) + +GCRY_CIPHER_HD +gcry_cipher_open( int algo, int mode, unsigned int flags ) { - CIPHER_HANDLE hd; - int i; + GCRY_CIPHER_HD h; + int idx; + int secure = (flags & GCRY_CIPHER_SECURE); fast_random_poll(); - do { - for(i=0; cipher_table[i].name; i++ ) - if( cipher_table[i].algo == algo ) - break; - } while( !cipher_table[i].name && load_cipher_modules() ); - if( !cipher_table[i].name ) { - log_fatal("cipher_open: algorithm %d not available\n", algo ); + + /* check whether the algo is available */ + if( check_cipher_algo( algo ) ) { + set_lasterr( GCRYERR_INV_ALGO ); return NULL; } - /* ? perform selftest here and mark this with a flag in cipher_table ? */ + /* check flags */ + if( (flags & ~(GCRY_CIPHER_SECURE|GCRY_CIPHER_ENABLE_SYNC)) ) { + set_lasterr( GCRYERR_INV_ARG ); + return NULL; + } + + /* get the table index of the algo */ + for(idx=0; cipher_table[idx].name; idx++ ) + if( cipher_table[idx].algo == algo ) + break; + if( !cipher_table[idx].name ) + BUG(); /* check_cipher_algo() should have loaded the algo */ - hd = secure ? m_alloc_secure_clear( sizeof *hd - + cipher_table[i].contextsize - - sizeof(PROPERLY_ALIGNED_TYPE) ) - : m_alloc_clear( sizeof *hd + cipher_table[i].contextsize - - sizeof(PROPERLY_ALIGNED_TYPE) ); - hd->algo = algo; - hd->blocksize = cipher_table[i].blocksize; - hd->setkey = cipher_table[i].setkey; - hd->encrypt = cipher_table[i].encrypt; - hd->decrypt = cipher_table[i].decrypt; if( algo == CIPHER_ALGO_DUMMY ) - hd->mode = CIPHER_MODE_DUMMY; - else if( mode == CIPHER_MODE_AUTO_CFB ) { - #warning Remove this code and the AUTO:CFB macro. - if( algo >= 100 ) - hd->mode = CIPHER_MODE_CFB; - else - hd->mode = CIPHER_MODE_PHILS_CFB; + mode = GCRY_CIPHER_MODE_NONE; /* force this mode for dummy algo */ + + /* check that a valid mode has been requested */ + switch( mode ) { + case GCRY_CIPHER_MODE_ECB: + case GCRY_CIPHER_MODE_CBC: + case GCRY_CIPHER_MODE_CFB: + break; + case GCRY_CIPHER_MODE_NONE: + /* FIXME: issue a warning when this mode is used */ + break; + default: + set_lasterr( GCRYERR_INV_ALGO ); + return NULL; } - else - hd->mode = mode; - return hd; + /* ? perform selftest here and mark this with a flag in cipher_table ? */ + + h = secure ? m_alloc_secure_clear( sizeof *h + + cipher_table[idx].contextsize + - sizeof(PROPERLY_ALIGNED_TYPE) ) + : m_alloc_clear( sizeof *h + cipher_table[idx].contextsize + - sizeof(PROPERLY_ALIGNED_TYPE) ); + h->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + h->algo = algo; + h->mode = mode; + h->flags = flags; + h->blocksize = cipher_table[idx].blocksize; + h->setkey = cipher_table[idx].setkey; + h->encrypt = cipher_table[idx].encrypt; + h->decrypt = cipher_table[idx].decrypt; + + return h; } void -cipher_close( CIPHER_HANDLE c ) +gcry_cipher_close( GCRY_CIPHER_HD h ) { - m_free(c); + if( !h ) + return; + if( h->magic != CTX_MAGIC_SECURE && h->magic != CTX_MAGIC_NORMAL ) { + fatal_invalid_arg("gcry_cipher_close: already closed/invalid handle"); + return; + } + h->magic = 0; + m_free(h); } -int -cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ) +static int +cipher_setkey( GCRY_CIPHER_HD c, byte *key, unsigned keylen ) { return (*c->setkey)( &c->context.c, key, keylen ); } - -void -cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ) +static void +cipher_setiv( GCRY_CIPHER_HD c, const byte *iv, unsigned ivlen ) { memset( c->iv, 0, c->blocksize ); if( iv ) { @@ -408,7 +449,7 @@ cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ) static void -do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +do_ecb_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks ) { unsigned n; @@ -420,7 +461,7 @@ do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) } static void -do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +do_ecb_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks ) { unsigned n; @@ -432,7 +473,7 @@ do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) } static void -do_cbc_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +do_cbc_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks ) { unsigned int n; byte *ivp; @@ -453,7 +494,7 @@ do_cbc_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) } static void -do_cbc_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +do_cbc_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nblocks ) { unsigned int n; byte *ivp; @@ -476,7 +517,7 @@ do_cbc_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) static void -do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +do_cfb_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes ) { byte *ivp; size_t blocksize = c->blocksize; @@ -520,7 +561,7 @@ do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) } static void -do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +do_cfb_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes ) { byte *ivp; ulong temp; @@ -582,23 +623,22 @@ do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) * inbuf and outbuf may overlap or be the same. * Depending on the mode some some contraints apply to NBYTES. */ -void -cipher_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +static void +cipher_encrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes ) { switch( c->mode ) { - case CIPHER_MODE_ECB: + case GCRY_CIPHER_MODE_ECB: assert(!(nbytes%8)); do_ecb_encrypt(c, outbuf, inbuf, nbytes/8 ); break; - case CIPHER_MODE_CBC: + case GCRY_CIPHER_MODE_CBC: assert(!(nbytes%8)); /* fixme: should be blocksize */ do_cbc_encrypt(c, outbuf, inbuf, nbytes/8 ); break; - case CIPHER_MODE_CFB: - case CIPHER_MODE_PHILS_CFB: + case GCRY_CIPHER_MODE_CFB: do_cfb_encrypt(c, outbuf, inbuf, nbytes ); break; - case CIPHER_MODE_DUMMY: + case GCRY_CIPHER_MODE_NONE: if( inbuf != outbuf ) memmove( outbuf, inbuf, nbytes ); break; @@ -608,27 +648,53 @@ cipher_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) /**************** + * Encrypt IN and write it to OUT. If IN is NULL, in-place encryption has + * been requested, + */ +int +gcry_cipher_encrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize, + const byte *in, size_t inlen ) +{ + if( !in ) { + /* caller requested in-place encryption */ + /* actullay cipher_encrypt() does not need to know about it, but + * we may chnage this to get better performace */ + cipher_encrypt( h, out, out, outsize ); + } + else { + if( outsize < inlen ) + return set_lasterr( GCRYERR_TOO_SHORT ); + /* fixme: check that the inlength is a multipe of the blocksize + * if a blockoriented mode is used, or modify cipher_encrypt to + * return an error in this case */ + cipher_encrypt( h, out, in, inlen ); + } + return 0; +} + + + +/**************** * Decrypt INBUF to OUTBUF with the mode selected at open. * inbuf and outbuf may overlap or be the same. * Depending on the mode some some contraints apply to NBYTES. */ -void -cipher_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +static void +cipher_decrypt( GCRY_CIPHER_HD c, byte *outbuf, byte *inbuf, unsigned nbytes ) { switch( c->mode ) { - case CIPHER_MODE_ECB: + case GCRY_CIPHER_MODE_ECB: assert(!(nbytes%8)); do_ecb_decrypt(c, outbuf, inbuf, nbytes/8 ); break; - case CIPHER_MODE_CBC: + case GCRY_CIPHER_MODE_CBC: assert(!(nbytes%8)); /* fixme: should assert on blocksize */ do_cbc_decrypt(c, outbuf, inbuf, nbytes/8 ); break; - case CIPHER_MODE_CFB: - case CIPHER_MODE_PHILS_CFB: + case GCRY_CIPHER_MODE_CFB: do_cfb_decrypt(c, outbuf, inbuf, nbytes ); break; - case CIPHER_MODE_DUMMY: + case GCRY_CIPHER_MODE_NONE: if( inbuf != outbuf ) memmove( outbuf, inbuf, nbytes ); break; @@ -637,18 +703,160 @@ cipher_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) } +int +gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize, + const byte *in, size_t inlen ) +{ + if( !in ) { + /* caller requested in-place encryption */ + /* actullay cipher_encrypt() does not need to know about it, but + * we may chnage this to get better performace */ + cipher_decrypt( h, out, out, outsize ); + } + else { + if( outsize < inlen ) + return set_lasterr( GCRYERR_TOO_SHORT ); + /* fixme: check that the inlength is a multipe of the blocksize + * if a blockoriented mode is used, or modify cipher_encrypt to + * return an error in this case */ + cipher_decrypt( h, out, in, inlen ); + } + return 0; +} + + /**************** * Used for PGP's somewhat strange CFB mode. Only works if - * the handle is in PHILS_CFB mode + * the corresponding flag is set. */ -void -cipher_sync( CIPHER_HANDLE c ) +static void +cipher_sync( GCRY_CIPHER_HD c ) { - if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) { + if( (c->flags & GCRY_CIPHER_ENABLE_SYNC) && c->unused ) { memmove(c->iv + c->unused, c->iv, c->blocksize - c->unused ); memcpy(c->iv, c->lastiv + c->blocksize - c->unused, c->unused); c->unused = 0; } } + +int +gcry_cipher_ctl( GCRY_CIPHER_HD h, int cmd, void *buffer, size_t buflen) +{ + switch( cmd ) { + case GCRYCTL_SET_KEY: + cipher_setkey( h, buffer, buflen ); + break; + case GCRYCTL_SET_IV: + cipher_setiv( h, buffer, buflen ); + break; + case GCRYCTL_CFB_SYNC: + cipher_sync( h ); + break; + + case GCRYCTL_DISABLE_ALGO: + /* this one expects a NULL handle and buffer pointing to an + * integer with the algo number. + */ + if( h || !buffer || buflen != sizeof(int) ) + return set_lasterr( GCRYERR_INV_ARG ); + disable_cipher_algo( *(int*)buffer ); + break; + + default: + return set_lasterr( GCRYERR_INV_OP ); + } + return 0; +} + + +/**************** + * Return information about the cipher handle. + * -1 is returned on error and gcry_errno() may be used to get more information + * about the error. + */ +int +gcry_cipher_info( GCRY_CIPHER_HD h, int cmd, void *buffer, size_t *nbytes) +{ + switch( cmd ) { + default: + set_lasterr( GCRYERR_INV_OP ); + return -1; + } + return 0; +} + +/**************** + * Return information about the given cipher algorithm + * WHAT select the kind of information returned: + * GCRYCTL_GET_KEYLEN: + * Return the length of the key, if the algorithm + * supports multiple key length, the maximum supported value + * is returnd. The length is return as number of octets. + * buffer and nbytes must be zero. + * The keylength is returned in _bytes_. + * GCRYCTL_GET_BLKLEN: + * Return the blocklength of the algorithm counted in octets. + * buffer and nbytes must be zero. + * GCRYCTL_TEST_ALGO: + * Returns 0 when the specified algorithm is available for use. + * buffer and nbytes must be zero. + * + * On error the value -1 is returned and the error reason may be + * retrieved by gcry_errno(). + * Note: Because this function is in most caes used to return an + * integer value, we can make it easier for the caller to just look at + * the return value. The caller will in all cases consult the value + * and thereby detecting whether a error occured or not (i.e. while checking + * the block size) + */ +int +gcry_cipher_algo_info( int algo, int what, void *buffer, size_t *nbytes) +{ + unsigned int ui; + + switch( what ) { + case GCRYCTL_GET_KEYLEN: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + break; + } + ui = cipher_get_keylen( algo ); + if( ui > 0 && ui <= 512 ) + return (int)ui/8; + /* the only reason is an invalid algo or a strange blocksize */ + set_lasterr( GCRYERR_INV_ALGO ); + break; + + case GCRYCTL_GET_BLKLEN: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + break; + } + ui = cipher_get_blocksize( algo ); + if( ui > 0 && ui < 10000 ) + return (int)ui; + /* the only reason is an invalid algo or a strange blocksize */ + set_lasterr( GCRYERR_INV_ALGO ); + break; + + case GCRYCTL_TEST_ALGO: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + break; + } + if( check_cipher_algo( algo ) ) { + set_lasterr( GCRYERR_INV_ALGO ); + break; + } + return 0; + + default: + set_lasterr( GCRYERR_INV_OP ); + } + return -1; +} + + + diff --git a/cipher/elgamal.c b/cipher/elgamal.c index bbf9c2782..9f98ce2e0 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -351,8 +351,10 @@ sign(MPI a, MPI b, MPI input, ELG_secret_key *skey ) 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) ) + 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 ); diff --git a/cipher/md.c b/cipher/md.c index be921e4b0..f0dc9394e 100644 --- a/cipher/md.c +++ b/cipher/md.c @@ -24,6 +24,8 @@ #include <string.h> #include <errno.h> #include <assert.h> + +#include "g10lib.h" #include "util.h" #include "cipher.h" #include "errors.h" @@ -31,9 +33,38 @@ #include "rmd.h" +struct md_digest_list_s; + +/* this structure is put right after the GCRY_MD_HD buffer, so that + * only one memory block is needed. */ +struct gcry_md_context { + int magic; + int secure; + FILE *debug; + int finalized; + struct md_digest_list_s *list; +}; +#define CTX_MAGIC_NORMAL 0x11071961 +#define CTX_MAGIC_SECURE 0x16917011 + +static const char * digest_algo_to_string( int algo ); +static int check_digest_algo( int algo ); +static GCRY_MD_HD md_open( int algo, int secure ); +static int md_enable( GCRY_MD_HD hd, int algo ); +static GCRY_MD_HD md_copy( GCRY_MD_HD a ); +static void md_close(GCRY_MD_HD a); +static void md_write( GCRY_MD_HD a, byte *inbuf, size_t inlen); +static void md_final(GCRY_MD_HD a); +static byte *md_read( GCRY_MD_HD a, int algo ); +static int md_get_algo( GCRY_MD_HD a ); +static int md_digest_length( int algo ); +static const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ); +static void md_start_debug( GCRY_MD_HD a, const char *suffix ); +static void md_stop_debug( GCRY_MD_HD a ); + /**************** * This structure is used for the list of available algorithms - * and for the list of algorithms in MD_HANDLE. + * and for the list of algorithms in GCRY_MD_HD. */ struct md_digest_list_s { struct md_digest_list_s *next; @@ -146,7 +177,7 @@ load_digest_module( int req_algo ) * Map a string to the digest algo */ int -string_to_digest_algo( const char *string ) +gcry_md_map_name( const char *string ) { struct md_digest_list_s *r; @@ -162,7 +193,7 @@ string_to_digest_algo( const char *string ) /**************** * Map a digest algo to a string */ -const char * +static const char * digest_algo_to_string( int algo ) { struct md_digest_list_s *r; @@ -175,8 +206,21 @@ digest_algo_to_string( int algo ) return NULL; } +/**************** + * This function simply returns the name of the algorithm or some constant + * string when there is no algo. It will never return NULL. + * Use the macro gcry_md_test_algo() to check whether the algorithm + * is valid. + */ +const char * +gcry_md_algo_name( int algo ) +{ + const char *s = digest_algo_to_string( algo ); + return s? s: "?"; +} -int + +static int check_digest_algo( int algo ) { struct md_digest_list_s *r; @@ -196,37 +240,73 @@ check_digest_algo( int algo ) * More algorithms may be added by md_enable(). The initial algorithm * may be 0. */ -MD_HANDLE +static GCRY_MD_HD md_open( int algo, int secure ) { - MD_HANDLE hd; - int bufsize; - - if( secure ) { - bufsize = 512 - sizeof( *hd ); - hd = m_alloc_secure_clear( sizeof *hd + bufsize ); - } - else { - bufsize = 1024 - sizeof( *hd ); - hd = m_alloc_clear( sizeof *hd + bufsize ); + GCRY_MD_HD hd; + struct gcry_md_context *ctx; + int bufsize = secure? 512 : 1024; + size_t n; + + /* Allocate a memory area to hold the caller visible buffer with it's + * control information and the data required by this module. Set the + * context pointer at the beginning to this area. + * We have to use this strange scheme because we want to hide the + * internal data but have a variable sized buffer. + * + * +---+------+---........------+-------------+ + * !ctx! bctl ! buffer ! private ! + * +---+------+---........------+-------------+ + * ! ^ + * !---------------------------! + * + * We have to make sture that private is well aligned. + */ + n = sizeof( struct gcry_md_handle ) + bufsize; + n = ((n + sizeof(PROPERLY_ALIGNED_TYPE)-1) + / sizeof(PROPERLY_ALIGNED_TYPE) ) * sizeof(PROPERLY_ALIGNED_TYPE); + + /* allocate and set the Context pointer to the private data */ + hd = secure ? m_alloc_secure( n + sizeof( struct gcry_md_context ) ) + : m_alloc( n + sizeof( struct gcry_md_context ) ); + hd->ctx = ctx = (struct gcry_md_context*)( (char*)hd + n ); + /* setup the globally visible data (bctl in the diagram)*/ + hd->bufsize = n - sizeof( struct gcry_md_handle ) + 1; + hd->bufpos = 0; + /* initialize the private data */ + memset( hd->ctx, 0, sizeof *hd->ctx ); + ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; + ctx->secure = secure; + fast_random_poll(); /* FIXME: should we really do that? */ + if( algo && md_enable( hd, algo ) ) { + md_close( hd ); + return NULL; } + return hd; +} + - hd->bufsize = bufsize+1; /* hd has already one byte allocated */ - hd->secure = secure; - if( algo ) - md_enable( hd, algo ); - fast_random_poll(); +GCRY_MD_HD +gcry_md_open( int algo, unsigned int flags ) +{ + GCRY_MD_HD hd; + /* fixme: check that algo is available and that only valid + * flag values are used */ + hd = md_open( algo, (flags & GCRY_MD_FLAG_SECURE) ); return hd; } -void -md_enable( MD_HANDLE h, int algo ) + + +static int +md_enable( GCRY_MD_HD hd, int algo ) { + struct gcry_md_context *h = hd->ctx; struct md_digest_list_s *r, *ac; for( ac=h->list; ac; ac = ac->next ) if( ac->algo == algo ) - return ; /* already enabled */ + return 0; /* already enabled */ /* find the algorithm */ do { for(r = digest_list; r; r = r->next ) @@ -234,8 +314,8 @@ md_enable( MD_HANDLE h, int algo ) break; } while( !r && load_digest_module( algo ) ); if( !r ) { - log_error("md_enable: algorithm %d not available\n", algo ); - return; + log_debug("md_enable: algorithm %d not available\n", algo ); + return set_lasterr( GCRYERR_INV_ALGO ); } /* and allocate a new list entry */ ac = h->secure? m_alloc_secure( sizeof *ac + r->contextsize @@ -247,20 +327,37 @@ md_enable( MD_HANDLE h, int algo ) h->list = ac; /* and init this instance */ (*ac->init)( &ac->context.c ); + return 0; } -MD_HANDLE -md_copy( MD_HANDLE a ) +int +gcry_md_enable( GCRY_MD_HD hd, int algo ) { - MD_HANDLE b; - struct md_digest_list_s *ar, *br; + return md_enable( hd, algo ); +} - if( a->bufcount ) - md_write( a, NULL, 0 ); - b = a->secure ? m_alloc_secure( sizeof *b + a->bufsize - 1 ) - : m_alloc( sizeof *b + a->bufsize - 1 ); - memcpy( b, a, sizeof *a + a->bufsize - 1 ); +static GCRY_MD_HD +md_copy( GCRY_MD_HD ahd ) +{ + struct gcry_md_context *a = ahd->ctx; + struct gcry_md_context *b; + GCRY_MD_HD bhd; + struct md_digest_list_s *ar, *br; + size_t n; + + if( ahd->bufpos ) + md_write( ahd, NULL, 0 ); + + n = (char*)ahd->ctx - (char*)ahd; + bhd = a->secure ? m_alloc_secure( n + sizeof( struct gcry_md_context ) ) + : m_alloc( n + sizeof( struct gcry_md_context ) ); + bhd->ctx = b = (struct gcry_md_context*)( (char*)bhd + n ); + /* no need to copy the buffer due to the write above */ + assert( ahd->bufsize == (n - sizeof( struct gcry_md_handle ) + 1) ); + bhd->bufsize = ahd->bufsize; + bhd->bufpos = 0; assert( !ahd->bufpos ); + memcpy( b, a, sizeof *a ); b->list = NULL; b->debug = NULL; /* and now copy the complete list of algorithms */ @@ -277,38 +374,43 @@ md_copy( MD_HANDLE a ) } if( a->debug ) - md_start_debug( b, "unknown" ); - return b; + md_start_debug( bhd, "unknown" ); + return bhd; } +GCRY_MD_HD +gcry_md_copy( GCRY_MD_HD hd ) +{ + return md_copy( hd ); +} /**************** * Reset all contexts and discard any buffered stuff. This may be used * instead of a md_close(); md_open(). */ void -md_reset( MD_HANDLE a ) +gcry_md_reset( GCRY_MD_HD a ) { struct md_digest_list_s *r; - a->bufcount = 0; - for( r=a->list; r; r = r->next ) { + a->bufpos = a->ctx->finalized = 0; + for( r=a->ctx->list; r; r = r->next ) { memset( r->context.c, 0, r->contextsize ); (*r->init)( &r->context.c ); } } -void -md_close(MD_HANDLE a) +static void +md_close(GCRY_MD_HD a) { struct md_digest_list_s *r, *r2; if( !a ) return; - if( a->debug ) + if( a->ctx->debug ) md_stop_debug(a); - for(r=a->list; r; r = r2 ) { + for(r=a->ctx->list; r; r = r2 ) { r2 = r->next; m_free(r); } @@ -317,60 +419,86 @@ md_close(MD_HANDLE a) void -md_write( MD_HANDLE a, byte *inbuf, size_t inlen) +gcry_md_close( GCRY_MD_HD hd ) +{ + md_close( hd ); +} + + +static void +md_write( GCRY_MD_HD a, byte *inbuf, size_t inlen) { struct md_digest_list_s *r; - if( a->debug ) { - if( a->bufcount && fwrite(a->buffer, a->bufcount, 1, a->debug ) != 1 ) + if( a->ctx->debug ) { + if( a->bufpos && fwrite(a->buf, a->bufpos, 1, a->ctx->debug ) != 1 ) BUG(); - if( inlen && fwrite(inbuf, inlen, 1, a->debug ) != 1 ) + if( inlen && fwrite(inbuf, inlen, 1, a->ctx->debug ) != 1 ) BUG(); } - for(r=a->list; r; r = r->next ) { - (*r->write)( &r->context.c, a->buffer, a->bufcount ); + for(r=a->ctx->list; r; r = r->next ) { + if( a->bufpos ) + (*r->write)( &r->context.c, a->buf, a->bufpos ); (*r->write)( &r->context.c, inbuf, inlen ); } - a->bufcount = 0; + a->bufpos = 0; } - void -md_final(MD_HANDLE a) +gcry_md_write( GCRY_MD_HD hd, const byte *inbuf, size_t inlen) +{ + md_write( hd, (byte*)inbuf, inlen ); +} + + + +static void +md_final(GCRY_MD_HD a) { struct md_digest_list_s *r; - if( a->finalized ) + if( a->ctx->finalized ) return; - if( a->bufcount ) + if( a->bufpos ) md_write( a, NULL, 0 ); - for(r=a->list; r; r = r->next ) { + for(r=a->ctx->list; r; r = r->next ) { (*r->final)( &r->context.c ); } - a->finalized = 1; + a->ctx->finalized = 1; +} + + +int +gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen) +{ + if( cmd == GCRYCTL_FINALIZE ) + md_final( hd ); + else + return GCRYERR_INV_OP; + return 0; } /**************** * if ALGO is null get the digest for the used algo (which should be only one) */ -byte * -md_read( MD_HANDLE a, int algo ) +static byte * +md_read( GCRY_MD_HD a, int algo ) { struct md_digest_list_s *r; if( !algo ) { /* return the first algorithm */ - if( (r=a->list) ) { + if( (r=a->ctx->list) ) { if( r->next ) log_debug("more than algorithm in md_read(0)\n"); return (*r->read)( &r->context.c ); } } else { - for(r=a->list; r; r = r->next ) + for(r=a->ctx->list; r; r = r->next ) if( r->algo == algo ) return (*r->read)( &r->context.c ); } @@ -378,6 +506,17 @@ md_read( MD_HANDLE a, int algo ) return NULL; } +/**************** + * Read out the complete digest, this function implictly finalizes + * the hash. + */ +byte * +gcry_md_read( GCRY_MD_HD hd, int algo ) +{ + gcry_md_ctl( hd, GCRYCTL_FINALIZE, NULL, 0 ); + return md_read( hd, algo); +} + /**************** * This function combines md_final and md_read but keeps the context @@ -388,22 +527,23 @@ md_read( MD_HANDLE a, int algo ) * hold the complete digest, the buffer is filled with as many bytes are * possible and this value is returned. */ -int -md_digest( MD_HANDLE a, int algo, byte *buffer, int buflen ) +#if 0 +static int +md_digest( GCRY_MD_HD a, int algo, byte *buffer, int buflen ) { struct md_digest_list_s *r = NULL; char *context; char *digest; - if( a->bufcount ) + if( a->bufpos ) md_write( a, NULL, 0 ); if( !algo ) { /* return digest for the first algorithm */ - if( (r=a->list) && r->next ) + if( (r=a->ctx->list) && r->next ) log_debug("more than algorithm in md_digest(0)\n"); } else { - for(r=a->list; r; r = r->next ) + for(r=a->ctx->list; r; r = r->next ) if( r->algo == algo ) break; } @@ -414,9 +554,9 @@ md_digest( MD_HANDLE a, int algo, byte *buffer, int buflen ) return r->mdlen; /* I don't want to change the interface, so I simply work on a copy - * the context (extra overhead - should be fixed)*/ - context = a->secure ? m_alloc_secure( r->contextsize ) - : m_alloc( r->contextsize ); + * of the context (extra overhead - should be fixed)*/ + context = a->ctx->secure ? m_alloc_secure( r->contextsize ) + : m_alloc( r->contextsize ); memcpy( context, r->context.c, r->contextsize ); (*r->final)( context ); digest = (*r->read)( context ); @@ -428,14 +568,26 @@ md_digest( MD_HANDLE a, int algo, byte *buffer, int buflen ) m_free(context); return buflen; } +#endif - +/**************** + * Read out an intermediate digest. + */ int -md_get_algo( MD_HANDLE a ) +gcry_md_get( GCRY_MD_HD hd, int algo, byte *buffer, int buflen ) +{ + /*md_digest ... */ + return GCRYERR_INTERNAL; +} + + + +static int +md_get_algo( GCRY_MD_HD a ) { struct md_digest_list_s *r; - if( (r=a->list) ) { + if( (r=a->ctx->list) ) { if( r->next ) log_error("WARNING: more than algorithm in md_get_algo()\n"); return r->algo; @@ -443,10 +595,18 @@ md_get_algo( MD_HANDLE a ) return 0; } + +int +gcry_md_get_algo( GCRY_MD_HD hd ) +{ + return md_get_algo( hd ); /* fixme: we need error handling */ +} + + /**************** * Return the length of the digest */ -int +static int md_digest_length( int algo ) { struct md_digest_list_s *r; @@ -457,14 +617,35 @@ md_digest_length( int algo ) return r->mdlen; } } while( !r && load_digest_module( algo ) ); - log_error("WARNING: no length for md algo %d\n", algo); return 0; } +/**************** + * Return the length of the digest in bytes. + * This function will return 0 in case of errors. + */ +unsigned int +gcry_md_get_algo_dlen( int algo ) +{ + /* we do some very quick checks here */ + switch( algo ) + { + case GCRY_MD_MD5: return 16; + case GCRY_MD_SHA1: + case GCRY_MD_RMD160: return 20; + default: { + int len = md_digest_length( algo ); + if( !len ) + set_lasterr( GCRYERR_INV_ALGO ); + return 0; + } + } +} + /* Hmmm: add a mode to enumerate the OIDs * to make g10/sig-check.c more portable */ -const byte * +static const byte * md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ) { struct md_digest_list_s *r; @@ -485,31 +666,92 @@ md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ) } + +/**************** + * Return information about the given cipher algorithm + * WHAT select the kind of information returned: + * GCRYCTL_TEST_ALGO: + * Returns 0 when the specified algorithm is available for use. + * buffer and nbytes must be zero. + * GCRYCTL_GET_ASNOID: + * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only + * the required length is returned. + * + * On error the value -1 is returned and the error reason may be + * retrieved by gcry_errno(). + * Note: Because this function is in most caes used to return an + * integer value, we can make it easier for the caller to just look at + * the return value. The caller will in all cases consult the value + * and thereby detecting whether a error occured or not (i.e. while checking + * the block size) + */ +int +gcry_md_algo_info( int algo, int what, void *buffer, size_t *nbytes) +{ + switch( what ) { + case GCRYCTL_TEST_ALGO: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + return -1; + } + if( check_digest_algo( algo ) ) { + set_lasterr( GCRYERR_INV_ALGO ); + return -1; + } + break; + + case GCRYCTL_GET_ASNOID: { + size_t asnlen; + const char *asn = md_asn_oid( algo, &asnlen, NULL ); + if( buffer && *nbytes >= asnlen ) { + memcpy( buffer, asn, asnlen ); + *nbytes = asnlen; + return 0; + } + if( !buffer && nbytes ) { + *nbytes = asnlen; + return 0; + } + set_lasterr( buffer ? GCRYERR_TOO_SHORT : GCRYERR_INV_ARG ); + return -1; + } + break; + + default: + set_lasterr( GCRYERR_INV_OP ); + return -1; + } + return 0; +} + + + + void -md_start_debug( MD_HANDLE md, const char *suffix ) +md_start_debug( GCRY_MD_HD md, const char *suffix ) { static int idx=0; char buf[25]; - if( md->debug ) { + if( md->ctx->debug ) { log_debug("Oops: md debug already started\n"); return; } idx++; sprintf(buf, "dbgmd-%05d.%.10s", idx, suffix ); - md->debug = fopen(buf, "w"); - if( !md->debug ) + md->ctx->debug = fopen(buf, "w"); + if( !md->ctx->debug ) log_debug("md debug: can't open %s\n", buf ); } void -md_stop_debug( MD_HANDLE md ) +md_stop_debug( GCRY_MD_HD md ) { - if( md->debug ) { - if( md->bufcount ) + if( md->ctx->debug ) { + if( md->bufpos ) md_write( md, NULL, 0 ); - fclose(md->debug); - md->debug = NULL; + fclose(md->ctx->debug); + md->ctx->debug = NULL; } #ifdef HAVE_U64_TYPEDEF { /* a kludge to pull in the __muldi3 for Solaris */ @@ -521,3 +763,25 @@ md_stop_debug( MD_HANDLE md ) #endif } + + +/**************** + * Return information about the digest handle. + * GCRYCTL_IS_SECURE: + * Returns 1 when the handle works on secured memory + * otherwise 0 is returned. There is no error return. + */ +int +gcry_md_info( GCRY_MD_HD h, int cmd, void *buffer, size_t *nbytes) +{ + switch( cmd ) { + case GCRYCTL_IS_SECURE: + return h->ctx->secure; + + default: + set_lasterr( GCRYERR_INV_OP ); + return -1; + } + return 0; +} + diff --git a/cipher/pubkey.c b/cipher/pubkey.c index a03af3026..4561f2ffa 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -1,5 +1,5 @@ /* pubkey.c - pubkey dispatcher - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -24,6 +24,8 @@ #include <string.h> #include <errno.h> #include <assert.h> + +#include "g10lib.h" #include "util.h" #include "errors.h" #include "mpi.h" @@ -236,7 +238,7 @@ load_pubkey_modules(void) * Map a string to the pubkey algo */ int -string_to_pubkey_algo( const char *string ) +gcry_pk_map_name( const char *string ) { int i; const char *s; @@ -254,7 +256,7 @@ string_to_pubkey_algo( const char *string ) * Map a pubkey algo to a string */ const char * -pubkey_algo_to_string( int algo ) +gcry_pk_algo_name( int algo ) { int i; @@ -565,3 +567,78 @@ pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey, return rc; } + +int +gcry_pk_encrypt( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP pkey ) +{ + /* ... */ + return 0; +} + +int +gcry_pk_decrypt( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP skey ) +{ + /* ... */ + return 0; +} + +int +gcry_pk_sign( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP skey ) +{ + GCRY_SEXP s; + /* get the secret key */ + s = NULL; /*gcry_sexp_find_token( skey, "private-key", 0 );*/ + if( !s ) + return -1; /* no private key */ + /* ... */ + return 0; +} + +int +gcry_pk_verify( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP pkey ) +{ + /* ... */ + return 0; +} + + + + +/**************** + * Return information about the given algorithm + * WHAT select the kind of information returned: + * GCRYCTL_TEST_ALGO: + * Returns 0 when the specified algorithm is available for use. + * buffer and nbytes must be zero. + * + * On error the value -1 is returned and the error reason may be + * retrieved by gcry_errno(). + * Note: Because this function is in most caes used to return an + * integer value, we can make it easier for the caller to just look at + * the return value. The caller will in all cases consult the value + * and thereby detecting whether a error occured or not (i.e. while checking + * the block size) + */ +int +gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes) +{ + switch( what ) { + case GCRYCTL_TEST_ALGO: + if( buffer || nbytes ) { + set_lasterr( GCRYERR_INV_ARG ); + return -1; + } + if( check_pubkey_algo( algo ) ) { + set_lasterr( GCRYERR_INV_ALGO ); + return -1; + } + break; + + default: + set_lasterr( GCRYERR_INV_OP ); + return -1; + } + return 0; +} + + |