diff --git a/common/iobuf.c b/common/iobuf.c index 161769a35..748e6935d 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -3028,3 +3028,123 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial) } } } + + +/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed + * packet. LEN should be at least 6. */ +static int +is_openpgp_compressed_packet (const unsigned char *buf, size_t len) +{ + int c, ctb, pkttype; + int lenbytes; + + ctb = *buf++; len--; + if (!(ctb & 0x80)) + return 0; /* Invalid packet. */ + + if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */ + { + pkttype = (ctb & 0x3f); + if (!len) + return 0; /* Expected first length octet missing. */ + c = *buf++; len--; + if (c < 192) + ; + else if (c < 224) + { + if (!len) + return 0; /* Expected second length octet missing. */ + } + else if (c == 255) + { + if (len < 4) + return 0; /* Expected length octets missing */ + } + } + else /* Old style CTB. */ + { + pkttype = (ctb>>2)&0xf; + lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3)); + if (len < lenbytes) + return 0; /* Not enough length bytes. */ + } + + return (pkttype == 8); +} + + +/* + * Check if the file is compressed, by peeking the iobuf. You need to + * pass the iobuf with INP. Returns true if the buffer seems to be + * compressed. + */ +int +is_file_compressed (iobuf_t inp) +{ + int i; + char buf[32]; + int buflen; + + struct magic_compress_s + { + byte len; + byte extchk; + byte magic[5]; + } magic[] = + { + { 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ + { 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ + { 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ + { 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */ + { 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */ + { 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */ + }; + + if (!inp) + return 0; + + for ( ; inp->chain; inp = inp->chain ) + ; + + buflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof buf, buf); + if (buflen < 0) + { + buflen = 0; + log_debug ("peeking at input failed\n"); + } + + if ( buflen < 6 ) + { + return 0; /* Too short to check - assume uncompressed. */ + } + + for ( i = 0; i < DIM (magic); i++ ) + { + if (!memcmp( buf, magic[i].magic, magic[i].len)) + { + switch (magic[i].extchk) + { + case 0: + return 1; /* Is compressed. */ + case 1: + if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5)) + return 1; /* JFIF: this likely a compressed JPEG. */ + break; + case 2: + if (buflen > 8 + && buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a) + return 1; /* This is a PNG. */ + break; + default: + break; + } + } + } + + if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen)) + { + return 1; /* Already compressed. */ + } + + return 0; /* Not detected as compressed. */ +} diff --git a/common/iobuf.h b/common/iobuf.h index 751ae73c3..04e6b4421 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -625,6 +625,9 @@ void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len); from the following filter (which may or may not return EOF). */ void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial); +/* Check if the file is compressed, by peeking the iobuf. */ +int is_file_compressed (iobuf_t inp); + #define iobuf_where(a) "[don't know]" /* Each time a filter is allocated (via iobuf_alloc()), a diff --git a/common/miscellaneous.c b/common/miscellaneous.c index f19cc539d..1a090b1f5 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -415,112 +415,6 @@ decode_c_string (const char *src) } -/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed - * packet. LEN should be at least 6. */ -static int -is_openpgp_compressed_packet (const unsigned char *buf, size_t len) -{ - int c, ctb, pkttype; - int lenbytes; - - ctb = *buf++; len--; - if (!(ctb & 0x80)) - return 0; /* Invalid packet. */ - - if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */ - { - pkttype = (ctb & 0x3f); - if (!len) - return 0; /* Expected first length octet missing. */ - c = *buf++; len--; - if (c < 192) - ; - else if (c < 224) - { - if (!len) - return 0; /* Expected second length octet missing. */ - } - else if (c == 255) - { - if (len < 4) - return 0; /* Expected length octets missing */ - } - } - else /* Old style CTB. */ - { - pkttype = (ctb>>2)&0xf; - lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3)); - if (len < lenbytes) - return 0; /* Not enough length bytes. */ - } - - return (pkttype == 8); -} - - - -/* - * Check if the file is compressed. You need to pass the first bytes - * of the file as (BUF,BUFLEN). Returns true if the buffer seems to - * be compressed. - */ -int -is_file_compressed (const byte *buf, unsigned int buflen) -{ - int i; - - struct magic_compress_s - { - byte len; - byte extchk; - byte magic[5]; - } magic[] = - { - { 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ - { 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ - { 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ - { 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */ - { 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */ - { 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */ - }; - - if ( buflen < 6 ) - { - return 0; /* Too short to check - assume uncompressed. */ - } - - for ( i = 0; i < DIM (magic); i++ ) - { - if (!memcmp( buf, magic[i].magic, magic[i].len)) - { - switch (magic[i].extchk) - { - case 0: - return 1; /* Is compressed. */ - case 1: - if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5)) - return 1; /* JFIF: this likely a compressed JPEG. */ - break; - case 2: - if (buflen > 8 - && buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a) - return 1; /* This is a PNG. */ - break; - default: - break; - } - } - } - - if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen)) - { - return 1; /* Already compressed. */ - } - - return 0; /* Not detected as compressed. */ -} - - /* Try match against each substring of multistr, delimited by | */ int match_multistr (const char *multistr,const char *match) diff --git a/common/util.h b/common/util.h index 875969187..fff2e6e83 100644 --- a/common/util.h +++ b/common/util.h @@ -367,8 +367,6 @@ char *try_make_printable_string (const void *p, size_t n, int delim); char *make_printable_string (const void *p, size_t n, int delim); char *decode_c_string (const char *src); -int is_file_compressed (const byte *buf, unsigned int buflen); - int match_multistr (const char *multistr,const char *match); int gnupg_compare_version (const char *a, const char *b); diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c index 640d8432f..0c07e65de 100644 --- a/g10/cipher-aead.c +++ b/g10/cipher-aead.c @@ -174,8 +174,6 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a) log_debug ("aead packet: len=%lu extralen=%d\n", (unsigned long)ed.len, ed.extralen); - write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d", - cfx->dek->algo, ed.aead_algo); print_cipher_algo_note (cfx->dek->algo); if (build_packet( a, &pkt)) @@ -488,6 +486,11 @@ cipher_filter_aead (void *opaque, int control, { mem2str (buf, "cipher_filter_aead", *ret_len); } + else if (control == IOBUFCTRL_INIT) + { + write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d", + cfx->dek->algo, cfx->dek->use_aead); + } return rc; } diff --git a/g10/cipher-cfb.c b/g10/cipher-cfb.c index 3ba8eb738..29bf2477c 100644 --- a/g10/cipher-cfb.c +++ b/g10/cipher-cfb.c @@ -72,9 +72,6 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a) log_info (_("Hint: Do not use option %s\n"), "--rfc2440"); } - write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d", - ed.mdc_method, cfx->dek->algo); - init_packet (&pkt); pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED; pkt.pkt.encrypted = &ed; @@ -182,6 +179,12 @@ cipher_filter_cfb (void *opaque, int control, { mem2str (buf, "cipher_filter_cfb", *ret_len); } + else if (control == IOBUFCTRL_INIT) + { + write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d", + cfx->dek->use_mdc ? DIGEST_ALGO_SHA1 : 0, + cfx->dek->algo); + } return rc; } diff --git a/g10/encrypt.c b/g10/encrypt.c index 9aeafa292..b335b9797 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -410,8 +410,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey) text_filter_context_t tfx; progress_filter_context_t *pfx; int do_compress = !!default_compress_algo(); - char peekbuf[32]; - int peekbuflen; if (!gnupg_rng_is_compliant (opt.compliance)) { @@ -448,14 +446,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey) return rc; } - peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf); - if (peekbuflen < 0) - { - peekbuflen = 0; - if (DBG_FILTER) - log_debug ("peeking at input failed\n"); - } - handle_progress (pfx, inp, filename); if (opt.textmode) @@ -517,17 +507,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey) /**/ : "CFB"); } - if (do_compress - && cfx.dek - && (cfx.dek->use_mdc || cfx.dek->use_aead) - && !opt.explicit_compress_option - && is_file_compressed (peekbuf, peekbuflen)) - { - if (opt.verbose) - log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]"); - do_compress = 0; - } - if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out ))) { iobuf_cancel (inp); @@ -598,6 +577,24 @@ encrypt_simple (const char *filename, int mode, int use_seskey) else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ + /* Register the cipher filter. */ + if (mode) + iobuf_push_filter (out, + cfx.dek->use_aead? cipher_filter_aead + /**/ : cipher_filter_cfb, + &cfx ); + + if (do_compress + && cfx.dek + && (cfx.dek->use_mdc || cfx.dek->use_aead) + && !opt.explicit_compress_option + && is_file_compressed (inp)) + { + if (opt.verbose) + log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]"); + do_compress = 0; + } + if (!opt.no_literal) { /* Note that PT has been initialized above in !no_literal mode. */ @@ -617,13 +614,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey) pkt.pkt.generic = NULL; } - /* Register the cipher filter. */ - if (mode) - iobuf_push_filter (out, - cfx.dek->use_aead? cipher_filter_aead - /**/ : cipher_filter_cfb, - &cfx ); - /* Register the compress filter. */ if ( do_compress ) { @@ -783,7 +773,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, PKT_plaintext *pt = NULL; DEK *symkey_dek = NULL; STRING2KEY *symkey_s2k = NULL; - int rc = 0, rc2 = 0; + int rc = 0; u32 filesize; cipher_filter_context_t cfx; armor_filter_context_t *afx = NULL; @@ -792,8 +782,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, progress_filter_context_t *pfx; PK_LIST pk_list; int do_compress; - char peekbuf[32]; - int peekbuflen; if (filefd != -1 && filename) return gpg_error (GPG_ERR_INV_ARG); /* Both given. */ @@ -866,14 +854,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, if (opt.verbose) log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp)); - peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf); - if (peekbuflen < 0) - { - peekbuflen = 0; - if (DBG_FILTER) - log_debug ("peeking at input failed\n"); - } - handle_progress (pfx, inp, filename); if (opt.textmode) @@ -900,25 +880,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, if (!cfx.dek->use_aead) 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 or AEAD. This forces compressed files to be re-compressed if - * we do not have a MDC to give some protection against chosen - * ciphertext attacks. */ - if (do_compress - && (cfx.dek->use_mdc || cfx.dek->use_aead) - && !opt.explicit_compress_option - && is_file_compressed (peekbuf, peekbuflen)) - { - if (opt.verbose) - log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]"); - do_compress = 0; - } - if (rc2) - { - rc = rc2; - goto leave; - } - make_session_key (cfx.dek); if (DBG_CRYPTO) log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: "); @@ -959,6 +920,26 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, else filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */ + /* Register the cipher filter. */ + iobuf_push_filter (out, + cfx.dek->use_aead? cipher_filter_aead + /**/ : cipher_filter_cfb, + &cfx); + + /* Only do the is-file-already-compressed check if we are using a + * MDC or AEAD. This forces compressed files to be re-compressed if + * we do not have a MDC to give some protection against chosen + * ciphertext attacks. */ + if (do_compress + && (cfx.dek->use_mdc || cfx.dek->use_aead) + && !opt.explicit_compress_option + && is_file_compressed (inp)) + { + if (opt.verbose) + log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]"); + do_compress = 0; + } + if (!opt.no_literal) { pt->timestamp = make_timestamp(); @@ -973,12 +954,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, else cfx.datalen = filesize && !do_compress ? filesize : 0; - /* Register the cipher filter. */ - iobuf_push_filter (out, - cfx.dek->use_aead? cipher_filter_aead - /**/ : cipher_filter_cfb, - &cfx); - /* Register the compress filter. */ if (do_compress) { diff --git a/g10/sign.c b/g10/sign.c index f9984f811..d6ab396af 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1034,9 +1034,6 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int multifile = 0; u32 duration=0; pt_extra_hash_data_t extrahash = NULL; - char peekbuf[32]; - int peekbuflen = 0; - pfx = new_progress_context (); afx = new_armor_context (); @@ -1095,14 +1092,6 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, goto leave; } - peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf); - if (peekbuflen < 0) - { - peekbuflen = 0; - if (DBG_FILTER) - log_debug ("peeking at input failed\n"); - } - handle_progress (pfx, inp, fname); } @@ -1260,7 +1249,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int compr_algo = opt.compress_algo; if (!opt.explicit_compress_option - && is_file_compressed (peekbuf, peekbuflen)) + && is_file_compressed (inp)) { if (opt.verbose) log_info(_("'%s' already compressed\n"), fname? fname: "[stdin]");