* keydb.h, getkey.c (key_byname): Flag to enable or disable including
[gnupg.git] / g10 / encode.c
index 87289cf..e705a6f 100644 (file)
@@ -98,10 +98,56 @@ encode_sesskey( DEK *dek, DEK **ret_dek, byte *enckey )
     cipher_close( hd );
 
     memcpy( enckey, buf, c->keylen + 1 );
-    memset( buf, 0, sizeof buf ); /* burn key */
+    wipememory( buf, sizeof buf ); /* burn key */
     *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]",
@@ -155,11 +192,9 @@ encode_simple( const char *filename, int mode, int compat )
     if( mode ) {
        s2k = m_alloc_clear( sizeof *s2k );
        s2k->mode = opt.rfc1991? 0:opt.s2k_mode;
-       s2k->hash_algo = opt.def_digest_algo ? opt.def_digest_algo
-                                            : opt.s2k_digest_algo;
+       s2k->hash_algo = opt.s2k_digest_algo;
        cfx.dek = passphrase_to_dek( NULL, 0,
-                  opt.def_cipher_algo ? opt.def_cipher_algo
-                                     : opt.s2k_cipher_algo , s2k, 2, NULL );
+                                    default_cipher_algo(), s2k, 2, NULL );
        if( !cfx.dek || !cfx.dek->keylen ) {
            rc = G10ERR_PASSPHRASE;
            m_free(cfx.dek);
@@ -168,16 +203,30 @@ encode_simple( const char *filename, int mode, int compat )
            log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
            return rc;
        }
+        if (!compat && s2k->mode != 1 && s2k->mode != 3) {
+            compat = 1;
+            log_info (_("can't use a symmetric ESK packet "
+                        "due to the S2K mode\n"));
+        }
+
         if ( !compat ) {            
-            seskeylen = cipher_get_keylen( opt.def_cipher_algo ?
-                                           opt.def_cipher_algo:
-                                           opt.s2k_cipher_algo ) / 8;
+            seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
             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);
@@ -214,7 +263,8 @@ encode_simple( const char *filename, int mode, int compat )
        /* setup the inner packet */
        if( filename || opt.set_filename ) {
            char *s = make_basename( opt.set_filename ? opt.set_filename
-                                                     : filename );
+                                                     : filename,
+                                    iobuf_get_real_fname( inp ) );
            pt = m_alloc( sizeof *pt + strlen(s) - 1 );
            pt->namelen = strlen(s);
            memcpy(pt->name, s, pt->namelen );
@@ -238,13 +288,18 @@ encode_simple( const char *filename, int mode, int compat )
        messages. */
 
     if( filename && !opt.textmode ) {
-       if( !(filesize = iobuf_get_filelength(inp)) )
-           log_info(_("%s: WARNING: empty file\n"), filename );
-        /* we can't yet encode the length of very large files,
-         * so we switch to partial lengthn encoding in this case */
-        if ( filesize >= IOBUF_FILELENGTH_LIMIT )
-            filesize = 0;
-
+        off_t tmpsize;
+
+       if ( !(tmpsize = iobuf_get_filelength(inp)) )
+          log_info(_("%s: WARNING: empty file\n"), filename );
+        /* We can't encode the length of very large files because
+           OpenPGP uses only 32 bit for file sizes.  So if the the
+           size of a file is larger than 2^32 minus some bytes for
+           packet headers, we switch to partial length encoding. */
+        if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
+          filesize = tmpsize;
+        else
+          filesize = 0;
     }
     else
        filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
@@ -271,7 +326,12 @@ encode_simple( const char *filename, int mode, int compat )
        iobuf_push_filter( out, cipher_filter, &cfx );
     /* register the compress filter */
     if( do_compress )
+      {
+        if (cfx.dek && cfx.dek->use_mdc)
+          zfx.new_ctb = 1;
+       zfx.algo=default_compress_algo();
        iobuf_push_filter( out, compress_filter, &zfx );
+      }
 
     /* do the work */
     if (!opt.no_literal) {
@@ -289,7 +349,7 @@ encode_simple( const char *filename, int mode, int compat )
                log_error("copying input to output failed: %s\n", g10_errstr(rc) );
                break;
            }
-       memset(copy_buffer, 0, 4096); /* burn buffer */
+       wipememory(copy_buffer, 4096); /* burn buffer */
     }
 
     /* finish the stuff */
