diff options
Diffstat (limited to 'g10/encr-data.c')
-rw-r--r-- | g10/encr-data.c | 411 |
1 files changed, 227 insertions, 184 deletions
diff --git a/g10/encr-data.c b/g10/encr-data.c index cf2e43da7..c56e01706 100644 --- a/g10/encr-data.c +++ b/g10/encr-data.c @@ -34,16 +34,16 @@ #include "i18n.h" -static int mdc_decode_filter( void *opaque, int control, IOBUF a, - byte *buf, size_t *ret_len); -static int decode_filter( void *opaque, int control, IOBUF a, +static int mdc_decode_filter ( void *opaque, int control, IOBUF a, + byte *buf, size_t *ret_len); +static int decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); typedef struct { gcry_cipher_hd_t cipher_hd; gcry_md_hd_t mdc_hash; - char defer[20]; + char defer[22]; int defer_filled; int eof_seen; } decode_filter_ctx_t; @@ -55,228 +55,271 @@ typedef struct int decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) { - decode_filter_ctx_t dfx; - byte *p; - int rc=0, c, i; - byte temp[32]; - unsigned blocksize; - unsigned nprefix; + decode_filter_ctx_t dfx; + byte *p; + int rc=0, c, i; + byte temp[32]; + unsigned blocksize; + unsigned nprefix; + + memset( &dfx, 0, sizeof dfx ); + if ( opt.verbose && !dek->algo_info_printed ) + { + const char *s = gcry_cipher_algo_name (dek->algo); + if (s && *s) + log_info(_("%s encrypted data\n"), s ); + else + log_info(_("encrypted with unknown algorithm %d\n"), dek->algo ); + dek->algo_info_printed = 1; + } + rc = openpgp_cipher_test_algo (dek->algo); + if (rc) + goto leave; + blocksize = gcry_cipher_get_algo_blklen (dek->algo); + if ( !blocksize || blocksize > 16 ) + log_fatal("unsupported blocksize %u\n", blocksize ); + nprefix = blocksize; + if ( ed->len && ed->len < (nprefix+2) ) + BUG(); - memset( &dfx, 0, sizeof dfx ); - if( opt.verbose && !dek->algo_info_printed ) { - const char *s = gcry_cipher_algo_name (dek->algo); - if (s && *s) - log_info(_("%s encrypted data\n"), s ); - else - log_info(_("encrypted with unknown algorithm %d\n"), dek->algo ); - dek->algo_info_printed = 1; + if ( ed->mdc_method ) + { + if (gcry_md_open (&dfx.mdc_hash, ed->mdc_method, 0 )) + BUG (); + if ( DBG_HASHING ) + gcry_md_start_debug (dfx.mdc_hash, "checkmdc"); } - rc = openpgp_cipher_test_algo (dek->algo); - if (rc) - goto leave; - blocksize = gcry_cipher_get_algo_blklen (dek->algo); - if( !blocksize || blocksize > 16 ) - log_fatal("unsupported blocksize %u\n", blocksize ); - nprefix = blocksize; - if( ed->len && ed->len < (nprefix+2) ) - BUG(); - if( ed->mdc_method ) { - if (gcry_md_open (&dfx.mdc_hash, ed->mdc_method, 0 )) - BUG (); - if ( DBG_HASHING ) - gcry_md_start_debug (dfx.mdc_hash, "checkmdc"); + rc = gcry_cipher_open (&dfx.cipher_hd, dek->algo, + GCRY_CIPHER_MODE_CFB, + (GCRY_CIPHER_SECURE + | ((ed->mdc_method || dek->algo >= 100)? + 0 : GCRY_CIPHER_ENABLE_SYNC))); + if (rc) + { + /* We should never get an error here cause we already checked + * that the algorithm is available. */ + BUG(); } - rc = gcry_cipher_open (&dfx.cipher_hd, dek->algo, - GCRY_CIPHER_MODE_CFB, - (GCRY_CIPHER_SECURE - | ((ed->mdc_method || dek->algo >= 100)? - 0 : GCRY_CIPHER_ENABLE_SYNC))); - if (rc) - { - /* We should never get an error here cause we already checked - * that the algorithm is available. */ - BUG(); - } + /* log_hexdump( "thekey", dek->key, dek->keylen );*/ + rc = gcry_cipher_setkey (dfx.cipher_hd, dek->key, dek->keylen); + if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) + { + log_info(_("WARNING: message was encrypted with" + " a weak key in the symmetric cipher.\n")); + rc=0; + } + else if( rc ) + { + log_error("key setup failed: %s\n", g10_errstr(rc) ); + goto leave; + } - /* log_hexdump( "thekey", dek->key, dek->keylen );*/ - rc = gcry_cipher_setkey (dfx.cipher_hd, dek->key, dek->keylen); - if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) - { - log_info(_("WARNING: message was encrypted with" - " a weak key in the symmetric cipher.\n")); - rc=0; - } - else if( rc ) - { - log_error("key setup failed: %s\n", g10_errstr(rc) ); - goto leave; - - } - if (!ed->buf) { - log_error(_("problem handling encrypted packet\n")); - goto leave; + if (!ed->buf) + { + log_error(_("problem handling encrypted packet\n")); + goto leave; } - gcry_cipher_setiv (dfx.cipher_hd, NULL, 0); + gcry_cipher_setiv (dfx.cipher_hd, NULL, 0); - if( ed->len ) { - for(i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) { - if( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; - } + if ( ed->len ) + { + for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) + { + if ( (c=iobuf_get(ed->buf)) == -1 ) + break; + else + temp[i] = c; + } } - else { - for(i=0; i < (nprefix+2); i++ ) - if( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; + else + { + for (i=0; i < (nprefix+2); i++ ) + if ( (c=iobuf_get(ed->buf)) == -1 ) + break; + else + temp[i] = c; } + + gcry_cipher_decrypt (dfx.cipher_hd, temp, nprefix+2, NULL, 0); + gcry_cipher_sync (dfx.cipher_hd); + p = temp; + /* log_hexdump( "prefix", temp, nprefix+2 ); */ + if (dek->symmetric + && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) + { + rc = gpg_error (GPG_ERR_BAD_KEY); + goto leave; + } + + if ( dfx.mdc_hash ) + gcry_md_write (dfx.mdc_hash, temp, nprefix+2); + + if ( ed->mdc_method ) + iobuf_push_filter( ed->buf, mdc_decode_filter, &dfx ); + else + iobuf_push_filter( ed->buf, decode_filter, &dfx ); - gcry_cipher_decrypt (dfx.cipher_hd, temp, nprefix+2, NULL, 0); - gcry_cipher_sync (dfx.cipher_hd); - p = temp; -/* log_hexdump( "prefix", temp, nprefix+2 ); */ - if(dek->symmetric - && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) - { - rc = GPG_ERR_BAD_KEY; - goto leave; - } - - if( dfx.mdc_hash ) - gcry_md_write (dfx.mdc_hash, temp, nprefix+2); - - if( ed->mdc_method ) - iobuf_push_filter( ed->buf, mdc_decode_filter, &dfx ); - else - iobuf_push_filter( ed->buf, decode_filter, &dfx ); + proc_packets ( procctx, ed->buf ); + ed->buf = NULL; + if ( ed->mdc_method && dfx.eof_seen == 2 ) + rc = gpg_error (GPG_ERR_INV_PACKET); + else if ( ed->mdc_method ) + { + /* We used to let parse-packet.c handle the MDC packet but this + turned out to be a problem with compressed packets: With old + style packets there is no length information available and + the decompressor uses an implicit end. However we can't know + this implicit end beforehand (:-) and thus may feed the + decompressor with more bytes than actually needed. It would + be possible to unread the extra bytes but due to our weird + iobuf system any unread is non reliable due to filters + already popped off. The easy and sane solution is to care + about the MDC packet only here and never pass it to the + packet parser. Fortunatley the OpenPGP spec requires a + strict format for the MDC packet so that we know that 22 + bytes are appended. */ + int datalen = gcry_md_get_algo_dlen (ed->mdc_method); - proc_packets( procctx, ed->buf ); - ed->buf = NULL; - if( ed->mdc_method && dfx.eof_seen == 2 ) - rc = gpg_error (GPG_ERR_INV_PACKET); - else if( ed->mdc_method ) { /* check the mdc */ - int datalen = gcry_md_get_algo_dlen (ed->mdc_method); + gcry_cipher_decrypt (dfx.cipher_hd, dfx.defer, 22, NULL, 0); + gcry_md_write (dfx.mdc_hash, dfx.defer, 2); + gcry_md_final (dfx.mdc_hash); - gcry_cipher_decrypt (dfx.cipher_hd, dfx.defer, 20, NULL, 0); - gcry_md_final (dfx.mdc_hash); - if (datalen != 20 - || memcmp (gcry_md_read( dfx.mdc_hash, 0 ), dfx.defer, datalen) ) - rc = gpg_error (GPG_ERR_BAD_SIGNATURE); - /*log_hexdump("MDC calculated:", md_read( dfx.mdc_hash, 0), datalen);*/ - /*log_hexdump("MDC message :", dfx.defer, 20);*/ + if (dfx.defer[0] != '\xd3' || dfx.defer[1] != '\x14' ) + { + log_error("mdc_packet with invalid encoding\n"); + rc = gpg_error (GPG_ERR_INV_PACKET); + } + else if (datalen != 20 + || memcmp (gcry_md_read (dfx.mdc_hash, 0),dfx.defer+2,datalen)) + rc = gpg_error (GPG_ERR_BAD_SIGNATURE); + /* log_printhex("MDC message:", dfx.defer, 22); */ + /* log_printhex("MDC calc:", gcry_md_read (dfx.mdc_hash,0), datalen); */ } - - - leave: - gcry_cipher_close (dfx.cipher_hd); - gcry_md_close (dfx.mdc_hash); - return rc; + + + leave: + gcry_cipher_close (dfx.cipher_hd); + gcry_md_close (dfx.mdc_hash); + return rc; } /* I think we should merge this with cipher_filter */ static int -mdc_decode_filter( void *opaque, int control, IOBUF a, - byte *buf, size_t *ret_len) +mdc_decode_filter (void *opaque, int control, IOBUF a, + byte *buf, size_t *ret_len) { - decode_filter_ctx_t *dfx = opaque; - size_t n, size = *ret_len; - int rc = 0; - int c; - - if( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) { - *ret_len = 0; - rc = -1; + decode_filter_ctx_t *dfx = opaque; + size_t n, size = *ret_len; + int rc = 0; + int c; + + if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) + { + *ret_len = 0; + rc = -1; } - else if( control == IOBUFCTRL_UNDERFLOW ) { - assert(a); - assert( size > 40 ); - - /* get at least 20 bytes and put it somewhere ahead in the buffer */ - for(n=20; n < 40 ; n++ ) { - if( (c = iobuf_get(a)) == -1 ) - break; - buf[n] = c; + else if( control == IOBUFCTRL_UNDERFLOW ) + { + assert(a); + assert( size > 44 ); + + /* Get at least 22 bytes and put it somewhere ahead in the buffer. */ + for(n=22; n < 44 ; n++ ) + { + if( (c = iobuf_get(a)) == -1 ) + break; + buf[n] = c; } - if( n == 40 ) { - /* we have enough stuff - flush the deferred stuff */ - /* (we have asserted that the buffer is large enough) */ - if( !dfx->defer_filled ) { /* the first time */ - memcpy(buf, buf+20, 20 ); - n = 20; + if ( n == 44 ) + { + /* We have enough stuff - flush the deferred stuff. */ + /* (we asserted that the buffer is large enough) */ + if ( !dfx->defer_filled ) /* First time. */ + { + memcpy (buf, buf+22, 22 ); + n = 22; } - else { - memcpy(buf, dfx->defer, 20 ); + else + { + memcpy (buf, dfx->defer, 22 ); } - /* now fill up */ - for(; n < size; n++ ) { - if( (c = iobuf_get(a)) == -1 ) - break; - buf[n] = c; + /* Now fill up. */ + for (; n < size; n++ ) + { + if ( (c = iobuf_get(a)) == -1 ) + break; + buf[n] = c; } - /* move the last 20 bytes back to the defer buffer */ - /* (okay, we are wasting 20 bytes of supplied buffer) */ - n -= 20; - memcpy( dfx->defer, buf+n, 20 ); - dfx->defer_filled = 1; + /* Move the last 22 bytes back to the defer buffer. */ + /* (right, we are wasting 22 bytes of the supplied buffer.) */ + n -= 22; + memcpy (dfx->defer, buf+n, 22 ); + dfx->defer_filled = 1; } - else if( !dfx->defer_filled ) { /* eof seen buf empty defer */ - /* this is bad because there is an incomplete hash */ - n -= 20; - memcpy(buf, buf+20, n ); - dfx->eof_seen = 2; /* eof with incomplete hash */ + else if ( !dfx->defer_filled ) /* EOF seen but empty defer buffer. */ + { + /* This is bad because it means an incomplete hash. */ + n -= 22; + memcpy (buf, buf+22, n ); + dfx->eof_seen = 2; /* EOF with incomplete hash. */ } - else { /* eof seen */ - memcpy(buf, dfx->defer, 20 ); - n -= 20; - memcpy( dfx->defer, buf+n, 20 ); - dfx->eof_seen = 1; /* normal eof */ + else /* EOF seen (i.e. read less than 22 bytes). */ + { + memcpy (buf, dfx->defer, 22 ); + n -= 22; + memcpy (dfx->defer, buf+n, 22 ); + dfx->eof_seen = 1; /* Normal EOF. */ } - if( n ) { - gcry_cipher_decrypt (dfx->cipher_hd, buf, n, NULL, 0); - gcry_md_write (dfx->mdc_hash, buf, n); + if ( n ) + { + gcry_cipher_decrypt (dfx->cipher_hd, buf, n, NULL, 0); + gcry_md_write (dfx->mdc_hash, buf, n); } - else { - assert( dfx->eof_seen ); - rc = -1; /* eof */ + else + { + assert ( dfx->eof_seen ); + rc = -1; /* eof */ } - *ret_len = n; + *ret_len = n; } - else if( control == IOBUFCTRL_DESC ) { - *(char**)buf = "mdc_decode_filter"; + else if ( control == IOBUFCTRL_DESC ) + { + *(char**)buf = "mdc_decode_filter"; } - return rc; + return rc; } + static int decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { - decode_filter_ctx_t *fc = opaque; - size_t n, size = *ret_len; - int rc = 0; - - if( control == IOBUFCTRL_UNDERFLOW ) { - assert(a); - n = iobuf_read( a, buf, size ); - if( n == -1 ) n = 0; - if( n ) - gcry_cipher_decrypt (fc->cipher_hd, buf, n, NULL, 0); - else - rc = -1; /* eof */ - *ret_len = n; + decode_filter_ctx_t *fc = opaque; + size_t n, size = *ret_len; + int rc = 0; + + if ( control == IOBUFCTRL_UNDERFLOW ) + { + assert(a); + n = iobuf_read ( a, buf, size ); + if ( n == -1 ) + n = 0; + if ( n ) + gcry_cipher_decrypt (fc->cipher_hd, buf, n, NULL, 0); + else + rc = -1; /* EOF */ + *ret_len = n; } - else if( control == IOBUFCTRL_DESC ) { - *(char**)buf = "decode_filter"; + else if ( control == IOBUFCTRL_DESC ) + { + *(char**)buf = "decode_filter"; } - return rc; + return rc; } |