diff --git a/g10/ChangeLog b/g10/ChangeLog index 3918b528c..b1c3488b0 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,17 @@ +2003-11-12 David Shaw + + * g10.c (main): Add --symmetric --sign --encrypt. + + * main.h, encode.c (setup_symkey): New. Prompt for a passphrase + and create a DEK for symmetric encryption. + (write_symkey_enc): New. Write out symmetrically encrypted + session keys. + (encode_crypt, encrypt_filter): Use them here here when creating a + message that can be decrypted with a passphrase or a pk. + + * sign.c (sign_file): Call setup_symkey if we are doing a + --symmetric --sign --encrypt. + 2003-11-09 David Shaw * mainproc.c (proc_symkey_enc): Don't show algorithm information diff --git a/g10/encode.c b/g10/encode.c index dfde96234..b291ecefd 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -371,6 +371,53 @@ encode_simple( const char *filename, int mode, int use_seskey ) return rc; } +int +setup_symkey(STRING2KEY **symkey_s2k,DEK **symkey_dek) +{ + *symkey_s2k=m_alloc_clear(sizeof(STRING2KEY)); + (*symkey_s2k)->mode = opt.s2k_mode; + (*symkey_s2k)->hash_algo = opt.s2k_digest_algo; + + *symkey_dek=passphrase_to_dek(NULL,0,opt.s2k_cipher_algo, + *symkey_s2k,2,NULL,NULL); + if(!*symkey_dek || !(*symkey_dek)->keylen) + { + m_free(*symkey_dek); + m_free(*symkey_s2k); + return G10ERR_PASSPHRASE; + } + + return 0; +} + +static int +write_symkey_enc(STRING2KEY *symkey_s2k,DEK *symkey_dek,DEK *dek,IOBUF out) +{ + int rc,seskeylen=cipher_get_keylen(dek->algo)/8; + + PKT_symkey_enc *enc; + byte enckey[33]; + PACKET pkt; + + enc=m_alloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1); + encode_seskey(symkey_dek,&dek,enckey); + + enc->version = 4; + enc->cipher_algo = opt.s2k_cipher_algo; + enc->s2k = *symkey_s2k; + enc->seskeylen = seskeylen + 1; /* algo id */ + memcpy( enc->seskey, enckey, seskeylen + 1 ); + + pkt.pkttype = PKT_SYMKEY_ENC; + pkt.pkt.symkey_enc = enc; + + if((rc=build_packet(out,&pkt))) + log_error("build symkey_enc packet failed: %s\n",g10_errstr(rc)); + + m_free(enc); + return rc; +} + /**************** * Encrypt the file with the given userids (or ask if none * is supplied). @@ -399,25 +446,13 @@ encode_crypt( const char *filename, STRLIST remusr, int use_symkey ) memset( &tfx, 0, sizeof tfx); init_packet(&pkt); + if(use_symkey + && (rc=setup_symkey(&symkey_s2k,&symkey_dek))) + return rc; + if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) ) return rc; - if(use_symkey) - { - symkey_s2k=m_alloc_clear(sizeof(STRING2KEY)); - symkey_s2k->mode = opt.s2k_mode; - symkey_s2k->hash_algo = opt.s2k_digest_algo; - - symkey_dek=passphrase_to_dek(NULL,0,opt.s2k_cipher_algo, - symkey_s2k,2,NULL,NULL); - if(!symkey_dek || !symkey_dek->keylen) - { - m_free(symkey_dek); - m_free(symkey_s2k); - return G10ERR_PASSPHRASE; - } - } - if(PGP2) { for(work_list=pk_list; work_list; work_list=work_list->next) if(!(is_RSA(work_list->pk->pubkey_algo) && @@ -524,32 +559,8 @@ encode_crypt( const char *filename, STRLIST remusr, int use_symkey ) seems to be the most useful on the recipient side - there is no point in prompting a user for a passphrase if they have the secret key needed to decrypt. */ - if(use_symkey) - { - int seskeylen=cipher_get_keylen(cfx.dek->algo)/8; - PKT_symkey_enc *enc; - byte enckey[33]; - - enc=m_alloc_clear(sizeof(PKT_symkey_enc)+seskeylen+1); - encode_seskey(symkey_dek,&cfx.dek,enckey); - - enc->version = 4; - enc->cipher_algo = opt.s2k_cipher_algo; - enc->s2k = *symkey_s2k; - enc->seskeylen = seskeylen + 1; /* algo id */ - memcpy( enc->seskey, enckey, seskeylen + 1 ); - - pkt.pkttype = PKT_SYMKEY_ENC; - pkt.pkt.symkey_enc = enc; - if( (rc = build_packet( out, &pkt )) ) - { - log_error("build symkey packet failed: %s\n", g10_errstr(rc) ); - m_free(enc); - goto leave; - } - - m_free(enc); - } + if(use_symkey && (rc=write_symkey_enc(symkey_s2k,symkey_dek,cfx.dek,out))) + goto leave; if (!opt.no_literal) { /* setup the inner packet */ @@ -723,6 +734,14 @@ encrypt_filter( void *opaque, int control, if( rc ) return rc; + if(efx->symkey_s2k && efx->symkey_dek) + { + rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek, + efx->cfx.dek,a); + if(rc) + return rc; + } + iobuf_push_filter( a, cipher_filter, &efx->cfx ); efx->header_okay = 1; @@ -730,8 +749,11 @@ encrypt_filter( void *opaque, int control, rc = iobuf_write( a, buf, size ); } - else if( control == IOBUFCTRL_FREE ) { - } + else if( control == IOBUFCTRL_FREE ) + { + m_free(efx->symkey_dek); + m_free(efx->symkey_s2k); + } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "encrypt_filter"; } diff --git a/g10/g10.c b/g10/g10.c index eeb9101b9..b38a728e4 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -87,6 +87,7 @@ enum cmd_and_opt_values aStore, aKeygen, aSignEncr, + aSignEncrSym, aSignSym, aSignKey, aLSignKey, @@ -879,6 +880,12 @@ set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ) cmd = aEncrSym; else if( cmd == aKMode && new_cmd == aSym ) cmd = aKModeC; + else if (cmd == aSignEncr && new_cmd == aSym) + cmd = aSignEncrSym; + else if (cmd == aSignSym && new_cmd == aEncr) + cmd = aSignEncrSym; + else if (cmd == aEncrSym && new_cmd == aSign) + cmd = aSignEncrSym; else if( ( cmd == aSign && new_cmd == aClearsign ) || ( cmd == aClearsign && new_cmd == aSign ) ) cmd = aClearsign; @@ -2543,10 +2550,36 @@ main( int argc, char **argv ) else sl = NULL; if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) ) - log_error("%s: sign+encrypt failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); + log_error("%s: sign+encrypt failed: %s\n", + print_fname_stdin(fname), g10_errstr(rc) ); free_strlist(sl); break; + case aSignEncrSym: /* sign and encrypt the given file */ + if( argc > 1 ) + wrong_args(_("--symmetric --sign --encrypt [filename]")); + else if(opt.s2k_mode==0) + log_error(_("you cannot use --symmetric --sign --encrypt" + " with --s2k-mode 0\n")); + else if(PGP2 || PGP6 || PGP7 || RFC1991) + log_error(_("you cannot use --symmetric --sign --encrypt" + " while in %s mode\n"),compliance_option_string()); + else + { + if( argc ) + { + sl = m_alloc_clear( sizeof *sl + strlen(fname)); + strcpy(sl->d, fname); + } + else + sl = NULL; + if( (rc = sign_file(sl, detached_sig, locusr, 2, remusr, NULL)) ) + log_error("%s: symmetric+sign+encrypt failed: %s\n", + print_fname_stdin(fname), g10_errstr(rc) ); + free_strlist(sl); + } + break; + case aSignSym: /* sign and conventionally encrypt the given file */ if (argc > 1) wrong_args(_("--sign --symmetric [filename]")); diff --git a/g10/main.h b/g10/main.h index 1288790db..8afde1104 100644 --- a/g10/main.h +++ b/g10/main.h @@ -1,5 +1,6 @@ /* main.h - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, + * 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -32,10 +33,13 @@ #define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1 #define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP -typedef struct { - int header_okay; - PK_LIST pk_list; - cipher_filter_context_t cfx; +typedef struct +{ + int header_okay; + PK_LIST pk_list; + DEK *symkey_dek; + STRING2KEY *symkey_s2k; + cipher_filter_context_t cfx; } encrypt_filter_context_t; struct groupitem @@ -110,6 +114,7 @@ int parse_options(char *str,unsigned int *options,struct parse_options *opts); void display_online_help( const char *keyword ); /*-- encode.c --*/ +int setup_symkey(STRING2KEY **symkey_s2k,DEK **symkey_dek); int encode_symmetric( const char *filename ); int encode_store( const char *filename ); int encode_crypt( const char *filename, STRLIST remusr, int use_symkey ); diff --git a/g10/sign.c b/g10/sign.c index b24e68f89..e595ce9b1 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -723,6 +723,10 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, if( fname && filenames->next && (!detached || encryptflag) ) log_bug("multiple files can only be detached signed"); + if(encryptflag==2 + && (rc=setup_symkey(&efx.symkey_s2k,&efx.symkey_dek))) + goto leave; + if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !RFC1991) duration=ask_expire_interval(1);