@@ -351,18 +411,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 +471,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 )
@@ -436,7 +503,9 @@ encode_crypt( const char *filename, STRLIST remusr )
     if (!opt.no_literal) {
        /* setup the inner packet */
        if( filename || opt.set_filename ) {
-           char *s = make_basename( opt.set_filename ? opt.set_filename : filename );
+           char *s = make_basename( opt.set_filename ? opt.set_filename
+                                                     : filename,
+                                    iobuf_get_real_fname( inp ) );
            pt = m_alloc( sizeof *pt + strlen(s) - 1 );
            pt->namelen = strlen(s);
            memcpy(pt->name, s, pt->namelen );
@@ -449,12 +518,18 @@ encode_crypt( const char *filename, STRLIST remusr )
     }
 
     if( filename && !opt.textmode ) {
-       if( !(filesize = iobuf_get_filelength(inp)) )
-           log_info(_("%s: WARNING: empty file\n"), filename );
-        /* we can't yet encode the length of very large files,
-         * so we switch to partial length encoding in this case */
-        if ( filesize >= IOBUF_FILELENGTH_LIMIT )
-            filesize = 0;
+        off_t tmpsize;
+
+       if ( !(tmpsize = iobuf_get_filelength(inp)) )
+          log_info(_("%s: WARNING: empty file\n"), filename );
+        /* We can't encode the length of very large files because
+           OpenPGP uses only 32 bit for file sizes.  So if the the
+           size of a file is larger than 2^32 minus some bytes for
+           packet headers, we switch to partial length encoding. */
+        if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
+          filesize = tmpsize;
+        else
+          filesize = 0;
     }
     else
        filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
@@ -484,6 +559,8 @@ encode_crypt( const char *filename, STRLIST remusr )
            if((compr_algo=
                select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
              compr_algo=DEFAULT_COMPRESS_ALGO;
+           /* Theoretically impossible to get here since uncompressed
+              is implicit. */
          }
        else if(!opt.expert &&
                select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
@@ -495,6 +572,8 @@ encode_crypt( const char *filename, STRLIST remusr )
        /* algo 0 means no compression */
        if( compr_algo )
          {
+            if (cfx.dek && cfx.dek->use_mdc)
+              zfx.new_ctb = 1;
            zfx.algo = compr_algo;
            iobuf_push_filter( out, compress_filter, &zfx );
          }
@@ -506,16 +585,18 @@ encode_crypt( const char *filename, STRLIST remusr )
            log_error("build_packet failed: %s\n", g10_errstr(rc) );
     }
     else {
-       /* user requested not to create a literal packet, so we copy the plain data */
+       /* user requested not to create a literal packet, so we copy
+           the plain data */
        byte copy_buffer[4096];
        int  bytes_copied;
        while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
            if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
                rc = G10ERR_WRITE_FILE;
-               log_error("copying input to output failed: %s\n", g10_errstr(rc) );
+               log_error("copying input to output failed: %s\n",
+                          g10_errstr(rc) );
                break;
            }
-       memset(copy_buffer, 0, 4096); /* burn buffer */
+       wipememory(copy_buffer, 4096); /* burn buffer */
     }
 
     /* finish the stuff */
@@ -578,7 +659,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 )
@@ -625,18 +706,18 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
        enc = m_alloc_clear( sizeof *enc );
        enc->pubkey_algo = pk->pubkey_algo;
        keyid_from_pk( pk, enc->keyid );
-       enc->throw_keyid = opt.throw_keyid;
+       enc->throw_keyid = (opt.throw_keyid || (pk_list->flags&1));
 
-       if(opt.throw_keyid && (opt.pgp2 || opt.pgp6 || opt.pgp7))
+       if(opt.throw_keyid && (opt.pgp2 || opt.pgp6 || opt.pgp7 || opt.pgp8))
          {
            log_info(_("you may not use %s while in %s mode\n"),
                     "--throw-keyid",
-                    opt.pgp2?"--pgp2":opt.pgp6?"--pgp6":"--pgp7");
+                    opt.pgp2?"--pgp2":opt.pgp6?"--pgp6":opt.pgp7?"--pgp7":"--pgp8");
 
            log_info(_("this message may not be usable by %s\n"),
-                    opt.pgp2?"PGP 2.x":opt.pgp6?"PGP 6.x":"PGP 7.x");
+                    opt.pgp2?"PGP 2.x":opt.pgp6?"PGP 6.x":opt.pgp7?"PGP 7.x":"PGP 8.x");
 
-           opt.pgp2=opt.pgp6=opt.pgp7=0;
+           opt.pgp2=opt.pgp6=opt.pgp7=opt.pgp8=0;
          }
 
        /* Okay, what's going on: We have the session key somewhere in
@@ -660,8 +741,8 @@ write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
            log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
        else {
            if( opt.verbose ) {
-               char *ustr = get_user_id_string_native( enc->keyid );
-               log_info(_("%s/%s encrypted for: %s\n"),
+               char *ustr = get_user_id_string_printable (enc->keyid);
+               log_info(_("%s/%s encrypted for: \"%s\"\n"),
                    pubkey_algo_to_string(enc->pubkey_algo),
                    cipher_algo_to_string(dek->algo), ustr );
                m_free(ustr);