diff --git a/g10/ChangeLog b/g10/ChangeLog index 6fd61f373..708bd1211 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,22 @@ +2002-08-13 David Shaw + + * encode.c (encode_simple): Fix problem with using compression + algo 2 and symmetric compressed files. + + * encode.c (encode_simple, encode_crypt): If we are not using a + MDC, compress even if a file is already compressed. This is to + help against the chosen ciphertext attack. + + * pkclist.c (select_algo_from_prefs): Fix requested algorithm bug + so the request succeeds even if the requested algorithm is not the + first found. + + * cipher.c (write_header), encode.c (use_mdc, encode_simple, + encode_crypt, encrypt_filter), g10.c (main): Be more eager to use + a MDC. We use a MDC if the keys directly support it, if the keys + list AES (any) or TWOFISH anywhere in the prefs, or if the cipher + chosen does not have a 64 bit blocksize. + 2002-08-08 David Shaw * options.skel: Some language tweaks, and remove the diff --git a/g10/cipher.c b/g10/cipher.c index 2af8750c8..cb9f14916 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -47,31 +47,16 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) byte temp[18]; unsigned blocksize; unsigned nprefix; - int use_mdc; blocksize = cipher_get_blocksize( cfx->dek->algo ); if( blocksize < 8 || blocksize > 16 ) log_fatal("unsupported blocksize %u\n", blocksize ); - use_mdc = cfx->dek->use_mdc; - - if( blocksize != 8 ) - use_mdc = 1; /* Hack: enable it for all modern ciphers */ - /* Note: We should remove this hack as soon as a reasonable number of keys - are carrying the MDC flag. But always keep the hack for conventional - encryption */ - - if (opt.force_mdc) - use_mdc = 1; - - if( opt.rfc2440 || opt.rfc1991 || opt.disable_mdc ) - use_mdc = 0; /* override - rfc2440 does not know about MDC */ - memset( &ed, 0, sizeof ed ); ed.len = cfx->datalen; ed.extralen = blocksize+2; ed.new_ctb = !ed.len && !opt.rfc1991; - if( use_mdc ) { + if( cfx->dek->use_mdc ) { ed.mdc_method = DIGEST_ALGO_SHA1; cfx->mdc_hash = md_open( DIGEST_ALGO_SHA1, 0 ); if ( DBG_HASHING ) @@ -86,7 +71,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) } init_packet( &pkt ); - pkt.pkttype = use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; + pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; pkt.pkt.encrypted = &ed; if( build_packet( a, &pkt )) log_bug("build_packet(ENCR_DATA) failed\n"); @@ -96,7 +81,7 @@ write_header( cipher_filter_context_t *cfx, IOBUF a ) temp[nprefix+1] = temp[nprefix-1]; print_cipher_algo_note( cfx->dek->algo ); cfx->cipher_hd = cipher_open( cfx->dek->algo, - use_mdc? CIPHER_MODE_CFB + cfx->dek->use_mdc? CIPHER_MODE_CFB : CIPHER_MODE_AUTO_CFB, 1 ); /* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/ cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen ); diff --git a/g10/encode.c b/g10/encode.c index 87289cf77..417685f12 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -102,6 +102,52 @@ encode_sesskey( DEK *dek, DEK **ret_dek, byte *enckey ) *ret_dek = c; } +/* We try very hard to use a MDC */ +static int +use_mdc(PK_LIST pk_list,int algo) +{ + /* --force-mdc overrides --disable-mdc */ + if(opt.force_mdc) + return 1; + + if(opt.disable_mdc) + return 0; + + /* Do the keys really support MDC? */ + + if(select_mdc_from_pklist(pk_list)) + return 1; + + /* The keys don't support MDC, so now we do a bit of a hack - if any + of the AESes or TWOFISH are in the prefs, we assume that the user + can handle a MDC. This is valid for PGP 7, which can handle MDCs + though it will not generate them. 2440bis allows this, by the + way. */ + + if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, + CIPHER_ALGO_AES,NULL)==CIPHER_ALGO_AES) + return 1; + + if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, + CIPHER_ALGO_AES192,NULL)==CIPHER_ALGO_AES192) + return 1; + + if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, + CIPHER_ALGO_AES256,NULL)==CIPHER_ALGO_AES256) + return 1; + + if(select_algo_from_prefs(pk_list,PREFTYPE_SYM, + CIPHER_ALGO_TWOFISH,NULL)==CIPHER_ALGO_TWOFISH) + return 1; + + /* Last try. Use MDC for the modern ciphers. */ + + if(cipher_get_blocksize(algo)!=8) + return 1; + + return 0; /* No MDC */ +} + static int encode_simple( const char *filename, int mode, int compat ) { @@ -126,15 +172,6 @@ encode_simple( const char *filename, int mode, int compat ) memset( &tfx, 0, sizeof tfx); init_packet(&pkt); - if (opt.compress == -1 && is_file_compressed(filename, &rc)) - { - if (opt.verbose) - log_info(_("`%s' already compressed\n"), filename); - do_compress = 0; - } - if (rc) - return rc; - /* prepare iobufs */ if( !(inp = iobuf_open(filename)) ) { log_error(_("%s: can't open: %s\n"), filename? filename: "[stdin]", @@ -175,9 +212,19 @@ encode_simple( const char *filename, int mode, int compat ) encode_sesskey( cfx.dek, &dek, enckey ); m_free( cfx.dek ); cfx.dek = dek; } + + cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo); } - if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) { + if (opt.compress == -1 && cfx.dek && cfx.dek->use_mdc && + is_file_compressed(filename, &rc)) + { + if (opt.verbose) + log_info(_("`%s' already compressed\n"), filename); + do_compress = 0; + } + + if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) { iobuf_cancel(inp); m_free(cfx.dek); m_free(s2k); @@ -271,7 +318,12 @@ encode_simple( const char *filename, int mode, int compat ) iobuf_push_filter( out, cipher_filter, &cfx ); /* register the compress filter */ if( do_compress ) + { + zfx.algo=opt.def_compress_algo; + if(zfx.algo==-1) + zfx.algo=DEFAULT_COMPRESS_ALGO; iobuf_push_filter( out, compress_filter, &zfx ); + } /* do the work */ if (!opt.no_literal) { @@ -351,18 +403,6 @@ encode_crypt( const char *filename, STRLIST remusr ) } } - if (opt.compress == -1 && is_file_compressed(filename, &rc2)) - { - if (opt.verbose) - log_info(_("`%s' already compressed\n"), filename); - do_compress = 0; - } - if (rc2) - { - rc = rc2; - goto leave; - } - /* prepare iobufs */ if( !(inp = iobuf_open(filename)) ) { log_error(_("can't open %s: %s\n"), filename? filename: "[stdin]", @@ -423,7 +463,26 @@ encode_crypt( const char *filename, STRLIST remusr ) cfx.dek->algo = opt.def_cipher_algo; } - cfx.dek->use_mdc = select_mdc_from_pklist (pk_list); + + cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo); + + /* Only do the is-file-already-compressed check if we are using a + MDC. This forces compressed files to be re-compressed if we do + not have a MDC to give some protection against chosen + ciphertext attacks. */ + + if (opt.compress == -1 && cfx.dek->use_mdc && + is_file_compressed(filename, &rc2) ) + { + if (opt.verbose) + log_info(_("`%s' already compressed\n"), filename); + do_compress = 0; + } + if (rc2) + { + rc = rc2; + goto leave; + } make_session_key( cfx.dek ); if( DBG_CIPHER ) @@ -578,7 +637,7 @@ encrypt_filter( void *opaque, int control, efx->cfx.dek->algo = opt.def_cipher_algo; } - efx->cfx.dek->use_mdc = select_mdc_from_pklist (efx->pk_list); + efx->cfx.dek->use_mdc = use_mdc(efx->pk_list,efx->cfx.dek->algo); make_session_key( efx->cfx.dek ); if( DBG_CIPHER ) diff --git a/g10/g10.c b/g10/g10.c index 545c5b8a2..70c609c21 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -1400,12 +1400,15 @@ main( int argc, char **argv ) opt.rfc1991 = 1; opt.rfc2440 = 0; opt.force_v4_certs = 0; - opt.sk_comments = 0; + opt.disable_mdc = 1; opt.escape_from = 1; break; case oOpenPGP: + /* TODO: When 2440bis becomes a RFC, these may need + changing. */ opt.rfc1991 = 0; opt.rfc2440 = 1; + opt.disable_mdc = 1; opt.allow_non_selfsigned_uid = 1; opt.allow_freeform_uid = 1; opt.pgp2_workarounds = 0; diff --git a/g10/pkclist.c b/g10/pkclist.c index 671b56879..cf6eca659 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -1159,6 +1159,11 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype, int request, void *hint) i = -1; any = 0; + /* Can we use the requested algorithm? */ + if(request>-1 && (bits[request/32] & (1<<(request%32))) && + algo_available(preftype,request,hint)) + return request; + /* If we have personal prefs set, use them instead of the last key */ if(preftype==PREFTYPE_SYM && opt.personal_cipher_prefs) prefs=opt.personal_cipher_prefs; @@ -1190,10 +1195,6 @@ select_algo_from_prefs(PK_LIST pk_list, int preftype, int request, void *hint) } } - /* Can we use the requested algorithm? */ - if(request>-1 && request==i) - return i; - #if 0 log_debug("prefs of type %d: selected %d\n", preftype, i ); #endif